Private Accessors in Ruby

This is a post about writing private method accessors in Ruby, but it takes me a while to get around to saying that because there’s a ton of backstory, which is of course my favorite part. If you want to skip ahead to the code, I have provided a means of conveyance compatible with your hypermedia information consumption device. (Be warned: you’ll miss the part about the monkey.)

The Principle of Least Access

So there’s this great idea called the Principle of Least Access. It is found in computer science, information security, and other fields. It’s more frequently called the Principle of Least Privilege, but the names are interchangeable and when I learned it POLA was an acronym you could pronounce.

Yeah, that’s exactly the kind of motivation that I would choose to make a design decision over. There’s a reason POODR is my favorite book of all time, and “pronounceable acronym” is reason number two. You can guess what reason number one is. (Hint: It’s also number two).

Anyway, POLA can be summed up nicely as

A thing must be able to access only the information and resources that are necessary for its legitimate purpose.

In programming, this rule is often misquoted as simply “make everything private until something else needs it”. This isn’t a bad rule of thumb, but it’s not a great one, and at first blush it really puts private methods at odds with testing code.

But Testing Private Methods is Haaaaaard!

My relationship with POLA has been rocky. I used to think it was scripture. Then I thought it was idiotic. Then I came to ruby where everything is either public or can be accessed anyway. We even had a splendid bout of drama in the ruby community over whether or not you should test private methods. I fought bravely on the side of “yes you should”, even going so far as to write some code with a humorous name to make it easier to test those private methods.

The two tenets of my argument were that

  1. You should test things that can break. If you’re going to put really complicated logic in private methods in your code, then they can break and you should test them, and
  2. Testing private methods through the public interface adds impedance to the testing process, and results in low-value tests that are very hard to construct.

But you know what’s really funny? When I really got into it with a bunch of people, even the people furiously certain that their stance on testing private methods was correct, I found out something crying out loud funny:

Ruby programmers don’t write private methods.

Test ‘Em? Let’s Not Even Write ‘Em

For the most part, we just… don’t. We know that a determined user can get at our guts, so we make no pretense of security or safety in marking something protected or private. If we’re having a good design day, we extract the private functionality to a class. If we’re having a bad design day, we shrug and say “Eh” and just leave everything public. The important thing is, when we came in from C++ or Java, we had to check at the door this notion that our encapsulation would protect us, and for most of us that was the whole point of private methods to begin with.

I watched Sandi Metz talk about creating high-value tests a while ago, and she talks about private methods–and about testing them. Her take was that private methods are a good place to put code that is uncertain or subject to change on a whim; that way no external code would be affected. Since the code is so volatile, any tests that touch it will break often, so if the purpose of a test is to provide lasting reassurance, it doesn’t make sense to test them.

One of the reason I love Sandi so much is that she gets the concept that everything is a tradeoff. When she was on Ruby Rogues I asked her about the case where I sometimes will use tests to figure out complicated code. I’ll inch forward bit by bit, and lock each bit down with a short-term test. She considered this for a long moment, and then announced her new rule for testing private methods:

“Don’t test private methods unless you really need to. In which case, test them as much as you want.” –Sandi Metz

And THAT, dear readers, is how I found myself poring through POODR and pondering the fact that keeping everything public is a very, very bad idea.

Making Everything Public Is Killing Us

Every public method, variable and accessor on a class is a message that can be fired at that object from anywhere in the system. I know this will seem strange to some rubyists, but we really have to get away from this notion of making everything public–or, at least, making things public that other objects have no business knowing about. Let’s quote Sandi again:

Each [object in a hard-to-maintain system] exposes too much of itself and knows too much about its neighbors. This excess knowledge results in objects that are finely, explicitly, and disastrously tuned to do only the things that they do right now…

The roots of this new problem lie not in what each class does but in what it reveals. –Sandi Metz (emphasis hers)

