Now that we've covered variables, let's move on to functions. Good function names allow a developer to confidently call an interface without having to look at the implementation. Let's start with a concise definition of a good function name:
Function names are implicit subject, short sentences which specify every result of their execution.
Implicit subject
The term comes from traditional writing, where you can substitute a name, like Ibram, with a pronoun such as, He. You can also substitute the name with no pronoun at all in rare cases.
In programming, the caller is always the subject of our function name. Because of this, it is best to leave off the pronoun altogether. We shouldn't try to anticipate who the caller will be in our naming conventions.
This leaves us with sentences which always start with a verb.
SendMessages(Message[] messages);
GetSalesOrder(Guid salesOrderId);
TransformToShipment(UserSubmittedShipment userInput);
Verb rules
The action in your function name should specify the direction of the function and use active voice.
Specify direction
There are two directions in programming:
← Getting something
→ Changing something
Direction is important because the developer needs to understand what will happen when they call the method. With ambiguity in direction, the developer has to look at the implementation to find out if it's the appropriate method to call. This slows down the developer significantly.
Let's take an ambiguous name and specify direction.
// Is this rendering the frame to the screen or is it grabbing a frame and returning it to the caller?
RenderFrame(FrameFragment[] fragments);
// Let's use more specific verbs to specify direction.
GetFrame(FrameFragment[] fragments); // ←
ShowFrame(FrameFragment[] fragments); // →
Always consider whether your verb is "unidirectional." That is, whether the name specifies that it gets something or changes something, but not both. The verb should always be unidirectional even if the function is bidirectional.
Bidirectional functions
It is ok for your function to change something and then return something about what has changed. In this case, you should use a "changing something" verb and use the function signature + documentation to explain what the function returns. For instance,
// Obviously returns nothing.
void SaveOrder(Order order); // →
// Returns the order's Id. This will need to be documented in whatever way your language specifies.
Guid SaveOrder(Order order); // ←→
These functions clearly state that they change something. Then they use documentation to talk about what gets returned. This alerts the developer to the dangerous aspects of the function and allows them to either discard the returned information or glance at the documentation if they care.
Do not confuse return parameters with status codes. Throw exceptions for exceptional cases in whatever way your language specifies.
Using Active voice
While it is a common practice to use passive voice for function names, this changes the subject of the sentence from caller to object and leaves ambiguity between whether your function is a function or a variable.
You may remember in the exploration of variable naming, that boolean variables specify their type with prefixes such as, "is," "has," or "can." When a developer uses passive voice in function naming, they wind up with the same name. This is especially troublesome in interpreted languages like JavaScript or Python where the developer won't know about the error until runtime.
It feels a bit clunky, but if the developer puts "Get" in front of their function names which return booleans, they clearly mark their function as a function. Here are some examples:
// JavaScript
// how do you know whether this is a function or variable without looking at the implementation?
person.isOfAge();
person.isOfAge;
// Ahhh... I know which one is which.
person.isOfAge();
person.getIsOfAge();
Specify every result
I like this portion of our definition because it allows developers freedom for side effects if that's the style of code base they're working in. However, every effect and side effect must be documented in the name of the function.
This rule allows us to understand everything which will change as a result of calling the function. It also gives us an immediate code smell if the function is doing too much.
Let's take a short example:
int GetBirthdayAndTransformTags(Person birthdayPerson, Guest[] guests, Tag[] tags);
Yes, this is obviously a confusing name, and obviously the function is doing too much. Isn't it wonderful that we can tell that before we've looked at the implementation?
After the verb
Naming a function "Get();" with no context is not useful. What is being gotten?
The portion of the name after the verb gives enough context to the function that a developer won't have to look at the implementation to understand what happens as a result of the call.
Here are some examples:
ValidateOrder(Order order);
CreateOrder(Order order);
GetWeightInKilograms(int weightInGrams);
In class-based languages, functions can sometimes get away without additional context. This depends on whether the class is specific enough to lend its context to the function. When in doubt, specify the context again.
Here are some examples:
OrderValidator.Validate(Order order);
ShipmentCreator.Create(Shipment shipment);
Where to go from here
Memorize the sentence:
Function names are implicit subject, short sentences which specify every result of their execution.
and name your functions accordingly.
If you haven't already, check out my post on Variable Etymology.
If you see anything which could be improved about this post, let me know. This is going to be a section in my book on code quality, so I would appreciate feedback.
Top comments (1)
Thank you for this ❤