Ruby Standard Library

Just when you thought you couldn’t refactor any more…

Just when you thought you couldn’t refactor any more…

by Claudio B

In this talk titled "Just when you thought you couldn’t refactor any more…" at RubyConf 2017, speaker Claudio B. embarks on a refactoring journey aimed at improving Ruby code readability and functionality. The session focuses on understanding methods available in Ruby, particularly those introduced in the 2.4 release, and how they can enhance code quality by adhering to the four C's of good code: Correctness, Completeness, Clearness, and Compactness.

Key Points Discussed:
- Introduction to Ruby's evolution and the consistent release of new methods, emphasizing the importance of staying updated.
- The format of the talk is structured around a real-life example involving parsing YouTube URLs to demonstrate coding solutions in Ruby.
- Claudio introduces the concept of a 'parse' method to identify different YouTube resource types (videos, channels, playlists, and unknown links).
- The initial approach utilizes the 'start_with?' method from Ruby's String class to classify the URLs but is found to be verbose and unclear, leading to code duplication.
- To improve the code, he introduces the newly available 'String#match?' method, which leverages regular expressions for more concise and accurate parsing of URLs. This allows for effective capturing of video IDs and channel names, streamlining the logic in the code.
- Claudio further refactors the solution by implementing named captures in Ruby 2.4. Named captures help in removing redundancy, enhancing clarity, and making the code reusable and elegant.
- Discussion of using constants to manage patterns for different resource types, improving organization and maintainability of the code.
- Introduction of the Enumerable module, specifically the 'find' method, which aids in managing the complexity of matching operations.
- Concludes with a reflection on how proper structuring and organizational strategies can lead to cleaner, more efficient code solutions while encouraging audience interaction and feedback on the presented methodologies.

Takeaways:
- Understanding Ruby's rich set of methods can significantly improve code quality.
- Continuous refactoring leads to more readable and efficient code, aligning with best practices in programming.
- Engaging with the community for collaborative learning and sharing experiences is beneficial for further growth in coding skills.

Overall, the talk serves as an insightful guide for Ruby developers at all levels, highlighting practical applications of Ruby methods in real-world scenarios.

