9 December 2016

First thoughts on Ruby on Rails

As mentioned in my previous post, I recently did some front-end work for a Shopify development agency, and they asked me if I could potentially help with upcoming Rails-based projects. As I've heard a lot about Rails, many websites use it, and a freelancing friend of mine specialises in it, it was high time I looked into it to see what all the fuss was about.

And it can never hurt to learn a new technology, as it broadens the mind to new approaches for solving problems.

Well that's a weird name...

Yes, yes it is. But it has meaning:
  • "Ruby" is a dynamic object-orientated general programming language.
  • "Rails" is a server-side web application framework written in, exclusively using Ruby.
Hence "Ruby on Rails" means "software using Ruby on the Rails framework". Because that's a bit of a mouthful, it's often shortened to just "Rails".

Why use Rails over something like Spring Boot (Java)?

Wow, there's a question!

Ruby is a fairly modern programming language, designed from the outset "for programmer productivity and fun", and to be relatively easy to learn. It has a few functional elements I'm not entirely comfortable with yet, but generally speaking I can vouch for this. Because it's fairly modern, it has a lot of useful functions built-in, making it almost absurdly easy to solve common problems.

Also, with Ruby on Rails, you only have one scripting language to learn - Ruby is used everywhere, in both serverside code and front-end templating code (and even configs).

In Java web projects, you can use pure Java in front-end JSPs if you really want to, but it's really cumbersome so most people don't. This means that with Java projects, you have another language to learn, making it less easy to move between the front-end and back-end.

