Misleading Intuitions: Defining Private Class Methods in Ruby

Beware your gut! It’s only ever right some of the time.

Onel Harrison
The Core

--

Source

After working with a technology for a certain amount of time, we begin to develop a mental model of how we expect things to behave. We begin to feel how we should do things, and many a time these feelings are correct.

In this article, I will highlight an instance of when our intuitions might betray us by examining how private class methods are defined in Ruby. Additionally, I will demonstrate the ways by which Ruby allows us to define private class methods.

Before looking at how we define private class methods, let us revisit how we create public and private instance methods as well as public class methods. Seeing how these are done is necessary for understanding how we might be led to intuit, and consequently write, incorrect code for defining private class methods.

Defining Public and Private Instance Methods

Take this trite code snippet below for example. It shows how we define public and private instance methods and the actual behaviors when we try to use them.

Source: https://gist.github.com/onelharrison/107bf748108d9dbecd02c8aaac1c9536

Defining Public Class Methods

Approach #1: I typically use this approach when I’m defining one or two class methods.

Source: https://gist.github.com/onelharrison/16e1edf55f508d7a0c5ddb8d4653fda5

Approach #2: I use this other approach when it no longer makes sense to use approach #1 — that is, when there are enough class methods to make prepending each one with self a chore.

Source: https://gist.github.com/onelharrison/fbc95c29031b4cc33a74561ca7905d59

Defining Private Class Methods

Let’s say we want to refactor self.name to use a private method that returns the name of the car.

Based on what we know about defining private instance methods and public class methods, our intuitions might lead us to think of two approaches to define private class methods. We are going to look at both of these approaches.

Note: Changing self.name in the way I’ve done below is not good refactoring in practice— in fact, it’s the exact opposite. But, bear with me for the sake of making a point.

Approach #1: This approach combines what we know about defining private instance methods (put the methods below private) and defining public class methods (prepending the method name with self) from approach #1 in the previous section.

Source: https://gist.github.com/onelharrison/4af7e36baa7180637b1e5a43155f08d2

Plot Twist! Although seeming as if it should work, this is not how we define private class methods in Ruby.

Here is a situation where we will not get any warnings or signals that we’ve done something we did not intend to do. If we didn’t check if Toyota.i_am was actually private, we would remain ignorant, possibly until it caused some failure in our software and/or cost us some money.

Approach #2: This approach brings together what we know about defining private instance methods (put the methods below private) and defining public class methods from approach #2 in the previous section.

Source: https://gist.github.com/onelharrison/bc60cf4f0cfb6424bb09186c1a3874ca

There are no surprises here. This works as expected. However, there is a third approach!

Approach #3: The approach shown below is the quick and easy way of tagging a class method as private. It’s done simply by prepending the method definition with a private_class_method method call.

Source: https://gist.github.com/onelharrison/8a12dbf9a91aa7ccf10497a709d4f56d

Defining more than just one or two class methods in this way will quickly get annoying and ugly. You’ll probably see a variation of this approach that’s similar to the code segment below.

Source: https://gist.github.com/onelharrison/c1ae60787c3c5be5fc33365bc436cb4e

The problem with using this second version of approach #3 is that we have to be at the bottom of our class to see which methods are private class methods.

I tend to favor approach #2 for defining both public and private class methods in my day-to-day because of the very obvious separation of class methods from instance methods.

Summary

In this article, we saw an example of how our intuitions might lead us astray using the definition of private class methods in Ruby as our subject. Moreover, we saw the correct ways of defining private class methods and should now be able to choose the approach that best suits our needs.

Source

Remember, our intuitions are only right some of the time.

Special thanks to two of my friends Alston and Brandon for proofreading and giving me their feedback on this article.

If you learned something new or enjoyed reading this article, please clap it up 👏 so that others see it. Feel free to leave a comment too!

--

--