This is a work in progress from The Pipeline. It will likely change before it is published to the main listing of articles. It is currently at the "outlined" stage.
- Intro: Story of doing interview question “wrong”
- What is the goal of
- To communicate stability. Why?
- To discourage other devs from coupling to implementation details. Why?
- To facilitate refactoring/changes
- How does it achieve its goals?
- It provides feedback via exceptions in repl/TDD
- It acts as documentation you get when reading the code
- It clarifies what is safe to change
- Is it wrong to put consts/class methods under
- Does it achieve the goal?
- It can be easily circumvented—it doesn’t stop other devs accessing internals.
- How useful/valuable are the
- Some people say “anything that is undocumented is private”
- Applies to class methods, attr_reader/writer/accessor, and consts
- show how to actually make those things private
privatemeans “stop reading here” to clients (scissors rule, see sources)
- private methods usually aren’t tested—evidence they are not dependable
- Indenting private emphasises the scissor rule
- Say what the purpose is not
- People will use things if they’re not properly made private
- People might accidentally use quasi-private things without knowing, due to not reading the source file (repl,TDD method guessing, reflection)
- Rubocop is going to complain about it (see sources)
The public parts of a class are the stable parts; the private parts are the changeable parts. When you mark methods as public or private you tell users of your class upon which methods they may safely depend. When your classes use the public methods of others, you trust those methods to be stable. When you decide to depend on the private methods of others, you understand that you are relying on something that is inherently unstable and are thus increasing the risk of being affected by a distant and unrelated change.
Ruby provides three relevant keywords: public, protected, and private. Use of these keywords serves two distinct purposes. First, they indicate which methods are stable and which are unstable. Second, they control how visible a method is to other parts of your application. These two purposes are very different. Conveying information that a method is stable or unstable is one thing; attempting to control how others use it is quite another.
Do your best to interact with other classes using only their public interfaces. Assumethat the authors of those classes were just as intentional as you are now and theyare trying desperately, across time and space, to communicate which methods are dependable. The public/private distinctions they made are intended to help you and it’s best to heed them.
To further complicate matters, Ruby not only provides these keywords but also supplies various mechanisms for circumventing the visibility restrictions that privateand protected impose. Users of a class can redefine any method to public regardless of its initial declaration. The private and protected keywords are more likeflexible barriers than concrete restrictions. Anyone can get by them; it’s simply a matter of expending the effort.Therefore, any notion that you can prevent method access by using these keywordsis an illusion. The keywords don’t deny access, they just make it a bit harder. Usingthem sends two messages:
• You believe that you have better information today than programmers will have inthe future. • You believe that those future programmers need to be prevented from accidentallyusing a method that you currently consider unstable.
These beliefs may be correct but the future is a long way off and one can never be certain.The most apparently stable methods may change regularly and the most initially unstablemay survive the test of time. If the illusion of control is a comfort, feel free to use the keywords. However, many perfectly competent Ruby programmers omit them and insteaduse comments or a special method naming convention (Ruby on Rails, for example, addsa leading ‘_’ to private methods) to indicate the public and private parts of interfaces.These strategies are perfectly acceptable and sometimes even preferable. Theysupply information about method stability without imposing visibility restrictions.Use of them trusts future programmers to make good choices about which methodsto depend upon based on the increased information they have at that time.Regardless of how you choose to do so, as long as you find some way to conveythis information you have fulfilled your obligations to the future.