While Java is quite readable and fairly easy to learn (especially compared to some other OO languages (I'm looking at you C++)), it has quite a lot of complexity and verbosity. I often hear complaints over how much more code you need to write to achieve things in Java. While this is still true to some extent, it's definitely changing with Spring Boot, and modern libraries.

How do I structure an application?

You get a lot of really nice tools for developing Rails applications, run from the command line. Firstly, you run the command:

rails new myapp
to generate a complete default application called "myapp" in the standard structure, with its own embedded server (which is run using "rails server" or "rails s"). Then, with the rails generator, you can do things like:

rails generate controller Authentication login logout
- generates all classes, test stubs, configuration, and routes for a new controller called "Authentication" with two actions "login" and "logout"

rails generate model Employee firstname:string lastname:string jobtitle:string
- generates all classes, test stubs, database migrations and configuration for a new model class called "Employee" with three string fields "firstname", "lastname", "jobtitle".

As the stack overflow article linked above shows, there's a lot more than can be generated. And of course, you can modify these files afterwards, and create your own manually if you wanted to. It's nice that this is an option, as it promotes consistency and best practices.

Spring Boot has nothing like this. There might be wizards in IDEs for creating a basic project structure, but nothing built in to the actual framework itself. There are Maven Archetypes for generating a whole Java project from a template, but that's nothing to do with Spring, and it's not really used all that much.

Spring Boot is a generic application development framework that isn't specific to web applications, so it won't be tailored for web development. It's much more powerful and general-purpose in this regard, but you don't get some of the niceties of Rails for web development.

How do I manage the application?

Both Rails and Spring both make use of Convention over Configuration extensively. A simple example would be enabling database support in your application (often by just including a dependency, and minimal connection configuration), defining a model class called "Employee", and for the application to automatically create and use a database table called "employees" containing the fields of the class. You can configure it to behave differently, but the vast majority of the time, you won't need to.

Rails comes with built in database versioning and migration tools, as hinted at in the model generation above. There's some complexity here I don't yet fully understand, but this really excites me. I'm sad, I know, but I know first hand how challenging it can be making database changes in established systems. My understanding is that Rails, and yourself, can maintain versioned Ruby files in the "db/migrate" directory of the application, which will create and modify database schema. Then all you need to do to apply it to your database is run:

rails db:migrate
Rails knows which version your database is up to, and applies only those migrations it needs to in order. You can run the same command again afterwards, and it knows it doesn't need to do anything. You can also do easy rollbacks using a similar command:

rails db:rollback
Nice. As I said, there's complexity here I've not yet covered, but I really like how this is built in.

Speaking of "built in", because Rails is a web development framework, if you use Models properly (and why wouldn't you?), Rails automatically makes use of RESTful best practices, utilising the correct HTTP verbs to serve and update data.

Also (when I found out about this, it blew my mind), when you import the "active_support" library, all Ruby objects then come with a bunch of output formatting built in:

"obj.to_json"
"obj.to_xml"
"obj.to_yaml"

These all produce the correct representation of the object in the format requested, for free. Nice!

Which is more widely used?

This is actually a hard question to answer. The HotFrameworks website might seem fairly conclusive, showing Rails in 3rd place and Spring in 8th, but this is based off of GitHub projects, and StackOverflow discussions.

The impression I get, which may well be unfair, is that Java Spring is more often used for large high-performance enterprise applications, and Rails is more often used for less large-scale websites. I imagine most large enterprise applications aren't stored in GitHub, swaying the statistics away from Spring. Just a theory, but I know Jagex uses Spring (sometimes!), and doesn't use GitHub.

But as an immediate counter-argument to that, GitHub itself is built on Rails, as is Shopify.

I feel there is definitely space for both, and I intend to continue learning in both areas, as it opens up a significantly wider range of potential projects for me to get involved with.

So, do I like Ruby?

I... well, it's still new to me. I do like how concise it is, especially compared to the verbosity of Java. There are some nice features built in to make things quicker and easier. There are some things that still confuse me though.

Inconsistency

One issue I do have is some of the optional variances it accepts. The inconsistency makes me uncomfortable. For example, you can wrap blocks with curly brackets "{}" like Java, or use "do end", so these blocks are functionally identical:

if something {
   method
   second method
}

AND

if something do
   method
   second method
end

Why offer that option? Why not just enforce one? This variation is more superficial than my next problem though, which is that method brackets are optional. Sometimes. For example:

log_in user

This is a method called "log_in", being passed a "user" object (now imagine the arbitrary line "log_in user, website, ip, isp, feature, service"). This is syntactically identical to:

log_in(user)

But if you want to use a ternary operator, you *have* to use brackets. Without brackets, it's a syntax error. So this is the only form that is correct:

do_login? log_in(user) : log_out(user)

I'm sure there are reasons for this, but it this kind of inconsistency irritates me. Again, I can't see a reason for it, except for developer laziness.

Flexibility... too much?

One very cool, but also a little scary, feature of Ruby is that you can add functionality to a built-in class. For example, you can add an "is_palindrome" method to the built-in String class. I believe this feature is how the "active_support" library mentioned in the Application Management section above can add those "to_json" (etc.) methods to base classes.

While this is handy, it makes me a little uncomfortable, as you don't really know what you're getting.

Also, it seems it's fairly common to override operators. For example,

BCrypt::Password.new(remember_digest) == remember_token

In this case, "==" has been redefined to mean:

BCrypt::Password.new(remember_digest).is_password?(remember_token)

Once again, this almost feels like some things were added by lazy developers who didn't want to do things the standard and "proper" way ("my way is right!"), and now there's inconsistency.

Also, I'm not fond of "unless". It's the negative version of "if", and it confuses me like a stack of double-negatives. Some examples:

unless logged_in
   flash[:danger] = "Please log in."
   redirect_to login_url
end
...
redirect_to(root_url) unless @user == current_user

It's trying to use natural English to make things more clear, except the grammar doesn't work, making it more confusing to me. I personally find being explicit about negatives much easier to follow than reframing positives around a negative, so:

if !logged_in
   flash[:danger] = "Please log in."
   redirect_to login_url
end
...
redirect_to(root_url) if @user != current_user

Again, "unless" feels like some developer somewhere saying they didn't like using "nots" in conditionals, like most other languages. (I know Ruby isn't the first one to use it, but it's not common.)

And finally... why the **** did they choose to use "elsif" instead of "elseif" :|

So what's my answer?

I do think I like Ruby. I can see how quickly and easily one could implement features in it, especially on top of Rails. The idea of being able to quickly construct full production-grade web applications is exciting to me. I still have some learning to go before I'm anywhere near as comfortable with it as Java, but I've come a long way in the last few weeks. It's definitely worth the effort, and I'll keep gaining experience with it alongside Java technologies.

No comments:

Post a Comment