00:00:06.259
Aloha from beautiful Maui! My name is Justin Gordon, and I'm here today to give you my talk for Rails Conference 2021: "Implicit to Explicit: Decoding Ruby's Magical Syntax." I've wanted to give this talk for a really long time. One of the reasons I want to present it is that I interview a lot of Rails developers as I'm hiring right now.
00:00:12.120
One of the problems that I see is that many Rails developers cannot explain how the Rails DSL works in terms of basic Ruby code. Once you can understand how the Rails DSL is really just plain Ruby code, it will open up your understanding of what you're doing.
00:00:25.019
You're not going to just be copying and pasting code without any understanding. You will be able to look at the code and think, 'This is exactly what the Ruby interpreter is probably thinking. I know where to go get the documentation. I know how to debug it.' I definitely had a lot of these same issues when I started Ruby a long time ago.
00:00:38.700
That's why I'm so excited to give this talk today. So, without further ado, let's get started. How did I get into Ruby on Rails? For many years before Ruby on Rails, I was writing Java code. Java is known as a general-purpose language.
00:00:50.039
So what is a general-purpose language? It's a language you can use to do pretty much anything. This is opposed to the Domain Specific Language (DSL) that we will talk about today.
00:01:01.920
Here's a little bit of Java code. It's very basic and just a lot of code to say 'Hello, world,' essentially. Every little character in there is necessary. All the prints, braces, etc. That's what makes Java explicit.
00:01:12.480
Now, this explicitness makes Java a terrible DSL because if you remember what it's like to write a web application in Java, there's just so many files and complications. It's quite cumbersome, which is why Ruby on Rails took off.
00:01:25.019
With Rails, we have a Domain Specific Language. This means that when we write some Ruby code, it speaks directly to the problem we're trying to solve: building a web application.
00:01:38.100
For instance, if you look at this Rails code: 'class Person < ApplicationRecord; validates :name, presence: true.' There are hardly any extra characters in this code. This code succinctly defines the Person class and specifies validation on the name.
00:01:49.200
This simplicity is what we mean by a DSL. However, this code also contains a lot of implicit elements, making it a great DSL but hard to understand. Those are the aspects I will cover in this talk.
00:02:02.700
These topics include what exactly 'self' is, as well as variable declarations. In Ruby, you don't have to explicitly declare variables, and there are nuances like parentheses that can be left out.
00:02:11.400
A long time ago, I learned Ruby on Rails from the Rails Tutorial, and I imagined it would be straightforward given all my experience with Java. But the reality was that when I read Ruby code, I felt very much lost.
00:02:27.840
I was looking at the syntax wondering, 'What exactly is going on here?' It felt somewhat like the compiled code I was used to, and I struggled to distinguish between Ruby and Ruby on Rails.
00:02:43.800
I confess that often I resorted to just copying and pasting code without fully understanding it. How many of you felt like that when going through the Rails tutorial? I know I did.
00:02:58.560
Even though I wrote a lot of code, I didn't truly grasp that all that DSL code was just plain Ruby code. I could have added print statements or used 'binding.pry' to see exactly what was going on.
00:03:12.120
So, let's fix this. Can we learn to read the code like the Ruby interpreter does? I want you to look at this code, and after this talk, be able to understand it better.
00:03:22.200
It is important to comprehend that you shouldn't simply copy and paste code; you must understand it. After this talk, you will know how to read that code and realize it's not some magic Rails DSL.
00:03:35.280
It's just plain Ruby code. These are messages we're sending to objects, involving arguments and variable declarations. Many of these elements are straightforward.
00:03:49.080
I want to examine some fundamental building blocks: assigning values to variables and sending messages to objects. Now, let's compare JavaScript and Ruby.
00:04:03.840
JavaScript is very explicit, while Ruby is often implicit. Many of you, especially newer Ruby on Rails programmers, are probably familiar with JavaScript.
00:04:14.640
In JavaScript, parentheses always mean function invocation. Without parentheses, there is no function invocation. That's absolutely critical.
00:04:27.660
How many Ruby on Rails programmers have done some JavaScript and forgotten to include parentheses? I certainly have. If we look at a line like 'window.close', that's just a value; it could even be a function in Ruby.
00:04:41.880
In Ruby, parentheses are optional. For example, when we say 'has many :micro_posts dependent: :destroy,' it looks unclear at first—but as soon as we add parentheses, it becomes clear.
00:04:56.580
We can see that 'has many' takes an argument of ':micro_posts' and ':dependent => :destroy' indicates a hash.
00:05:06.420
Another critical thing in Ruby is that zero-argument method calls are indistinguishable from values. For example, 'user.first' is implicitly understood.
00:05:20.400
Although nobody writes the parentheses explicitly, you could say 'user.first()' to be clear that you're invoking the method. This means you're sending messages to that object.
00:05:33.840
Let’s flip between implicit and explicit. For example, an implicit 'has many' on a user model versus an explicit 'self.has_many' shows us exactly what's going on.
00:05:42.300
An early Ruby on Rails programmer might view this syntax as magical, struggling to understand what 'has many' entails. The truth is, it's simply a method called on 'self,' where 'self' is the user class.
00:05:58.740
Now, let’s take a break from the slides and look at how we can edit 'usertest.rb' and see if the tests still pass. This is a great way to validate what I've just explained.
00:06:08.880
If I make a minor edit, such as adding space, we can then check our tests. Ensuring the tests pass confirms that we're editing the right file.
00:06:22.680
Let's observe whether the changes affect our code. If it's affected, it's great. They still pass! This demonstrates how you can explore Rails code more confidently.
00:06:34.040
Next, let’s delve into custom operators. These can make the Ruby code seem quite magical, but with the right knowledge, we can demystify them.
00:06:46.080
For instance, we might encounter code featuring custom operators. Knowing how to interpret this code enables us to analyze its functions effectively.
00:06:58.440
Many beginning Rails programmers struggle to explain these operators in simple terms of Ruby code functionalities. It's important to understand it contextually.
00:07:12.780
Now, moving forward, let's assess a JavaScript code example. Remember that JavaScript doesn’t have implicit receivers, except for the global window object.
00:07:26.640
Consequently, you can write 'confirm("hi")' and it’s equivalent to 'window.confirm("hi")'. Yet, missing out on using 'this' with method calls results in errors.
00:07:39.240
In contrast, Ruby's implicit self means messages are sent with built-in context. This identification enables understanding of what the implicit 'self' is referring to.
00:07:51.780
For instance, you may have 'class User: has_many' followed by method calls. However, this can also be written out explicitly as 'self.has_many' for clarity.
00:08:03.060
This level of clarity reveals where methods like 'has_many' originate and shows their arguments clearly. Going from implicit to explicit enhances comprehension of the code.
00:08:18.600
In this diagram, I'm illustrating the implicit message receiver, followed by the message name and arguments. Recognizing these elements sheds light on the DSL built on Ruby.
00:08:30.540
Essentially, 'self' serves as an implicit message receiver, almost never explicitly stated. This understanding contributes significantly to grasping Ruby code nuances.
00:08:46.920
Now, you may wonder why 'pry' is included in this discussion. One important aspect of 'pry' is that it allows us to see what 'self' is at any given point in our code.
00:09:01.920
In a quick demo, I will put several 'binding.pry' calls within our Ruby code to allow the code execution to pause at a defined point.
00:09:16.560
After starting the Rails server and including a few 'binding.pry' commands, we can see the code execution halt at the break points established.
00:09:29.520
When we resume execution, we will see what 'self' refers to within various parts of our Rails application, making it a very useful debugging tool.
00:09:43.680
In one instance, we can inspect the context of 'self' before and after executing particular code lines. This insight provides greater control over our debugging process.
00:11:09.300
Let’s look at explicit variable declarations. In JavaScript, declarations must be explicit using 'var', 'let', or 'const', unlike Ruby’s implicit declaration.
00:11:29.880
Implicit declaration means syntax for creating a variable often takes precedence over method calls in Ruby. For instance, 'result = ...' is treated as a variable declaration.
00:11:45.120
When defining methods, like a setter method 'email=', you must be explicit with 'self.email' instead of just 'email' to avoid variable conflicts.
00:12:05.940
Otherwise, Ruby could mistakenly interpret it as creating a new local variable. When using 'self.email', it denotes that we are explicitly calling the method.
00:12:18.540
Let's go into another Rails controller example. Many developers find this code mystifying due to the layers of abstraction at play.
00:12:31.620
This code handles returning XML or JSON based on browser requests. Internally, it involves method calls and blocks that interact with format types.
00:12:56.520
Understanding the explicit nature of the code demystifies the operations being performed, therefore leading to a clearer comprehension.
00:13:09.180
For example, the 'respond_to' method sends back the appropriate format and manages blocks adequately, as the code acts on provided methods.
00:13:24.840
Lastly, we can acknowledge differences in return syntax as well: JavaScript requires explicit returns while Ruby allows implicit returns.
00:13:39.960
In JavaScript, you frequently have to import everything explicitly—no surprises. In Ruby, this isn't the case; it utilizes constant lookups, offering more freedom.
00:13:54.720
Now, enough of the theoretical discussions. Let's explore 'pry' further. There are various techniques I will showcase that allow better comprehension of Ruby on Rails code.
00:14:09.480
Using this, you can quickly iterate through code, make interactive changes, and experiment with outcomes—all useful for fine-tuning your Ruby skills.
00:14:24.300
Let's start a quick demo of 'pry' to gain more insights. I'll configure the Rails server using a special script to prevent multithreading issues.
00:14:38.580
As I delve into relationships and controller methods, you'll notice how intuitively manageable the code becomes with the right tools.
00:14:52.860
While exploring further, I will demonstrate how to quickly attain necessary information, documentation, and shortcuts within 'pry'.
00:15:07.560
In one instance, I can search for documentation on methods by leveraging 'pry', significantly reducing time compared to a web search.
00:15:22.680
Let's continue our demonstration, leveraging 'binding.pry' in various contexts to retrieve insights effectively.
00:15:35.460
As I step into 'self', we can explore further, dispelling any confusions and thoroughly understanding each step in the code.
00:15:51.960
Exploring the relationships and how they correlate in our Rails application offers clarity that illustrates the underlying principles.
00:16:07.260
Now let's get back to configuration settings, where understanding implicit or explicit self plays a significant role.
00:16:24.600
During my explorations, I’ll be investigating how these configurations are built, specifically regarding missing methods.
00:16:39.780
This approach allows an array of values to be set through 'method_missing', thus making the DSL relevant and usable.
00:16:56.160
For example, if we had a configuration statement that didn’t exist, we could utilize 'method_missing' to manage those missing methods.
00:17:09.840
Let’s dive into 'config.environment.rb' and witness firsthand the effects of binding on implicit variables and configurations.
00:17:30.480
It's vital to understand the top-level object in Ruby and how it works with configurations to extract maximum functionality.
00:17:45.000
I’ll perform a live demonstration, showcasing what 'self' is when attempting to access or set configuration variables.
00:17:57.720
From this understanding, we can set and retrieve configurations accurately by employing 'method_missing' effectively.
00:18:11.640
You will see how calling non-existent methods prompts the system to execute code that can intelligently handle these calls.
00:18:25.680
By observing how we can dynamically create and access configuration values through method calls, you’ll appreciate Ruby's flexibility.
00:18:38.640
After reviewing this process, you should now feel more confident about working with Ruby on Rails and recognize its underlying simplicity.
00:18:52.440
This thorough examination will improve your ability to write cleaner and clearer Ruby code.
00:19:06.300
Ultimately, as you engage more deeply with Ruby and its constructs, it will feel less magical and far more approachable.
00:19:18.720
So, to sum up: the key takeaway is that when Ruby code appears magical, try to make it explicit in your mind.
00:19:34.080
Utilize 'binding.pry' to explore what’s occurring under the hood and become more confident in your Ruby programming.
00:19:49.440
Thank you for attending this talk, and I hope you found valuable insights on Ruby's magical yet straightforward syntax!
00:20:09.060
I want to give a shout-out to the open-source sponsors that support my journey and project. They have contributed significantly to the community.
00:20:25.320
Lastly, if you're interested in joining me or want to explore more on this topic, feel free to reach out! Happy Ruby programming! Aloha.