00:00:10.340 Good afternoon, my name is Claudio, and I'm really excited to be here at RubyConf.
00:00:17.490 This talk is actually about Ruby, the programming language that we all love to write and read. It's a language that is a little old, but still evolving.
00:00:30.060 In fact, there is a new release every year with new methods added. Today, I will provide an overview of some methods that I'm going to cover during this talk.
00:00:44.010 Some of these methods have been in Ruby for many years, while others were just introduced in the 2.4 release last December.
00:01:02.219 The format I chose for this talk is a refactoring journey, and I invite you all to join me on this journey.
00:01:12.869 We will take a problem—an actual problem I faced at a previous job—and find a solution in Ruby. We'll begin with the first pass and then iterate through the problem, utilizing some of these methods to improve our code.
00:01:21.479 Whether you are a beginner or an expert Ruby developer, I hope you will learn something from this talk.
00:01:38.579 Now that the doors have magically closed, let's get started. Let me give you some context for the example problem we will use to explore these methods.
00:01:52.350 This example revolves around YouTube URLs, which I dealt with frequently at my previous job. If you have ever watched a video on YouTube, you've likely encountered a URL of one of these types.
00:02:06.450 For instance, the first URL is for a YouTube video, the second URL is a shorter format for another YouTube video, the third and fourth URLs are for YouTube channels, and the last URL is for a YouTube playlist.
00:02:26.140 So we have different URLs that are subtly different strings representing distinct types of resources.
00:02:33.730 We are going to write a method called 'parse' which accepts a string as input and identifies the type of YouTube resource it represents.
00:02:46.420 For the first type, which is a YouTube video, ideally this 'parse' method should return that it is a video. In the second case, we expect it to return a channel based on the name of that channel.
00:03:06.310 For instances where the URL does not match a YouTube resource, we expect it to return 'unknown'. As Rubyists, we want to write code that is not only correct and complete but also clear and compact.
00:03:20.109 We aim to follow the philosophy of 'Don't repeat yourself.' This is the problem we will address over the next thirty minutes.
00:03:25.480 Before diving in, I want to give you a moment to think. If this were a job interview and you were presented with this problem, what methods would you use if you had access to all the methods in the Ruby standard library?
00:04:02.889 Okay, let's start with a first attempt. I noticed that these URLs start in different ways: the first one starts with 'youtube.com/watch', indicating a video; the second starts with 'youtube.com/', suggesting it's a channel. The last one doesn't even contain 'YouTube,' so it may be classified as unknown.
00:04:27.550 My first thought is to use the 'start_with?' method from the String class. This method returns true if the string starts with one of the specified prefixes. For example, 'hello'.start_with?('hell') is true, and 'hello'.start_with?('heaven') is also true because one of the prefixes matches.
00:05:00.010 However, there are some complications. Initially, I believe this first pass will be clear, but there are significant issues.
00:05:06.610 This code isn't compact because we have repetition and fails to deliver correctness. For instance, if the URL is just 'youtube.com/', that is actually the homepage, not a channel.
00:05:43.310 YouTube has strict rules regarding how URLs are formed; every video has a unique 11-character ID consisting of letters, digits, underscores, or hyphens. You will learn this principle today as we delve deeper.
00:06:19.450 To enhance our iteration on the solution, we can employ the new 'String#match?' method added in Ruby 2.4. This method allows us to compare a string with a regular expression to check for a match.
00:06:48.740 Earlier, we needed explicit matching conditions. Using this new approach, we can rewrite our code so that it checks if the given string matches our expected regular expression.
00:07:31.790 In the first case, we can capture the video ID, ensuring we correctly identify it. For a channel, we can require at least one character. This means our URL parser can now distinguish between videos, channels, or unknown types.
00:08:14.870 But we could further improve this code by eliminating the duplicate calls to 'match?' in the next iteration.
00:08:51.500 We can use the triple-equal operator, which allows comparisons with the Ruby language's case statements, enabling us to streamline our checks without rewriting the same checks multiple times.
00:09:25.960 So refactoring allows us to remove code duplication, but our current version still hasn't resolved the initial requirement to return both the Type and any additional desired value, such as the ID or name.
00:09:49.340 Thus, we are searching for a robust way to retrieve those relevant strings when we perform a match.
00:10:34.850 When matching in Ruby we can capture segments using parentheses while assigning them names. This will maximize our ability to extract whatever we need from the last match.
00:10:59.640 For example, when capturing currency values in a string, we can later refer to those named segments to get specific numeric values.
00:11:29.090 So let's write our code capturing IDs for video URLs and channel names to return in the output hash.
00:11:59.350 Even though we've arrived at a solution that works, it still simply returns results without condensing the logic, leading us to redundancy.
00:12:24.360 In Ruby 2.4, there's a concise way to retrieve values from several named groups at once known as 'named_captures'. By applying it to our earlier example, we can get more reusable and elegant syntax by grouping patterns based on functionality.
00:13:03.440 This would further minimize the repetition we currently face in returning grouped types together. Let's see how we apply named captures for our existing environment.
00:13:44.030 With our current example, matching 'youtube.com/whatever' URL works and returns effectively because we can now dynamically capture ID or channel information.
00:14:26.320 Yet even after simplifying this structure, we need to consider the relationship between patterns and proper structures to help manage complexity in what we write.
00:15:09.860 Diving into refactoring again, it's essential we can align keys with each specific group. Rather than leaving them stuck together, the patterns need to be separated for enhanced read-ability.
00:15:53.510 When segregating URL patterns, it's necessary to assign separate constants for each distinct type we will encounter, such as video and channel patterns.
00:16:32.350 By adopting this structure, we lessen the confusion during maintenance or changes to those identifiers later.
00:17:14.090 Next, incorporating Enumarable enables a more powerful response in organizing our operations with patterns in the search for matches.
00:17:55.790 The foundational method of 'find' enables an easy identification of any matching criteria as we raise and understand the limits of iterations during these functional methods.
00:18:40.620 Thus far, the latest method I will implement allows for returning matches through a match method loop capturing only once and iterating until we find what was requested.
00:19:30.350 This approach supplies us with the necessary context around how rare it can be to clarify patterns expected--obviously relying on the knowledge of shape and form when creating them.
00:20:20.940 This newfound methodology continuously demonstrates helping us connect with returning actionable results based on named captures.
00:21:00.370 Placing those results into a hash clears our cluttered earlier structure while refining explicit connections between patterns.
00:21:41.790 I propose developing this more compact way sooner than later to make our future nomenclature a global mapping of data rather than funneling through repetitive checks.
00:22:23.010 As we take everything together, the ability to maintain organizational structure goes both deeply in code read-ability and efficiently back to defining individual parts.
00:23:05.350 Not only does this foster interaction with each recognized pattern, but improving strategy also dictates clarity and direct flow without convoluted segments.
00:23:47.310 Restructuring any future developments can lean more prominently in nested patterns, ensuring the utilization is more accurate than ambiguous.
00:24:30.800 Therefore, wrapping up, I invite feedback or shared ideas correlating to these strategies and suggest a conversational platform beyond today's conference.
00:25:15.800 There are several methods residing with Ruby's library to flourish your coding journey; it's essential to utilize these effectively for your benefit.
00:25:56.650 Thank you for your attention, and I'm eager to answer questions or continue our conversation throughout the conference!