I was pairing with a developer to walk through some code. They had a question regarding the documentation.
I wrote the inline documentation using Yardoc syntax. I previously wrote about The Why and How of Yardoc, which isn’t necessary to read but does highlight how documentation can help the development process.
In the documentation I had the following documentation
# @api public and the sibling
# @api private. Both methods were scoped as public methods.
Let’s setup a concrete example:
class Tesseract # @api public def self.fetch(path:, remote: default_remote) new(path: path, remote: remote) end # @api private def self.default_remote end def initialize(path:, remote:) end end
In the above example, both
Tesseract.default_remote are public class methods. However I have documented
Tesseract.fetch as being part of the public Application Programming Interface (API 📖) and
Tesseract.default_remote as being part of the private API.
What Do I Mean by Interface?
An interface is how you interact with something. A great example is a toaster. There are two common interfaces:
- The Slot for the Bread
- The Lever to Start the Toaster
Both of these are “public” interfaces. This is how you may and should interact with the toaster. Most toaster’s I know have a lever that has a plastic cover; to improve asthetics and not expose the more “primative” metal lever.
In way, that metal lever is the “private” interface. You can use it directly and it’s most certainly “exposed” in a way that you could. But the designers wanted you to interact with the nicely covered lever.
You may use that lever directly but probably should not because that was not quite it’s intention.
To draw this back to programming; a public method that is part of the public interface is intended for you to use. A public method that is part of the private interface is also something you can consider using, but the maintainers of that interface are not committing to maintaining that private interface.
A Quick Explanation of Public and Private Methods
Most programming languages I know have consideration for
private methods. A
public method is one that can be called on the receiver. A
private method is one that may only be called within the context of the receiver.
What’s a receiver? The object from which you’re invoking/calling a function.
Let’s create an example to illustrate:
module Receiver def self.public_method :public_method end def self.private_method :private_method end private_class_method :private_method def self.public_wrapper_for_private_method private_method end end
When I call
Receiver.public_method it returns
:public_method. When I call
Receiver.private_method it raise the following exception with message
private method `private_method' called for Receiver:Module (NoMethodError)
When I call
Receiver.public_wrapper_for_private_method it returns
In other words, outside of the
Receiver module, we cannot directly call
Why Not Privatize Everything?
In an ideal state, perhaps the Venn Diagram of public methods and public interface declarations would be a single circle. However those concepts are not quite overlapping.
The goal of
private method declaration is to programmatically enforce strict rules. The goal of
@api private declaration is to narratively describe how humans can and should interact and implement against it.
Also, in an ideal state, an interface would be very narrow; however to understand the scope/breadth of an interface often requires some degree of using that interface. Only then does it become clearer what should be public versus private.
In other words, and leaping forward in logic, start from a position of private methods and private APIs and gradually move “promote” them for public consumption.
Other Means of “Telegraphing” Privacy
One idiom I have seen is to declare private Application Programming Interface methods with a double underscore (e.g.
Another example, from my current Emacs 📖 fixation, is Denote’s “For Developers and Advanced Users” documentation stating:
By contradistinction, a “private” form is declared with two hyphens in its symbol such as denote–file-extension. Do not use those as we might change them without further notice.
So, keep an eye out for methods that are named contrary to the standard idiom; their naming may indicate an assumption of the maintainers.
This quick foray into
public/private methods versus
public/private API is to help folks understand the differences in interface and function/method visibility.