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!