Talks

Ruby Racing: Challenging Ruby Methods

Ruby Racing: Challenging Ruby Methods

by Danielle Adams

Ruby Racing: Challenging Ruby Methods

In this video, Danielle Adams discusses optimizing Ruby code performance, drawing on her experiences at Blue Apron and insights gained during her Ruby programming. The presentation explores the execution of Ruby code at runtime, ways to speed up methods, and key performance considerations related to Ruby programming.

Key Points Discussed:

  • Introduction to Ruby Programming:

    • Danielle introduces herself, her role at Blue Apron, and her recent work on a Ruby microservice for printing shipping labels.
    • Engages the audience by gauging their programming experience and familiarity with Ruby.
  • Ruby Code Execution at Runtime:

    • Discusses the process of code transformation from written scripts into tokens, using Ruby's Ripper tool to demonstrate this parsing.
    • Explains the conversion of scripts into an abstract syntax tree and subsequent compilation into bytecode for interpretation by the Ruby Virtual Machine (MRI).
  • Performance Optimization:

    • Shares insights from discussions with co-workers regarding identifying programming proficiency through coding interviews using practical Ruby problems.
    • Introduces her Ruby gem, 'Ruby Racer', designed to benchmark user-defined methods against Ruby's built-in methods, showcasing the importance of testing performance.
  • Method Implementations and Comparisons:

    • Demonstrates various implementations of commonly used methods like 'flatten', 'unique', 'max', and 'min'.
    • Highlights how different approaches can yield varying performance results, showing that optimal performance in Ruby often requires tailored coding strategies.
  • Factors Affecting Performance:

    • Discusses the balance between code readability, performance, and maintainability, underscoring the importance of all these factors.
    • Emphasizes Ruby's strengths beyond performance, such as community support and documentation quality.
  • Exploration of Ruby Source Code:

    • Analyzes how Ruby's native methods are constructed, revealing the underlying principles that contribute to their efficiency.
  • Conclusion and Takeaways:

    • Reiterates the significance of enjoyment in programming while recognizing the value of experimenting with Ruby's capabilities.
    • Encourages the audience to embrace Ruby's strengths and keep learning while using Ruby as a powerful tool for development.

Through the presentation, Danielle emphasizes that while Ruby may face some performance critiques, its usability, community support, and robust features make it a strong choice for many programming tasks.

