RailsConf 2017

Perusing the Rails Source Code - A Beginners Guide

Perusing the Rails Source Code - A Beginners Guide

by Alex Kitchens

In the talk "Perusing the Rails Source Code - A Beginners Guide," presented at RailsConf 2017 by Alex Kitchens, the speaker demystifies the complexities of exploring the Ruby on Rails codebase for beginners. The session emphasizes that while open-source projects can seem daunting, particularly Rails due to its extensive history and size, it is essential for developers to understand the underlying code to enhance their application-building skills.

Key points discussed include:
- Starting with the Source Code: The importance of cloning the Rails repository from GitHub and setting it up for development is crucial to understanding its workings. Alex suggests utilizing the Rails guides for this purpose.
- Understanding Rails Architecture: Alex breaks down the Rails architecture by explaining core modules such as Action Pack (which contains both Action Controller and Action Dispatch), Active Record, and Active Support, highlighting their functions within a typical Rails request lifecycle.
- Navigating the Codebase: The speaker provides insights into the Rails source code structure, focusing on various modules and their functionalities, including Action Mailer, Active Job, and Action Cable. He notes that reviewing the README and the gemspec files can provide vital context regarding dependencies and initial setups.
- Experiencing 'Aha' Moments: The concept of 'aha' moments is shared, referring to the realizations and insights that come from reading and experimenting with the code, which boost understanding and learning.
- Using Debugging Tools: Alex demonstrates the use of debugging tools like byebug and pry to traverse code execution paths and understand method functionalities better. He shares experiences of employing introspection methods in Ruby to find method source locations within the Rails code.
- Utilizing Git for Exploration: The talk highlights the importance of using Git effectively to track changes and understand the evolution of code, emphasizing how commit messages tell the story behind code alterations.
- Community Engagement: Alex encourages attendees to engage with the Rails GitHub issues and pull requests to learn from real-world problems and solutions, offering valuable insights and fostering a deeper understanding of Rail's coding practices.
- Closing Resources: The session concludes with Alex providing a list of resources, such as other talks and podcasts, for further learning and exploration about Rails development.

The main takeaway from Alex's talk is that by actively engaging with the Rails source code and utilizing available resources, developers can significantly enhance their understanding of how Rails operates, ultimately improving their programming skills and application development expertise.

