Talks

Make Ruby Functional Again!

Make Ruby Functional Again!

by Devon Estes

Summary of 'Make Ruby Functional Again!'

In the presentation titled "Make Ruby Functional Again!" given by Devon Estes at Ruby Day 2016, the main theme revolves around the evolution of Ruby in the context of multi-core processing and the necessity to embrace functional programming concepts to maintain its relevance as a programming language. Estes introduces several critical challenges Ruby programmers face due to shifting processing technologies and user expectations.

Key Points Discussed:

  • Introduction to Ruby's Challenges:

    • Discussion on Moore's Law and how its decline affects application performance and complexity.
    • Highlights the shift from faster clock speeds to multi-core processing.
  • Functional Programming as a Solution:

    • Ruby programmers are encouraged to explore functional programming features to optimize code for multi-core systems.
    • Key functional programming concepts mentioned include:
    • Immutable Data Structures: Use of the freeze method for immutability.
    • Lazy Evaluation: Introduced through methods like lazy in Enumerator, enhancing performance.
    • Pure Functions: Focus on writing functions that return consistent results and do not have side effects.
    • Higher-Order Functions: Utilization of blocks in Ruby for efficient API implementations.
  • Refactoring Code Examples:

    • A practical demonstration involving code refactoring to improve clarity and maintainability, including creating separate classes for team and game data for an NFL API wrapper.
    • Advocates for method objects to achieve single-responsibility functions, enhancing readability and testability of the code.
  • Community and Collaboration:

    • Emphasizes the strength of the Ruby community and the necessity for collaborative innovation in improving Ruby.

Significant Examples:

  • Personal Anecdotes:
    • References to personal interests, like Japanese culture and Shiba Inu pets, to engage the audience.
    • Humor through anecdotes, such as Aaron Patterson's cat pictures at RubyConf.

Conclusions and Takeaways:

  • Future of Ruby:
    • As user demands and application complexities rise, Ruby must adapt to retain its place in modern programming.
    • Encouragement to leverage the existing features in Ruby for better performance and maintainability.
    • Final call to action for the community to collaboratively work towards enhancing Ruby's functionality and performance.

Devon Estes concludes by instilling enthusiasm for experimentation and collaboration within the Ruby programming community, ensuring Ruby's ongoing evolution in alignment with technological advancements.