00:00:09.720 Hello everyone! I'm Danielle Adams, and I come from New York. I work at a company called Blue Apron, where I help turn millions of pounds of raw goods into prepped ingredients that we ship across the country for families to cook delicious meals together. Recently, over the summer, I worked on a microservice in Ruby that printed out shipping labels and stuck them to our Blue Apron boxes. On a personal note, I also just got a cat, so like most cat owners, I spend a lot of my free time taking pictures of him while he sleeps.
00:00:43.680 Now, let’s get started! How many of you in here are programmers? Awesome! And how many of you primarily write in Ruby? Great! Now, how many people can confidently say that their Ruby code runs as fast as possible? Just one? There’s always one! That's okay; as programmers, we have a lot going on. We're writing code and tests, deploying it, having meetings, and communicating with product and engineering managers. We are fixing our own bugs and fixing other people's bugs too.
00:01:01.950 It’s important to note that it's not necessarily our responsibility to ensure our code runs fast, as long as it’s running efficiently. Ruby is a prime example of an open-source language that we depend on, along with other projects to ensure that our work meets expectations. I’d like to give you a brief outline of what I’ll cover today. First, we’ll discuss what happens when your code executes at runtime. Then, we’ll talk about how to speed up your Ruby code and dive into some Ruby source code.
00:01:44.190 So, let’s talk about what happens during runtime. Can anyone tell me what this block of code does?
00:02:02.820 Yes, 'pop'! That’s right, it’s much shorter and easier, and that’s one of the reasons we love coding in Ruby. To understand how Ruby methods work, we start with our code that we write out clearly, and then it gets transformed into tokens. I’ll demonstrate this using the Ruby method Ripper, which allows us to parse a script and display what happens when compiling and interpreting Ruby code.
00:02:41.040 For example, with a simple Ruby script that says hello, we have the method definition, argument, code execution, and invocation at the bottom passing in its argument. This is first converted into tokens, and then we can visualize what a script looks like as an abstract syntax tree. We construct a tree structure that defines it as a program, including the method's name and parameters.
00:03:38.930 Now, we convert that script into symbolic expressions. After we've done this, the method gets compiled into bytecode, which is then interpreted by the Ruby Virtual Machine, or MRI, which stands for 'Matz's Ruby Interpreter'.
00:04:18.449 Next, I want to disassemble this compiled object to see what the Ruby VM is actually processing. Here, we can observe the instructions the VM needs to execute the desired code.
00:04:52.330 This can often resemble low-level assembly language instructions, particularly for Ruby that runs under C library. Other Ruby implementations like JRuby use the Java VM, and Rubena executes it differently. Now, let’s talk about how to speed up Ruby code.
00:06:17.010 This topic emerged from discussions with my co-workers about how we could better assess incoming candidates during interviews. We considered relevant problems that could apply across our different departments, all using Ruby but through various frameworks, including Rails and plain Ruby. For example, one of my co-workers asked candidates to rewrite the 'flatten' method recursively and then without recursion. This way, we could evaluate their understanding of Ruby and computer science fundamentals.
00:07:01.270 Through whiteboarding sessions, we worked to refine our own solutions, ensuring they were effective and correct. We then benchmarked the candidate's solutions against the Ruby versions of those methods. To my surprise, my version turned out to be faster than Ruby's implementation, which sparked a lot of questions in my mind.
00:08:09.430 Why wouldn’t Ruby code simply be the fastest? This question prompted me to experiment further to see if I could beat the Ruby library's versions with my solutions. Thus, I created a Ruby gem—‘Ruby Racer’—which allows you to measure the speed of your methods against Ruby's built-in methods. You can easily install it via RubyGems. It currently only supports arrays and numerals, but contributions are welcome!
00:09:08.430 Let's move to a demonstration. To illustrate this, I’m going to race a 'flatten' method against the Ruby version. As you can see, the implementation duplicates the input and processes it through a stack structure, returning a new array.
00:10:10.430 I’ll run the race now. In this example, my implementation was actually slower than Ruby's. Still, during my actual testing at work, the input we provided did significantly improve the performance of my method compared to Ruby's built-in method.
00:11:00.000 Next, I’ll showcase a unique method implementation that I created, which uses a different approach than the typical 'each' method. This implementation uses a while loop instead, iterating through the array and retaining unique values.
00:12:25.600 Here we’ll race this 'unique' method against the Ruby version. It runs close, sometimes faster, sometimes slower. The differing runtimes are often dependent on the environment in which they are run.
00:13:30.000 Now moving on to the 'max' method. In this implementation, we traverse the array, keeping track of the maximum value found as we go. Similarly, I have an implementation of the 'min' method which follows the same pattern.
00:14:59.000 As you can observe, this runs consistently faster, demonstrating how linear complexity performs much better in Ruby. This is true for many basic operations.
00:15:36.000 To deepen our understanding, let’s discuss performance factors in Ruby. Primitive operations are generally fast, and while loops can be better than using higher-level iterative methods, it can sacrifice readability. Code quality should not solely be determined by speed.
00:16:55.000 Many factors contribute to code quality including readability, scalability, and the ability to test code effectively. Ruby's strengths are not merely its performance.
00:17:46.030 We don’t have to look solely at speed; Ruby excels in many areas, from its supportive community to its robust documentation, and even its aesthetics.
00:19:02.299 Now let’s dive into some Ruby source code to illustrate how methods like 'flatten' and 'unique' are constructed. This exploration can only enhance our understanding of Ruby's efficiency.
00:19:33.330 Following up to source code, the Ruby 'flatten' method builds a results array through stack manipulation, cleverly handling nested arrays.
00:19:57.000 Next, looking at 'unique', which checks for conditions before proceeding and effectively uses hashes under the hood.
00:20:08.660 Lastly, Ruby's 'sort' method efficiently duplicates an array with simplicity.
00:20:39.310 In conclusion, Ruby programming enhances productivity and enjoyment, but we should balance performance with readability and maintainability.
00:21:16.770 Ruby, despite some of its performance critiques, remains an excellent choice for many tasks, emphasized by its supportive culture and documentation. Programming is meant to be enjoyable!
00:21:48.320 With that, I’d like to incorporate a quote about programming creativity and its intersection with knowledge. Thank you!
00:22:28.000 Overall, thank you everyone, remember to experiment, embrace Ruby’s strengths, and continue to learn!