rubyday 2019

Zeitwerk: A new code loader for Ruby

Zeitwerk: A new code loader for Ruby

by Xavier Noria

Summary of the Video: Zeitwerk: A New Code Loader for Ruby

In this talk at RubyDay 2019, Xavier Noria introduces Zeitwerk, a new code loader for Ruby that aims to replace the classic autoloader used in Rails 6. The presentation is structured around several key points that illustrate the motivations, functionalities, and implementation of Zeitwerk.

Key Points Discussed:

  • Introduction to Zeitwerk: Zeitwerk is a gem designed to handle autoloading, eager loading, and reloading of code. It is positioned as a standalone component, independent of Rails, and can be used in any Ruby project as long as the file paths adhere to specific conventions.

  • Historic Context: The talk starts with a comparison of Rails' existing autoloading mechanism against Zeitwerk’s improved method. Specifically, while Rails typically relied on an explicit path setup, Zeitwerk streamlines the process, focusing on consistent naming conventions and file structures.

  • Features of Zeitwerk:

    • No dependencies: Zeitwerk has a minimal footprint with no external dependencies, which simplifies usage across various Ruby environments including JRuby, albeit with some considerations for threads.
    • File Structure: The audience is guided through a recommended file organization that enhances autoloading efficiency. It emphasizes the correlation between file names, class/module names, and directory structures. For example, a file named user.rb should declare the User constant - a predictable relationship that Zeitwerk expects.
  • Efficiency and Memory Management: Noria highlights the issues that arise with the traditional Rails autoloading system, particularly regarding efficiency and memory. Zeitwerk addresses these by adopting a more intuitive approach to class and module loading based on Ruby's inherent constant resolution mechanics.

  • Implementation Examples: Various practical examples are provided illustrating how Zeitwerk manages file dependencies, organizes namespaces, and resolves paths, all designed to prevent common pitfalls encountered in Rails' autoloading.

  • Conclusion and Takeaways: Zeitwerk enhances the Ruby development experience by ensuring projects are structured for optimal performance. Proper coding literacy regarding file and module organization is critical for this system to function correctly and efficiently. Noria emphasizes that with Zeitwerk, developers can streamline their Ruby code loading process and improve the overall management of constants.

This talk encapsulates the benefits of adopting Zeitwerk, underscoring its role in modern Ruby development and the transition towards a more robust Rails autoloading structure.

