Ruby is for people who don't know how to code? Really???
Well... Let's explore this, shall we?
A few weeks ago, prior to me writing this blog post, I've met with a few folks in a company that asked if we could colab on a project for a specific period of time. I've said "Sure, why not?" and we've scheduled a meeting to discuss the details. I was greeted by a developer, CTO, PM, and two more managers, we've had a product presentation, all the good bits.
And then we went deep
We started discussing how the project is currently set and all. It was this awesome classic app, as you could imagine, React (Next 14) on the FE, NestJS sitting on the BE, and a few other things in between. The deeper we went, the more I liked what I'm hearing. There was talks of elasticsearch, on-premises deploys to cut costs for staging and dev envs, really, all the great stuff.
In the end, I decided that well, I really don't need to join them for the said like half a year to setup the project, since I really had the expression they've got everything under control.
Now, a lil' before we departed, we touched base on some more of what I do (aside JS stuff), and I've mentioned Ruby on Rails, Laravel, not sure what else went in the talk. But, the CTO, he said something that really got me thinking. He said that Ruby is for people who don't know how to code.
Well, that's a bold statement
I didn't go into specifics here, I just... shook my head and smiled politely, not sure how my reaction really looked like. I've said that I disagree, and that Ruby is a great language, and that it's not just for beginners, but for everyone. We're here to explore why I think that's the case, and to go over a few misconceptions about Ruby. Let's dive in.
Ruby? Ruby ON Rails? What Rails?
I might have mentioned Ruby on Rails, but I didn't really go into specifics. Ruby is a programming language, and Ruby on Rails is a web framework built on top of Ruby. It's a powerful and versatile language that's been around for over 25 years, and it's been used to build some of the most popular websites and applications in the world. It's not just for beginners, and it's not just for building simple websites. I've used Ruby on Rails to build complex, high-traffic web applications, some were in the banking sector, some were in the e-commerce sector even, which requires stability and security, and Ruby on Rails has delivered. And overdelivered.
Personally, I think DHH and the team did a great job with Rails, and I think it's a great framework for building web applications. It's got a lot of built-in features that make it easy to get started, and it's got a lot of powerful tools that make it easy to build complex applications. It's also got a great community of developers who are always willing to help out and share their knowledge. I've learned a lot from the Ruby on Rails community, and I've made a lot of friends and great connections along the way.
Oke. Let's move on.
Ruby is for beginners?
Ruby is often recommended as a first programming language because it's easy to read and write, and it's got a lot of built-in features that make it easy to get started. But that doesn't mean it's just for beginners. There are some really amazing and powerful things you can do with Ruby, and it's a great language for building web applications, APIs, and more.
I'm going to pick a few things that I think really puts Ruby among the top-tiered languages that I've written so far.
-
Readability and Conciseness Ruby is known for its clean and elegant syntax, which prioritizes readability. This can lead to more maintainable and understandable code.
-
Developer Productivity Ruby emphasizes developer happiness and productivity. Its syntax allows developers to write code quickly and with fewer lines compared to some other languages, reducing boilerplate code.
-
Dynamic Typing Ruby is dynamically typed, meaning you don't need to declare the data type of a variable. This can lead to more flexible and expressive code. However, it can also lead to more runtime errors, so it's important to write tests to catch these errors early.
-
Metaprogramming Ruby has powerful metaprogramming features, allowing developers to write code that can modify itself during runtime. This flexibility can be leveraged to create expressive and dynamic solutions. I'll poke at this a bit more later on.
-
Community and Ecosystem Ruby has a vibrant and supportive community, and a rich ecosystem of libraries and tools. This can make it easier to find help and resources when you need them. Third party tools and even whole frameworks on top of frameworks exist, such as ActiveAdmin (create admin portals with ease), Ahoy (first party analytics? piece of cake), and so on.
-
Rails The king of monoliths. Ruby on Rails is a powerful web framework that has been used to build some of the most popular websites and applications in the world. The only other framework that I've seen that's as powerful as Rails is Laravel, and that's a PHP framework. I've used both, and I can say that I've enjoyed working with both. I am not counting in other frameworks that are mostly built for enterprise solutions, such as Spring or .NET. I've worked with these, and I can say that they're powerful, but they're not as fun to work with as Rails or Laravel. And startups mostly won't even start with these, they'll go with Rails or Laravel, or NodeJS, or Flask, or something else. Among all of the bunch, Rails is the most mature for sure. At least that's my opinion.
I'm gonna go over a few of these things in more detail, and I'm gonna show you some examples of Ruby code to illustrate my points. Not gonna cover everything, Ruby (and Rails) is a huge topic, and I could write a whole book about it, and not a simple blog post. ...well, I couldn't, I don't think I've got what it takes to write a whole book on something, gosh, my ADHD would kick in and I'd be off to something else in no time. 🤯
Readability and Conciseness
Just look at this code:
def fibonacci(n)
return n if n <= 1
fibonacci(n - 1) + fibonacci(n - 2)
end
It's a simple recursive function that calculates the nth number in the Fibonacci sequence. It's easy to read and understand, and it's only 3 lines long. And doesn't even have a return on the last line! But it's there, it's implicit. Might be confusing for folks that come from other backgrounds, but it's a thing in Ruby. It's a thing that I've learned to love. Compare that to the same function written in C++:
int fibonacci(int n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
I mean... It's not too bad. But it's not as clean and elegant as the Ruby version. And it's got a lot more boilerplate code.
Let's go over more complex example:
class GithubUserFetcher
def fetch_and_process_user_data(username)
raise ArgumentError, "Username is required" unless username.present?
# HTTParty is just an HTTP client. Like axios in JS ecosystem.
response = HTTParty.get("https://api.github.com/users/#{username}")
raise StandardError, "Failed to fetch user data" unless response.success?
user_data = JSON.parse(response.body)
{ success: true, data: process_user_data(user_data) }
rescue ArgumentError, StandardError => e
{ success: false, error: e.message }
end
private
def process_user_data(user_data)
{
id: user_data['id'],
login: user_data['login'],
name: user_data['name'],
public_repos: user_data['public_repos']
}
end
end
Right. Let's hop over to JavaScript:
const axios = require('axios');
async function fetchAndProcessUserData(username) {
if (!username) {
throw new Error("Username is required");
}
try {
const response = await axios.get(`https://api.github.com/users/${username}`);
if (!response.data) {
throw new Error("Failed to fetch user data");
}
const processedData = processUserData(response.data);
return { success: true, data: processedData };
} catch (error) {
return { success: false, error: error.message };
}
}
function processUserData(userData) {
return {
id: userData.id,
login: userData.login,
name: userData.name,
publicRepos: userData.public_repos
};
}
Again... Not too bad. I love both of these sytaxes and languages. But, the Ruby version is just... cleaner. And more elegant. And it's got less boilerplate code. Ruby's ability to inline if and unless (which is just a negated if) statements is just... beautiful. If you don't like it, when you start using it, you'd come around quite quickly. I know I did.
Oh and this same function, in like PHP? Yeah. I'll just drop the code, won't really go over it, you'll see my beef with it. :d
<?php
require 'vendor/autoload.php'; // Guzzle is a PHP HTTP client. Quite popular.
use GuzzleHttp\Client;
class UsersController {
public function fetchAndProcessUserData($username) {
if (empty($username)) {
throw new InvalidArgumentException("Username is required");
}
$client = new Client();
try {
$response = $client->get("https://api.github.com/users/{$username}");
if ($response->getStatusCode() !== 200) {
throw new RuntimeException("Failed to fetch user data");
}
$userData = json_decode($response->getBody(), true);
$processedData = $this->processUserData($userData);
return ['success' => true, 'data' => $processedData];
} catch (InvalidArgumentException | RuntimeException $e) {
return ['success' => false, 'error' => $e->getMessage()];
}
}
private function processUserData($userData) {
return [
'id' => $userData['id'],
'login' => $userData['login'],
'name' => $userData['name'],
'publicRepos' => $userData['public_repos']
];
}
}
Oh! And do you know how you can access the first element of an array in Ruby? You can do it like this:
first_element = array.first
First?? Fiiiirst? It's not NULTH? And it's writtein in plain ole English? Yeah, you can grab the last element like that as well, just xyz.last
that array.
But don't worry. Indexing of arrays in Ruby starts at 0. Just like in 99% of other languages. Just... not in Matlab. Fortran. R. errrrrrr...
Moving on!
Metaprogramming
Metaprogramming is a programming technique that allows you to write code that can modify itself during runtime. Sounds weird? Lemme clarify.
In Ruby, everything is an object. Even classes and modules (in their own way. Not kidding. Class.is_a? Object
returns true
.).
This means you can write code that can modify classes and modules at runtime.
I've gone to Ruby from JS, which is a prototypal language, and I've found this to be quite interesting. And quite similar to JS, in a way.
Here's a simple example of metaprogramming in Ruby:
class String
def reverse_and_upcase
self.reverse.upcase
end
end
puts "hello".reverse_and_upcase # it just gives you: OLLEH. Yeah.
Basically, anywhere in the project you're building, well, if you're building a web app, you can just add a method to the String class, and it's available everywhere. You can do this with any class or module in Ruby. You can add methods to built-in classes like Integer, Array, and Hash. I've done this a few times, and it's quite fun. Buuuuuuuut, just a word of warning, you should be careful with metaprogramming. It can be quite powerful, but also lead to some issues if, God forbid, you name your method the same as a built-in method. You can override built-in methods, and that's... not good. Or even if you bring in an external library that does the same thing, and you've got a method that does the same thing, and you're not aware of it. It's, again... not good. It's not good at all. I can advise you doing this very, very carefully and even prepend the methods you're adding with a something like your project's name or something similar. Just to be safe.
Another example of Ruby's metaprograming is the define_method
magic. It's a method that allows you to define methods dynamically at runtime.
class RandomClass
attr_accessor :name
def initialize(name)
@name = name
end
end
my_object = RandomClass.new("Example")
puts my_object.name # Output: Example
RandomClass.class_eval do
define_method(:display_name) do
puts "Name: #{@name}"
end
end
my_object.display_name # Output: Name: Example
This example might look a bit silly and not really useful, but you getting the ability to define methods at runtime, past the class definition, is quite powerful. Imagine you are really missing a method in a class that's imported from a gem. Let's say it's some sort of... idk, state handler, it keeps track of the state of something. And you're missing a method that would be quite useful to you, like pretty print it in console for debugging. You can just add it. And it's there. And it's available everywhere.
Conclusion (about daym time, this took a bit to write)
Well, I hope I've managed to show you that Ruby is not just for beginners, and that it's a powerful and versatile language that's suitable for developers of all skill levels. I've shown you a few examples of Ruby code, in comparison to something you might be more familiar with, and I hope I've managed to show you that Ruby is a clean and elegant language that's easy to read and write, and that it's got a lot of powerful features that make it easy to build complex applications.
P.S. I really wanted to go over other topics mentioned here, I think they're all very important, but let's do some of these in their own separate blog posts. Or I'll start a YT channel... I think it'll be easier to talk about these things than to write about them. I'm not sure. I'll see. I'll see. 🤔
Peace out! 🤘