00:00:13.130
Go ahead, thumbs up! I have to be honest; this room has a lot more people than I expected. Thank you all for coming! It's great to see so many smart people choosing to spend 45 minutes of your time here with me. I'll try to make it worth your while.
00:00:26.369
This is a talk about the Ruby Singleton Module, the Singleton pattern itself, and an interesting realization I came to while learning about these topics.
00:00:38.069
A little bit about me: my name is Mike, and I live in Vancouver, Washington, just a suburb of Portland, Oregon. I spent about nine consecutive years in Nashville, so it feels a bit like being back in my old stomping grounds.
00:00:49.589
You can usually find me on the internet at comike 011, where there’s a humorous photo of me passed out on a train. It was an exceptionally hot day, and that’s probably the reason behind it! I work as a senior engineer with a company called VOCA, based out of Santa Barbara, California. They let me work remotely, and we specialize in AI-powered call tracking and analytics.
00:01:07.280
Oh, and we're hiring! I wanted to emphasize this, so for a brief moment, please enjoy this multimedia experience. Come and talk to me or anyone wearing a VOCA t-shirt; we’re awesome people!
00:01:17.950
Now, about this talk: once it was accepted for the conference, it underwent an evolution that I didn't expect. I realized it had three primary parts: the Singleton pattern, the Singleton module, and the Ruby Singleton class.
00:01:26.590
Let’s dive into how we got here. The RubyConf call for proposals opened in July, and I submitted this talk about half a month later. I wasn’t very quick to it.
00:01:38.230
Originally, it found its home in the general track, but its origins were rooted in Ruby's documentation.
00:01:44.800
When I decided to submit the talk, I didn't really know what I was looking for; I mainly turned to the standard library to find something interesting.
00:01:51.400
I stumbled upon the Singleton pattern. I had heard of Singletons before but didn't know much about them. The documentation regarding the Singleton module was exceptional. There’s a very succinct description that states, 'The Singleton module implements the Singleton pattern.'
00:02:06.170
So again, thank you very much. I appreciate it, and I’ll take questions later. To begin, let’s start in the middle and work our way back to the beginning. What exactly is the Singleton pattern?
00:02:13.310
The Singleton pattern is one of the Gang of Four design patterns detailed in the book, 'Design Patterns: Elements of Reusable Object-Oriented Software.' There are several characteristics of Singletons that I find both objective and somewhat subjective.
00:02:26.590
For starters, Singletons restrict the creation of a class to a single instance, providing a single access point to that single resource.
00:02:38.230
In other words, there is one instance of a class, and we always have a mechanism to gain access to it no matter where we are in our application.
00:02:45.540
While it has a global scope, it's not necessarily a global variable. Singleton instances don't occupy space in the global namespace like global variables do.
00:02:57.880
Furthermore, Singletons are not instantiated until explicitly called, unlike global variables.
00:03:08.670
Now regarding the application of Singletons, there’s a more subjective aspect to consider. Many of you may already be aware of the concerns surrounding global variables; much of the programming community tends to distrust them.
00:03:18.890
Tightly coupled code is often a point of contention, which is why a lot of developers shy away from using global variables, leading to testing files that are more of stubs and mocks than actual tests.
00:03:29.860
You wouldn’t be alone in this sentiment. The more I read about Singletons, the more opinionated the discourse seemed to be.
00:03:35.860
For instance, one article pointedly asked, 'Are Singletons bad?' and did so with a lengthy critique.
00:03:43.290
This author compiled six reasons to avoid Singletons. He remarked, 'Yes, I’m writing a blog post about why the Singleton pattern is bad in 2016,' but the subject continually arises in discussions.
00:03:52.420
Here's a list of reasons often cited for avoiding Singletons. The downside is that this post emerged because the author was frequently forced to discuss Singletons. He thought to document his points so he wouldn’t have to bring it up again.
00:04:00.520
He claimed: 'Most patterns from the Gang of Four are straightforward and logical. However, there’s one specific pattern that receives universal disdain from every programming-related website: the infamous Singleton pattern.'
00:04:11.690
This has been labeled as the most overused and frequently misapplied programming anti-pattern out there.
00:04:21.060
In the same vein, various articles have labeled Singletons as 'pathological liars' and many others have stated that they are untrustworthy.
00:04:27.360
I love the band LCD Soundsystem, and this notion of ‘Single being bad’ strikes a chord with me.
00:04:34.430
So what are these concerns regarding Singletons? I previously mentioned problematic misuse, but let’s explore that in greater detail.
00:04:47.160
Single instances allow for multiple points of access to a shared resource. This isn’t inherently problematic if it’s immutable.
00:04:55.640
However, if shared resources can be altered, that can lead to significant issues.
00:05:01.950
Additionally, a Singleton can introduce objects that are globally accessible and modifiable, which means that if one area of your application manipulates it, it can have unpredictable effects elsewhere.
00:05:07.830
This leads to a violation of the single responsibility principle. Such objects are intended to maintain a single instance of themselves but may also be responsible for various other functionalities.
00:05:14.160
Moreover, this raises questions about testability. If we employ proper practices, one might find themselves stubbing or mocking the Singleton for every test.
00:05:21.570
This leads us to the final concern: a single point of access to a shared resource leads to tight coupling.
00:05:29.810
I came across an illustrative, albeit somewhat contrived, narrative about a user management application. If an application is designed to manage a single logged-in user, the attributes of that user must be accessible throughout the application.
00:05:41.200
Thus, making the user a Singleton allows access in whatever context it’s needed, without the need to consistently reload it.
00:05:49.460
However, consider a situation where a user changes their email address or last name; that could change in one place, but other parts of the application might not have received that information yet.
00:05:58.320
This leads to a tangled mess where users' details can fall out of sync, resulting in prediction and functionality problems.
00:06:06.480
Despite this, I don’t want to imply that Singletons are universally bad ideas. Many writers and experienced developers see them as usable design patterns for valid reasons.
00:06:15.480
I will suggest that Singletons are particularly practical in circumstances that feature a unidirectional flow of data. In other words, exchanges where there is no expectation of values being altered based on requests.
00:06:28.550
In scenarios where this class is utilized universally or across disparate areas, one could achieve similar outcomes through dependency injection.
00:06:38.630
However, this can become tedious, as you would have to pass that object to many areas that don’t necessarily need to work with it.
00:06:44.930
A typical use case is logging, where having a single logger class accessible globally may not be a bad idea. It provides consistency.
00:06:52.080
For instance, one could send information to log and receive a simple response indicating whether the log was successful—how often, after all, do loggers fail?
00:07:02.240
The information flows in one direction from the application to the logger, which works well since loggers will likely be needed universally.
00:07:10.360
Again, if we introduced logging through dependency injection, we would need to pass a logger into every class.
00:07:18.510
Another example would be configurations. Ideally, our configs, for our passwords and such, aren’t changing often.
00:07:25.410
We might want to access API authentication tokens globally, and ideally, those too should remain unaltered.
00:07:34.750
While we want to avoid anything globally accessible that can be changed by our application, we may still want to utilize external files for settings.
00:07:43.040
Thus, we could have a Singleton that pulls in these external configurations while being immutable within the application, resulting in a consistent state.
00:07:51.780
Now that we’ve established the concept of the Singleton pattern, let’s discuss the Ruby Singleton library, Singleton.rb.
00:08:05.200
We’ve already read through the docs, so we know what’s there. Singleton.rb is where this started for me.
00:08:17.360
I found it interesting that there is a module specifically dedicated to this pattern. Though it's not in the standard library, it can be easily included and leveraged.
00:08:28.390
The module does a lot more, but I want to highlight some key characteristics.
00:08:37.630
A key characteristic is that there is a single instance of this designated class. To ensure this, the 'new' method is made private.
00:08:46.930
The 'allocate' method is also made private, meaning they cannot be directly called. Instead, they are replaced with 'instance', which pulls the existing Singleton into your context.
00:08:56.860
Furthermore, cloning is not allowed. Calling 'clone' or 'dup' will produce errors, reinforcing that there is only one instance.
00:09:06.800
To illustrate how this works, I have an aptly named 'SingletonExample' class with an attribute called 'goggles'.
00:09:15.440
When I try to create a new instance at first, it fails because we’re attempting to call a private method.
00:09:24.870
The error message is informative but doesn’t explain why, hence we start over and use the appropriate method to instantiate our Singleton.
00:09:35.090
I’ll show the object ID. With a few exceptions, the object ID points to a memory location where the data is stored.
00:09:43.450
Next, we’ll attempt to duplicate our Singleton object. Just like before, error messages clarify what happens.
00:09:51.970
Indeed, we can create a second reference so we can see they share the same object ID, confirming there's only one instance.
00:10:03.380
For completeness, we’ll check equality using 'equal?' which should indicate they are the same since they have the same object ID.
00:10:12.700
Now let’s shift back to what Singletons are and what we’ve learned about them.
00:10:22.530
Now moving on to Ruby's Singleton class and its significance. My interest in the Singleton pattern arose during this proposal.
00:10:29.530
Unlike the significant criticism on the internet, I stumbled onto this small module, which seemed to implement a controversial design pattern.
00:10:37.000
The Singleton class is vital to Ruby’s framework as it allows for the encapsulation of instance methods.
00:10:46.000
These classes are accessed via 'singleton_class' calls. One may find it hidden, as it can be accessed fairly easily but doesn’t show up unless you specifically look for it.
00:10:54.240
I find it reminiscent of gravity; while it can’t be seen, it nonetheless has measurable effects!
00:11:02.960
There are fundamental rules regarding Ruby object models. Everything is an object in Ruby.
00:11:13.900
Beginning from the basic 'Object' class, to defined classes, each one inherits the properties of the previous levels.
00:11:22.700
When we include modules in our classes, their hierarchy is adjusted accordingly.
00:11:28.380
Let me illustrate this by utilizing 'ancestors' to visualize how Ruby manages its hierarchy.
00:11:38.320
Here's an example from the class 'ConferenceTalk' to visualize the object model.
00:11:45.720
As reflected in our defined class, the designated 'ConferenceTalk' class also includes an ancestor hierarchy.
00:11:54.380
For example, the 'String' class reveals the same structural hierarchy, with included modules visible to see how inheritance interacts.
00:12:03.460
Next, let’s discuss how the Singleton class can be employed practically.
00:12:11.620
Cats have dominated discussions around technical elements at conferences. Here are my two cats to illustrate the topic.
00:12:19.480
On the left is PK, or Porch Kitty, who meandered her way into my life post-flooding.
00:12:25.800
On the right is Pearl, who is an adapted indoor cat, living an entirely different life!
00:12:31.420
I crafted a basic application that simulates their activities—very little is required to call them into action.
00:12:38.640
As we add attributes and methods, we can see how they interact and how the functionality of each instance holds up.
00:12:47.960
In this instance, Pearl can 'speak' through its instance method, while showcasing the Singleton structure.
00:12:55.400
As I invoke a private method, the message may not clarify why it fails, but the output maintains the integrity of the Singleton.
00:13:02.760
If we try to define additional attributes or methods, the application reveals that behavior distinctly reflects the underlying principles of Singletons.
00:13:10.320
This leads us to further explore how the Singleton class can be modified to include various practices.
00:13:19.360
We can assess capabilities, differentiating methods defined across classes versus instance methods for tailored functionality.
00:13:26.880
This layered structure allows us to dynamically modify and enhance functionality while preserving core implementations.
00:13:33.900
Returning to the thematic notion of cats, the famous Schrödinger's cat illustrates an interesting principle.
00:13:42.860
Schrödinger's cat represents a thought experiment that gets to the heart of observation in quantum mechanics.
00:13:49.700
By confining a cat to a sealed box with a randomly applied peril, it forces an essential questioning of dual states.
00:13:56.790
This analogy is pertinent to private methods and visibility within classes, shedding light on how we perceive things in the Ruby structure.
00:14:05.450
We can further consider how different methodologies affect learning about these singleton approaches.
00:14:12.490
Ultimately, how it relates back to different aspects of programming and applying these methodologies.
00:14:19.850
As we move forward, it's crucial to identify how these modular forms further our understanding of varied programming constructs.
00:14:29.040
We revisit where we started and the significance of Singleton patterns throughout our programming experiences.
00:14:37.660
As this unfolds, our fascination should remain in line with how intricately these patterns exhibit functionality, leveraging structures that persist.
00:14:46.490
Thank you again for spending this time with me and engaging with the journey through Ruby's rich landscape of Singleton strategies.