00:00:11.900 Okay, thank you everyone for coming to my talk. I'm going to start off first with a shout-out to my son. My family's watching the livestream, and my 16-month-old son's favorite new word is "flowers." So, Hudson, look—flowers!
00:00:20.810 I have this weird habit of starring GitHub repositories and never looking at the source code. I have like two hundred and seventy something stars, and I did this with Rails. I even took a step further with Rails: I cloned the Rails repository and never looked at the source code for a long time.
00:00:39.300 Finally, when I did, this is a little bit of how I started perusing the source code and how I comprehended it. I had these little "aha" moments, and they boosted my learning of the source code over time. What I want to do today is share with you some of the "aha" moments I had so that you can get up and running in the Rails source code a lot quicker than I did.
00:01:02.660 There are a few side effects of perusing the Rails source code. Going through thousands of lines of Ruby code, you're likely to learn some new methods that you may not have used before. You'll gain a lot of knowledge about optimizations in Ruby, and you might even be introduced to metaprogramming. If you've never done metaprogramming, you can see how Rails uses it.
00:01:38.340 The source repository for Rails is over ten years old and spans over tens of thousands of commits, making it a good playground for learning some new Git methods and options, as well as good methods you already know. By digging through this information, you'll learn a lot about Git. One thing I heard frequently when getting into Rails is that there is a lot of "magic" in Rails. It's really easy to get up and running quickly with very little code.
00:02:10.649 However, it turns out there's no magic in Rails; there's just a very good public API that does a lot of the heavy lifting for users, enabling them to get up and running without hitting implementation hurdles. To start off, you need a copy of the Rails source, which you can get from GitHub. I recommend setting it up for development, and the Rails guides provide a good step-by-step process on how to set it up.
00:02:45.570 There are a couple of dependencies that you need, which will allow you to run the tests for the Rails source code. When you get the source code, you will see a top-level view of the repository. It contains folders for the various modules, along with documentation like the license, contributing guidelines, the README, and the gem files in the gemspec.
00:03:09.959 The Rails modules are independent, as they each have their own folder and are each their own gem. The reason the Rails team does this is that they want the modules to be interchangeable. So, if you want to use a different ORM than Active Record in Rails, you can. It also means you can take Active Record outside of Rails and use it in another project. I've done this a couple of times.
00:03:51.150 Now, to run through the different modules, I'm going to go through a typical Rails request. You start your Rails app with the command 'rails server,' and when a request comes in, it is sent to the routes. The router will parse it and send it to a controller.
00:04:13.380 The controller usually grabs a model and a view, sending a response back through the routes. The routes and the controller are both part of Action Dispatch, or Action Pack. Action Pack consists of two separate modules: Action Dispatch and Action Controller. The routes refer to Action Dispatch, while the controllers refer to Action Controller.
00:04:51.930 The models are usually Active Record or Active Model, should you choose not to interact with the database or want to wrap your Active Record even more. The view is Action View. These components are initialized by Rails through the command-line interface, which is handled by Railties. Active Support is sprinkled throughout the app and extends the Ruby standard library.
00:05:14.430 Also, there are three other modules I consider additional: Action Mailer, which is used to include mail delivery in your app; Active Job, which handles background tasks and jobs; and Action Cable, a newer module that integrates WebSockets into Rails, allowing for a lot of real-time application use, such as adding user stories and real-time chat to your apps.
00:05:52.920 In the top-level directory, you will find the guides—specifically at guides.rubyonrails.org. When you clone the Rails repository, you also have a copy of the guides with you, so if you want to make changes, you can do so and submit a pull request. That's actually how I first started with Rails—I found a typo in the guidelines, submitted a pull request, and now I'm a committer!
00:06:27.800 So we are going to look at a module, and I'll be using Active Record. The things I will show you can be done from module to module. The first level of a module contains the 'lib' directory, where the code and tests reside, as well as the README. I think the README is a good starting point; if you're familiar with the module, you'll likely find at least one or two takeaways from it.
00:06:55.080 And if you're not familiar with the module, the README provides a solid overview. The gemspec is also good to inspect because you can view the module's dependencies. For example, you will see that Active Record depends on Active Support, Active Model, and another gem called ERB, which handles most of the SQL generation within Active Record.
00:07:34.339 If we look inside the internal 'lib' directory, you'll usually find a folder named after the module, along with a 'rails' folder. The rails folder is responsible for much of the initialization—specifically handling the generators. If you're using Active Record within Rails, this is where you'll find the files for commands such as 'rails generate model' and 'rails generate migration.' The 'active_record.rb' file contains a lot of the initialization configuration.
00:08:12.640 If you've heard of terms like eager loading and auto-loading, that's where most of the handling takes place. If we change directories into the module's directory, we'll see the classes for Active Record. The documentation in these files constitutes the information for the API website.
00:08:51.980 Thus, just as you have the guides, you also have the API website by reading through the various files. As you're exploring here, you may see key terms you recognize, like attributes, relations, and schema. You may also come across terms that you don’t recognize, such as attribute mutation tracker and persistence. The terms you do recognize make for a good starting point because you are already familiar with those concepts, and this allows you to delve into their implementation.
00:09:39.140 For instance, I did this with the 'find_by' query method. The methods 'find_by' and 'where' are quite similar; both accept attributes as parameters. For example, you want to retrieve a post by its title. However, 'find_by' returns a single object, while 'where' returns an Active Record relation collection of objects.
00:10:08.350 By examining 'find_by', you'll find that it actually uses 'where' and just takes the first item it retrieves. That’s interesting—it's essentially syntactic sugar for 'where.' However, exploring Active Record for the 'create' method is not as straightforward. You’ll have to dig to find out where these methods live. One of my first 'aha' moments was learning about Ruby's introspection methods.
00:10:53.80 I discovered many of these through Aaron Patterson's blog, titled 'I'm a Debugger,' where he demonstrates various debugging techniques using simple Ruby methods. Ruby offers introspection methods that enable you to call on a class or method and learn more about it. One method I often use is 'method(:method_name).source_location'. You can call it on a class and get the location of the method within the Rails repository.
00:11:30.000 Then, we can look at the create method. In a straightforward version, it creates a new object, saves it, and returns it. Yet, sometimes the process is not that simple.
00:11:43.600 For instance, calling 'save' is an instance method and its source location will show it resides in persistence. But if you check the API documentation, you'll notice that's not the only aspect of the method. The 'save' function does some housekeeping before reaching the core of its functionality.
00:12:20.470 The 'save' method is actually a bit of an elaborate dance. If you're trying to suppress certain records, it simply returns true. In cases like that, it's going to super into a method call, which saves the state of that record, and if anything fails, it will roll back to the original state when 'save' was called.
00:12:44.320 When 'save' is executed, it goes super into a class called 'Dirty,' which tracks changes to the object since you last interacted with the database. It doesn't perform validation during this stage, but if there were validations that failed, they would return false. The next step would send us over to persistence.
00:13:40.390 While we could have looked at the API documentation to understand what 'save' does, the knowledge gap between what 'source_location' returns and what the API documentation describes could be insightful. Another useful method is 'super_method', which you can call after the 'save' method.
00:14:07.450 I prefer to use 'byebug' when I get stuck in situations like this because it allows me to traverse code while it's executing. You'll need a script to insert 'byebug' into your code, and the Rails source contains templates for creating such a script—essentially a minimal version of these modules for exploration.
00:14:47.600 In the context of our 'Active Record' scenario, the master script begins by requiring bundler in line and creating an inline gem file. If you don’t have a copy of the necessary gems on your computer, this will pull them for you and importantly, it grabs the latest version from GitHub.
00:15:27.310 We also incorporate the gem for the database you're using. You can switch that out to whichever one you prefer. Given that we're using the cloned version on our computer, you can change the required version from GitHub to a local path, allowing you to see your changes as you run your tests.
00:16:04.130 Next, we configure Active Record to establish a connection to the database. We define the schema, creating a table called 'post' that includes a title attribute. Including at least one attribute is helpful to see how data is passed through.
00:16:44.560 After defining the attribute, we proceed to work with our Post class, which has a minitest setup to assert statements. Usually, I skip the assertions because these exploration scripts are about understanding and tinkering, rather than confirming functionality.
00:17:13.390 Interestingly, if you want a similar experience to the Rails console, you could require 'pry' and call 'binding.pry' in these scripts. This gives you an interactive console similar to the standard Rails console interface.
00:17:54.400 To use 'byebug,' simply require it and call 'byebug' in the script before the line you wish to explore. When you're stepping through the process, there are cool methods at your disposal with 'byebug.' For example, while at 'post.create', if you want to step into the 'create' method, type 's.' If you want to skip a method or a statement, use 'n' to go to the first line of the else statement.
00:18:38.440 You can also display local variables with the command 'var local', which will show local variables in scope in the current context. On stepping through the code, I sometimes encounter what I call 'heisenbugs.' These occur when there's uncertainty between the expected and actual running values of a variable.
00:19:23.740 This is particularly common in Active Record's query methods, such as 'where,' where the variable keeps getting passed through but may not have been instantiated until it is finally needed. All of Active Record's query methods are designed for 'lazy query,' meaning the actual database query won't execute until the value is necessary.
00:20:14.290 As you're iterating through the classes, you'll start to familiarize yourself with those you know while getting introduced to new ones. This exposure can help you dig more deeply into the Rails framework, broadening your understanding.
00:20:46.210 If you encounter a line of code you don't understand, it can be helpful to change or delete it and then run the tests for the module to see what breaks. I did this not long ago with a method called 'define_method_attribute_equals.' What this method does is use metaprogramming in Active Record to create methods for all the different attributes.
00:21:29.690 It takes a name, like 'title', unpacks it into hexadecimal, and assigns it a safe name. It then uses a module called 'Generated attribute methods' to create a new method based on that name. This part captivated me; upon experimenting, I realized that Rails implements this method in a clever way.
00:22:06.360 In my tinkering with this code, I discovered how Rails cleverly circumvent Ruby's limitations regarding character use in method names. They generate methods while ensuring those methods can also be aliased to more complex method names, providing thoughtful methods for the framework.
00:22:45.950 The second 'aha' moment came when I learned how to effectively use Git to uncover the story of the code. In the Rails repository, the commit history tells a tale of how the code has evolved over time. Using Git's capabilities, I could follow the commit logs to understand why changes were made.
00:23:39.030 Initially, I started with 'git blame,' which returns the last commit hash for each line of code in a file. When I found an unexpected indentation change from 2016, it led me down a trail of investigating why decorum changes were implemented within the Rails code.
00:25:02.230 Then, I used 'git log -S' along with other options to search through commits and selectively bring up not only the relevant changes to the commit, but also the evolved context of that code. It became apparent that many commit messages are rich with the rationale behind the development stages of the framework.
00:26:05.170 By utilizing the commands 'git log -p' and 'git log -p -A,' I could see changes along with their surrounding context, letting me follow along the evolution of specific functionalities in Rails—a journey marked by its struggle to maintain style guidelines.
00:27:26.420 The visual aspect of GitHub adds another layer, where you're able to check out files as they lived in the past, following their evolution over time. For example, I once explored a deprecation notice regarding a method 'redirect_to_back,' linked to an essential chat with its creator concerning the best practices surrounding safe redirection in applications.
00:28:33.420 What I discovered was a wealth of knowledge, encapsulated not only in the commits, but also the discussions and pull requests surrounding those changes. Engaging with these conversations exposes you to a variety of use cases and unique solutions that can deepen your understanding of Rails.
00:29:17.260 Moreover, as you explore issues on GitHub, you can follow reproduction scripts and experiment on your own. Utilizing the scripts allows you to practically engage with the code and understand where bugs exist, reinforcing your knowledge and making you much more familiar with framework intricacies.
00:30:12.540 Similarly, milestones give you foresight into what changes are being planned for new releases of Rails. Whenever I see someone making provisions for testing—like system testing—it intrigues me to watch the timeline unfold.
00:30:49.560 Pull requests do not merely indicate change; they also reflect collaborative effort. As the community discusses and refines ideas, you will see the branching context of problem-solving manifesting over several commits before it finally merges the solution to master.
00:31:46.50 Over time, I’ve really enjoyed diving into the issues and pull requests of Rails because they spark learning moments with every page I read. At first, it was often challenging to grasp the discussions, but it evolved into a treasure trove of insights into how Rails functions and where enhancements are made.
00:32:34.100 Additionally, by employing various labels on GitHub, you can drill down to specific modules like Active Record or Action Pack. You can filter issues and pull requests that relate directly to your areas of interest, allowing you to focus on what you care about and keep in touch with ongoing discussions.
00:33:24.900 Another resource is the roadmap section in Rails’ GitHub repository, where you can see version milestones and their targeted changes. You can glean insights into the future direction of Rails by observing what discussions take place concerning future features.
00:34:07.230 Finally, my biggest 'aha' moment came when I sought to tackle issues in depth. When you start to become comfortable with the issues, look for ones with attached reproduction scripts and PRs. Investigate those issues before looking at the pull requests—run the scripts on your machine and see if you can rectify the failures.
00:34:58.490 This approach leads to gaining experience as you test your understanding against others'. If you find solutions, compare your methods with those of the contributor. Even if you don’t succeed immediately, exposure to the code will broaden your knowledge.
00:36:02.320 To conclude, I’ll leave you with some valuable resources that helped me delve into Rails' source code. First is Aaron Patterson's talk, 'I’m a Foots Debugger,' which shares many great debugging techniques.
00:36:33.640 Then, Eileen's 2015 talk on contributing to Rails goes into much more depth regarding tools like 'git bisect.' I recommend checking her pull request for systematic tests. This pull request contains a treasure trove of knowledge in how she wrestled with changes to contribute to Rails.
00:37:21.430 Also worth noting is the podcast 'The Bike Shed,' co-hosted by Derrick Pryor and Shawn Griffin, who tackle various Rails features and issues in each episode—like eavesdropping on a developer lunch.
00:37:59.680 Lastly, 'Crafting Rails 4 Applications' by José Valim, dives deep into core concepts and could provide a greater scope for understanding. Sabra Nuria also delivered a talk about the boot process of Rails that’s worthwhile.
00:38:28.780 If you’d like to find slides from my talk, they are available on my website at 'alexkitchen.com/railsconf.' Thank you all for coming to my talk!
00:38:54.500 I'll be out here taking questions, so please feel free to approach me if you're interested in discussing further.