The more I read the more I realize that each object has a sort of “surface area”, which is its public interface, where it can be interacted with. I’m used to referring to applications with too many dependencies as “monolithic”, literally meaning “one piece of stone”. This word makes me think of how all the dependencies in the system are interlocked and hard (as stone) to break apart. But Sandi has an even better metaphor: She draws this little picture of all these objects, and then she connects them with a kitten’s ball of yarn. Instead of talking about interlocking dependencies, she starts talking about the messages going back and forth, shooting all around the system. Viewing the system as an uncontrolled net of messages, Sandi pulls out an even better word: a woven mat.

So… okay. I’m convinced. It’s time to reduce the surface area of my classes. It’s time to start writing private and protected methods. More importantly, it’s time to start writing private accessors.

Okay, But There’s a Secret Reason I’ve Hated POLA All These Years

There’s a cost to the Principle of Least Access, however. It is simply this: if you start out making everything private, and then find out you need to make something public, there’s a refactoring cost. It’s not big, but it’s there, and it’s one of the kinds of hassle that I am very finely tuned to sniff out. I have literally spent 5 years learning how to design applications to not need private methods rather than writing them.

It’s not that you can’t do it. Here’s what it looks like in ruby:

class Monkey
  private
  attr_accessor :poo_count
  public

  def need_to_reload?
    poo_count < 1
  end

  def throw! victim
    self.poo_count -= 1
    victim.horrify
    onlookers.each {|onlooker| onlooker.amuse! }
    reload! if need_to_reload?
  end
end

Look at those first three lines inside Monkey. YUCK! Either we need to change ruby itself, or Sandi’s book needs to stop being so awesome.

(Admit it, I had you at “change ruby itself”, didn’t I.)

Adding Private Accessors to Ruby

As I write this blog post, I am dumbfounded that nobody else has done this already. What I’m about to show you is so obvious that I am convinced that it is proof that we as rubyists just don’t care much for private methods and accessors. Because this turns out to not be so hard at all:

module PrivateAttrAccessor
  def private_attr_accessor(*names)
    private
    attr_accessor *names
  end
end

class Monkey
  extend PrivateAttrAccessor
  private_attr_accessor :poo_count

  # ... rest of code unchanged
end

Also, if we’re willing to commit to using private and protected accessors, then we can move that call to extend PrivateAttrAccessor up into the Object class and now Monkey just looks like this:

class Monkey
  private_attr_accessor :poo_count

  # ... rest of code still hilarious
end

BAM. There you go. No, wait… HERE you go. That’s the full set of scoped accessors (protected_attr_reader, private_attr_writer, etc) ready to go. The file is 20 lines of documentation, 38 lines of code, and about 290 lines of test code. This feels like about the right ratio of code to test for code that is designed to be stabbed right into the very heart of ruby’s object system. If you are running ruby 2 (and if not, what is wrong with you?) you can just run the file and MiniTest will autorun and test the module. If you are running an out-of-date Ruby, such as 1.9.3, you can still run the file, just make sure you gem install minitest first.

I only had one real concern as I wrote that module: Inside the class, I am declaring everything in public scope, but inside the private accessor method, I tell ruby to use private scope. Would ruby stay stuck in private scope when it returned, or would the scope reset back to public?

Answer: It resets!

Sorry, sorry, that was pretty anticlimactic. I should have said something super profound about ruby’s access scoping and how it interacts with ruby’s lexical scope handling, but the short answer is I have no clue and the even better answer is I don’t need to have one. Rather than pick the ruby source code apart, I just wrote some unit tests specifically to ensure that the scope remains unchanged, and it does.

Give those scoped accessors a whirl and let me know what you think. If you just type ruby scoped_attr_accessor.rb minitest will execute its test suite. Or you can require the file in your project and it will quietly patch Object and you’re all set.

I haven’t touched the deep-downs of ruby with a monkeypatch in literally hours, so I’m unsure if this idea is awesome or just terrible. What do you think? Should I publish this as a gem or should I delete it, burn my laptop, and exile myself to Tibet? Update: I chose the non-Tibetan-exile option. Type gem install scoped_attr_accessor or get the source code here.