00:00:21.500 Today, I am here representing my company, Education SuperHighway, which is based in San Francisco. We focus on improving the broadband situation in U.S. schools.
00:00:52.129 Before we begin, good morning! I’ll try to be funny, as I know that's a crucial part of presentations. To help me with that, I want to start with a famous quote.
00:01:03.329 The quote goes: 'First, make the change easy. If it's hard, then maybe the change is not going to happen.' This made me think about how to make today's talk engaging and humorous.
00:01:19.020 I considered how the presentation feels for first-time attendees. They often don't know what to expect or how to process the information. So, I decided to use emojis to help convey the emotions involved.
00:01:30.470 Now, I've added some emojis into the presentation, and I also love Japanese culture, especially the language and aesthetic. Did you know Ruby is actually a Japanese programming language? One of my favorite bands is also Japanese. If you haven't heard of Babymetal, they are a speed metal band fronted by three teenage girls from Japan—a fantastic combination!
00:01:51.990 But on a more personal note, I own a Shiba Inu, which is the national dog of Japan. Her name is Miki, and I have a picture of her from when she was just a few weeks old when we first got her. This is what she looks like today; she gets so excited when I come home. That's part of the charm I want to share with you all today, along with my love for emojis.
00:02:38.430 I also recently attended RubyConf, where Aaron Patterson made me laugh by airdropping pictures of his cats to everyone at the conference. So, if you have airdrop capabilities turned on, you might receive a few pictures from me as well!
00:03:24.400 Now, I want to address a problem we, as Ruby programmers, might not yet recognize. We have a challenge created by Moore's Law. If you're not familiar, Moore's Law theorized that processing speeds would double approximately every 12 to 18 months.
00:03:35.020 For a long time, this was true, but eventually, this cycle became less predictable. Users began to expect applications to be faster and more complex every year, but the reality is that the processing power needed to keep up with these expectations is not quite there.
00:03:52.480 Consider how hard it would be to write video games today compared to ten years ago; the hardware just wasn't available then. As programmers, we relied on the increase in processing speeds to deliver high-quality products.
00:04:06.190 However, I have some bad news: for Ruby, Moore's Law is essentially dead. More specifically, it's no longer applicable because the focus has shifted from simply faster clock speeds to building more cores into processors.
00:04:32.260 Typically, when I refer to Ruby, I mean MRI (Matz's Ruby Interpreter) because JRuby and Rubinius handle native threads much more effectively. Yet, most usage still revolves around MRI.
00:04:50.080 As an illustration, look at this graph of Intel chip processing clock speeds from 1975 to 2012. You can see that around 2004, the curve plateaued. We hit a wall, and it dropped very sharply from there.
00:05:04.150 This stagnation predominantly happened as we reached our engineering limits. Many of the features on chips are now smaller than some viruses. At these scales, we start encountering unpredictable results and excessive heat, which inhibit further development. Therefore, manufacturers pivoted towards multi-core processing.
00:05:58.990 We have been living in a multi-core world for over a dozen years now, and many developers are looking to functional programming to optimize their code for these architectures.
00:06:12.460 Often, this doesn’t stem from the fact that functional programming is inherently superior for such architectures. Instead, many of the features offer simplified multi-threading and concurrent programming.
00:06:18.360 Some of these helpful features include immutable data structures, delayed evaluation, pure functions, higher-order functions, and curried functions.
00:06:31.660 Fortunately, all of these concepts already exist in Ruby to some extent, and while utilizing these features may be slightly challenging, they are available. For example, we can achieve immutability in Ruby using the `freeze` method.
00:06:52.720 There is also lazy evaluation available with methods like `lazy`, particularly in `Enumerator`. Active Record in recent years has become an excellent example of this laziness in its operation, which allows for improved performance.
00:07:10.740 When looking at pure functions, it's essential to realize that while they may be more difficult to achieve in Ruby due to its natural inclination towards mutation, the focus on designing high-quality implementations is paramount.
00:08:00.930 As for higher-order functions, Ruby excels in this area due to blocks, which serve as an elegant API. Additionally, Ruby includes methods for carried functions in its standard library.
00:08:21.640 However, we still haven't fully embraced these features just yet. I believe Ruby has the potential to remain a language of the future, but we need to rethink how we write our programs. We cannot continue with our current methodologies because that simply won't work as user expectations rise.
00:09:11.290 Users will demand better performance, and leveraging all cores will become necessary to provide that performance. While Ruby Three aims to improve concurrency and integrate a better threading model, it's crucial that we start experimenting now.
00:09:25.590 One of Ruby's greatest strengths is its community, and collaboration is key to innovating future versions of the language.
00:09:39.680 Today, we are going to take a closer look at some Ruby code and refactor it with the future of threading and performance in mind.
00:09:51.150 Let's consider a hypothetical API wrapper for the NFL where we can fetch data about teams or games. We're writing a little command-line interface (CLI) alongside this.
00:10:03.390 First, here's what our CLI script looks like. It straightforwardly fetches data based on the inputs provided—no surprises there. Here are the two public client methods for fetching a team's data and fetching game data, respectively.
00:10:45.810 In the client, we have methods set up to construct the API URL, fetch the raw data, and additional private methods that enhance our data by adding metadata.
00:11:01.990 However, upon reviewing the code, we can see it's not great practice as different responsibilities are jammed into the same class—this should lead us to consider extracting classes.
00:11:18.020 In our new CLI, we would create separate classes for the team data and game data, both inheriting from a base class that abstracts shared methods.
00:11:29.360 This effectively cleans up the hierarchy while ensuring we maintain similar functionality without redundancy. Still, I want to express my hesitations regarding the reliance on inheritance.
00:11:55.640 As classes become more complex, inheritance may lead to tightly coupled code, which can hamper efficiency. Moreover, there's the mystery guest anti-pattern, where class methods could reference data that isn't immediately clear, leading to confusion.
00:12:05.300 Testing becomes difficult when methods are intertwined with hidden dependencies. To address this issue, I advocate for using method objects—which will aid in isolating functionality.
00:12:22.600 Method objects allow us to create clear single-responsibility functions, making our code easier to read and test. Each object would have a single public method, which provides clarity and fortune-telling abilities for debugging.
00:12:57.639 Our extracted classes now become more manageable with single public APIs, and we can easily pass in mocks for testing; this makes the overall code significantly cleaner.
00:13:10.429 Transitioning towards utilizing pure functions can also be beneficial. A pure function consistently delivers the same output for the same input without side effects, making it simpler to test and integrate into applications.
00:13:35.220 Let's quickly evaluate Ruby's built-in methods against these criteria. For example, `IO.read` is not a pure function because it interacts with the file system. On the other hand, basic mathematical functions like `Integer#+` demonstrate pure function characteristics as they deliver consistent results without side effects.
00:14:15.900 As we refactor, it is essential we deliver functionality while maintaining the pure function principle, allowing our main application logic to manage side effects efficiently.
00:14:48.700 By keeping our side effects at the boundaries of our application, we retain flexibility and improve the testability of our code.
00:15:27.330 Let's take a look at how we can implement some of those metadata-adjacent features while avoiding mutation. For instance, returning a frozen hash for shared data allows us to promote state changes without issue.
00:15:55.109 As we advance, naturally, we should strive for maintaining immutability and consider the implications for future Ruby versions using guilds.
00:16:10.600 It's crucial that we start planning for freezing our objects and data as part of our best practices in Ruby, especially in multi-threaded environments.
00:16:44.480 In summary, if there's one core takeaway from today's talk, it's to leverage method objects, which help clarify your code structure and make it significantly easier to manage and test.
00:17:29.290 Dash away mystery guests from your codebase. You'll improve your mental clarity immensely by ensuring you can see everything your file needs without expanding into other contexts.
00:18:00.100 Look for more opportunities to implement pure functions and ensure side effects are confined to a controllable boundary.
00:18:27.820 As we move toward a future of increasing complexity and multi-threading in programming, let's dedicate time to think about how we can enhance Ruby collectively.
00:18:55.570 I believe that Ruby can maintain its relevance and will continue to grow, given our exceptional community. Together, we possess the capability to propel Ruby forward.
00:19:25.720 Let's embrace this and take pride in our shared mission to improve Ruby as a language. Thank you for listening, and I hope to encourage each of you to contribute a little time towards this goal.
00:20:00.860 Let’s engage with the community, collaborate, and never hesitate to bring up our thoughts and ideas for a better Ruby. Thank you!
00:20:30.860 Now, regarding monads—it's not something I regularly implement. However, I am interested in utilizing them within Active Record's attributes API eventually.
00:20:55.900 And of course, there are gems that enhance concurrency and threading in Ruby. While not many seem to actively use them today, ensuring awareness of their existence is essential.
00:21:10.990 It's vital that we begin thinking critically about these aspects to prepare ourselves for future implementations.
00:21:24.350 There will come a time when high-performance, multi-core systems become the standard. As we evolve, Ruby itself might need to adapt some of its architecture to meet those demands.
00:21:50.490 I believe the community will push for these advancements, and it's our responsibility to remain adaptive.
00:22:03.820 As we strive to maintain the joy and elegance of coding with Ruby, we should also prioritize discussions on performance improvements—aspects like enhancing the garbage collection process.
00:22:45.670 In conclusion, thank you all for being here, and I hope you always feel inspired to experiment, innovate, and collaborate. Let’s continue to elevate Ruby together!