00:00:17.320 All right, good morning! In this talk, we have a menu lined up for you. We will begin with an introduction to Zeitwerk. I will do my best to pronounce it correctly, even though I may not do as well as Monica.
00:00:23.000 I'll try because I've named this gem in a way that I cannot pronounce correctly. I can't explain why I did that, but here we are! Zeitwerk has been motivated by several factors, which we'll discuss today.
00:00:36.379 We'll look into how Rails autoloads files and compare that to how this gem does loading. Finally, we'll see how it integrates into Rails 6.
00:00:49.790 So, what is Zeitwerk? The main features are that it is a gem capable of autoloading, eager loading, and reloading code.
00:01:01.140 It's important to note that in order to eager load a generic project, you must first enable autoloading. Eager loading isn't just a naive recursive require, as you need to take into account constants at the top level and a graph of dependencies to load things correctly.
00:01:20.050 You cannot simply use recursive requires. This means that having autoload enabled is a prerequisite for everything else to wrap and, in the end, load the project properly.
00:01:30.050 In production, we often say we're eager loading, but while doing an inner load, autoloading may be happening. It's only when the entire project is loaded that you can disable autoloading since everything would then be in memory.
00:01:45.360 It's worth highlighting that the project has no dependencies. You may have heard that Zeitwerk is the new autoloader for Rails—that's true—but it's also designed to be a standalone gem. It’s independent and meant to be usable in any Ruby project or library, as long as the file paths follow the appropriate conventions.
00:02:06.760 So, no dependencies, just a pure standard Ruby API is what we need, which will make it integrate easily into Ruby projects of various kinds.
00:02:24.249 For JRuby, the situation is a bit different. If JRuby finally works correctly with Zeitwerk, we might need to utilize Concurrent Ruby for some thread-safe constructors. But aside from that, the footprint of Zeitwerk is very small, and there are no dependencies on Rails.
00:02:40.050 First of all, to use Zeitwerk effectively, you need to start with a project that follows a standard file structure. This means that file names should correspond to constant paths, just like when you're working with Rails.
00:02:55.150 For example, a file named user.rb should define the User constant, while a class UserProfile should define the UserProfile constant. We want to maintain a consistent naming convention.
00:03:09.000 Zeitwerk anticipates defining constants from snake_case to CamelCase. By default, it expects files such as html_parser.rb to define the HtmlParser constant. If you prefer uppercase letters for your constants, there is a method to accommodate that.
00:03:24.800 In a conventional project structure, directories correspond to namespaces. Although 'namespace' isn’t a formal term in Ruby, it conveys the idea that if you have a directory called hotel, that itself becomes the namespace.
00:03:37.000 Within that directory, you could have a file that defines a namespace, such as hotel.rb, where you define the actual Hotel class. This means that time when defining a file, if there's a structure in place, constants can be effectively organized.
00:03:54.980 For instance, a 'pricing' module placed correctly within directories should conform to conventions, leading to predictable outcomes in constant definitions.
00:04:15.080 Zeitwerk also recognizes implicit namespaces, which have existed in Rails for a long time. An example would be if you have an 'admin' directory where you do not need a corresponding admin.rb file to define the module.
00:04:29.799 If the directory exists, Zeitwerk will automatically build a dummy module there for you, ensuring that it's correctly defined in the context you've established.
00:04:43.990 With this structure established, you're ready to use the gem effectively. You can now instantiate the loader, push the root directories—these are where your relevant files reside. Within a Rails project, this might include the app/models or app/controllers.
00:05:06.990 In a Ruby project, the structure doesn’t need to be specific, but typically you'll just have a lib directory under which the project files reside.
00:05:20.140 Once you've done that, you just run the setup method, and you're ready to autoload and eager load your project seamlessly.
00:05:38.180 For myriad types of projects that utilize a lib directory and have a defined entry point, setting this up allows you to get immediate benefits from eager loading.
00:05:51.730 In the context of Ruby gems or projects that follow a standard structure, Zeitwerk alleviates the need to constantly deal with repetitive requires.
00:06:02.160 An underlying point to remember is that in Ruby projects, you have the advantage of setting up a project layout where the paths and modules are easily manageable.
00:06:16.750 This is one of the true benefits of using Zeitwerk: you streamline the loading process.
00:06:21.150 Now, let’s discuss how Rails autoloads and understand why the previous logic may have limitations compared to what Zeitwerk implements.
00:06:39.190 To do that, let’s have a brief refresher on constants, as much of the conversation around Zeitwerk involves understanding these constants and their relationships with classes and modules.
00:06:56.690 In Ruby, there’s a specific syntax for constants, and it’s worth noting that the concepts of classes and modules fundamentally relate back to how constants are assigned.
00:07:09.650 When you assign a class to a constant, Ruby automatically treats that assignment as a constant assignment. It’s essential to grasp this to understand the underpinnings of how autoloading functions.
00:07:21.800 So every time a constant gets assigned a class object, Ruby ensures that this relationship holds, understanding that a class is simply another representation of a constant.
00:07:34.250 Therefore, as you traverse through our Ruby code, whenever you invoke classes or modules, be mindful that ultimately, they are just constants holding respective class objects.
00:07:48.090 During this process, if you invoke a missing constant, the algorithm will kick in to attempt to load it based on its resolved path.
00:08:04.520 Now, let’s look closely at how Rails specifically sets up autoloading, the conventional libraries and paths involved, and how the resolution occurs.
00:08:17.480 In a typical Rails application, the autoload paths are generally configured in a way to look into directories related to the models and controllers.
00:08:28.990 When you define a class or constant, Rails will load files from these predetermined paths to associate the names correctly.
00:08:46.720 However, this approach is based entirely on the assumption that you've defined a pathway to reference constants. A common problem there may surface if this pathway is not established correctly.
00:09:00.240 It’s part of the broader context of Rails' autoloading, working with the fact that it may overlook certain files that need to be defined explicitly.
00:09:16.470 Moving forward, let’s consider the challenges presented when discussing the limitations surrounding Rails auto loading and how Zeitwerk aims to improve on this foundation.
00:09:36.000 One key aspect highlighted by Zeitwerk is the addressal of issues inherent in Rails autoloading, particularly concerning efficiency and memory management.
00:09:52.390 The overriding goal is to create a true framework that respects Ruby's semantics while delivering an effective class and module architecture.
00:10:10.250 With that, Zeitwerk introduces a more nuanced approach to how classes and modules are auto loaded, leaning heavily into the syntax inherent in Ruby rather than unorthodox conventions.
00:10:27.380 Let's delve into how these ideas manifest in the improvement over existing Rails applications and learn how we've managed to create a more stable learning environment.
00:10:41.450 As we continue on, the focus will be how this project enhances Ruby's innate capacity for constant resolution, which in turn facilitates the loading of dependencies smoothly and reliably.
00:10:59.670 There’s a clear incentive to streamline how your Ruby projects deal with file structures. The intricate aspects of Rails should not be abstracted away entirely but maintained through thoughtful structuring.
00:11:10.630 Let’s now investigate more acute examples that demonstrate both the pitfalls experienced with Rails autoloading and how Zeitwerk proposes to overcome them.
00:11:29.530 We'll scrutinize these examples against the framework laid out earlier regarding the definition of constants and how these relate back to module as they surface within the application.
00:11:45.540 Ultimately, the discussion here revolves around the ability to mitigate potential pitfalls in defining files by clearly understanding how and when certain constants are invoked.
00:11:58.780 This focus on verifying paths and ensuring clarity in naming conventions helps mitigate confusion and errors that would otherwise enter a production environment.
00:12:12.460 In closing, Zeitwerk stands poised to enhance the Ruby development experience and play a pivotal role in ensuring Rails autoloading transitions towards a more satisfactory and efficient methodology.
00:12:26.410 It's critical, however, to remember that coding literacy, in terms of structuring one's project, is equally important in this refined approach.