11 thoughts on “Private Accessors in Ruby

  1. pierodibello

    Hi David,
    I always applied the Principle of Least Access when designing my objects (be they java or ruby objects) for all the good reasons you described.

    I don’t understand why you say that there’s a refactoring cost when making some private method public. While the contrary is quite true (making public methods private means you have to check whether some other objects is still calling that method on your public interface), promoting a private method to the object’s public interface should be safe. Shouldn’t it?

    Thanks!

    Reply
    1. David Brady Post author

      Oh! Yes. Externally, it’s quite safe. I meant literally the hassle of editing the file, say from

      attr_accessor :pigtruck
      private :pigtruck

      or

      private
      attr_accessor :pigtruck # Note don't do this it raises a warning
      public

      to the simpler form:

      attr_accessor :pigtruck

      I’ve also encountered the occasional refactoring cost where I’ve built a bypass of some kind into the public API, and now the direct access to the attribute makes the bypass cruft which should be removed–and that you DO have to check for to make sure it’s not being used, etc.

      I can see there’s a LOT more meat on this bone than I thought when I wrote this post; look for a followup (or two… or three) sometime after this weekend. I’m up to my eyeballs in way over my head trying to get a talk written for Open West this Thursday.

      Thanks for the comment! Cheers!

      Reply
    2. David Brady Post author

      Oh, I should also say that when I first got headaches from POLA it was in languages that didn’t have accessors. So that simple refactoring was more like going from

      private int m_iCount;

      to something like

      private int m_iCount;

      public int getCount() { return m_iCount; }
      public void setCount(int newCount) { m_iCount = newCount; }

      I just threw in the hungarian notation to point out that EVERYTHING was bad back in those days, but yeah–this predated people thinking it might be a good idea to teach their IDEs to add accessor methods automatically, etc.

      Again, it’s a small cost–tiny, really–but it’s one of a class of hassles (daily, repetitive microannoyances) to which I am finely attuned. 🙂

      Reply
  2. pierodibello

    I spent several years programming java, so I see your point.
    BTW, my habit to follow POLA is not an academic or theoretical, but it flows naturally from applying TDD: test after test, you design your objects and their API. As you know, it’s totally natural with this technique to have a narrow public interface, and every public method exists because a test described the need for that method. Everything else is kept private.

    Reply
  3. Declan Whelan

    Hey David,

    I am relatively new to Ruby and ascribe to POLA because of my C# and Java work. Actually, I consider it more in the light of information hiding (http://en.wikipedia.org/wiki/Information_hiding) a la David Parnas – gotta say that because he’s a fellow Canadian :).

    Anyway, what I have been doing is just moving the private declaration to the bottom of the file so all private accessors and methods are together. I like this because the public stuff is at the top and the private is of less interest so you need to look down to see it. The drawback of course if that the accessors are now in two places.

    I am interested in your thoughts on that.

    Cheers,

    Declan

    Reply
    1. dbrady Post author

      Hi Declan!

      I’m a huge fan of information hiding, especially to prevent changes from rippling through code. The gotcha to remember with Ruby is that Ruby’s openness means that all we can really do is put up a handrail and ask people not to look past it. 🙂 As long as you keep that dynamic in mind, and aren’t holding on to a C#/Java spirit of “private means inaccessible to outsiders” then you’re fine.

      I think your method of splitting classes with private methods at the bottom is a best practice. I do a similar thing, and have seen lots of folks do likewise. There seems to be an unwritten rule in Ruby that you never declare a section private and then declare a later section to be public again.

      Once you have a private declaration, attr_accessor makes as much sense as private_attr_accessor, to be honest; I’m not sure the tradeoff is worth the extra verbiage. That said, if I had no private methods but did want to create a few private accessors, I personally would declare them at the top with the other accessors, perhaps at the end of the list. That may entirely be a matter a preference, however: the message I’d be trying to communicate is “hey, you’re going to see this function accessed throughout this class; it’s this private accessor, everything’s cool. Don’t worry about it.”

      I think ending a class with no private declaration but a list of private_attr_* declarations would look weird… but I do like your notion of “look down for private stuff” so weird isn’t necessarily bad. In fact it might actually be “good weird” as it does send a clear demarcation message. I think I’m trying to deliberately blur the lines between public and private accessors here, and show that things of such tiny consequence should look inconsequential on the page. Moving them to the bottom creates a sort of special “place of honor” for them in my mind, and I’m not sure if that’s good or bad–or both, depending on whether or not I wanted to signal that intent to the reader. I guess the only thing I would say for sure is don’t do BOTH in the same project, or at least not in the same file…. 🙂

      Reply
  4. Declan Whelan

    David,

    Thanks for your thoughts – I appreciate your detailed response. And I agree with it all. I wish I didn’t though so I could provide some dbrady cutting response. Love listening to you on Ruby Rogues!

    Declan

    Reply
    1. dbrady Post author

      Fair enough; I wrote this post assuming the value of this approach was already bought. 🙂

      However, there’s an old consulting proverb: anytime someone uses the word “Just”, beware: they are singing you a lullaby.

      Just using instance variables certainly works, but it has a few tradeoffs, and to be honest those tradeoffs annoy me enough that I avoid them wherever possible. First, if you decide to refactor an instance variable to a getter method, it’s a pain. Extracting a method can be tricky if you are tightly coupled to instance implementation, and extracting a class–where instance implementation cannot be carried over transparently–becomes agonizing. Giving your class a “private API” into its own state makes it MUCH easier to handle these refactorings. Second, inside a class, the rule of “depend on things that change less than you do” is one of the single most valuable principles for designing classes that can be easily maintained, modified, and refactored. Accessor methods are a fantastic way to isolate a class’ behavior from its own state, which typically changes much more often than the behavior of the class itself. There are other reasons, but those two come immediately to my mind and have proven very valuable to me over the years.

      Your mileage may vary, of course, and I respect that. If that’s not enough to sell you on this approach, check out Sandi Metz’ “Practical Object-Oriented Development in Ruby”, which lays out a much stronger case for classes not implicitly depending on their own internal state. She’s a lot smarter than me. 🙂

      Personally, I only use instance vars in constructors and when caching the return value from an instance method. Once in a blue moon I’ll use one for performance reasons, but usually only when I have e.g. a very tight loop that’s spending all of its time calling the accessor method, and the entire program is measurably too slow and needs to be sped up. (E.g. I might use one in a script to find prime factors or calculate fibonacci numbers, etc, where I’m doing a very tight grindy inner loop.) That’s where I was coming from when I wrote this post: I write accessor methods for ALL of my internal state, and this had the tradeoff of pushing my ivars out to the public API of the class, which is clearly an unacceptable tradeoff in the other direction. Streamlining private accessor methods is a way of having my cake and eating it too–but only via the private eat_cake accessor method, of course. 😉

      Thanks for your comment, and if I haven’t persuaded you… well, I hope I’ve at least given you food for thought. 🙂 Cheers!

      Reply
      1. Nathan Ladd (@realntl)

        Thanks for the response!

        Regarding refactoring, I regard turning an ivar into an accessor as a pretty easy tooling problem to solve. I’ve been using ivars to encapsulate state for a few weeks now, and I’ve hit this refactoring a few times, and it’s never been painful.

        Accessors are nice because they are referenced via messages; you can have behavior *or* state behind them. But private methods are usually a suboptimal way to shield behavior from the outside world. Generally, a class with a public API and a private API is operating at two layers of abstraction. I find that I can usually find a better home for private methods where they live as first class citizens of a new object *behind* my public API.

        I’ve definitely read POODR, it’s a good book. I agree with Sandi Metz (and you) about hiding as much as possible from the outside world. However, I am also a fan of dependency inversion, which means usually my accessors are *designed* to be utilized by the consuming object. When I need internal state that I don’t expose to the outside world, instance variables are generally a great tool for the job.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s