Software Craftsmanship
Naming Conventions
September 19, 2016
If you can't come up with a good name for it, then it's a mess. The names are the API talking back to you, so listen to them.
- Guy Steele
Software development requires a huge amount of memorization. Consistent naming conventions reduce the 'conceptual weight' of an API making everyone's day to day work a lot easier.
https://swift.org/documentation/api-design-guidelines/#promote-clear-usage
Clarity at the point of use is your most important goal. Entities such as methods and properties are declared only once but used repeatedly. Design APIs to make those uses clear and concise. When evaluating a design, reading a declaration is seldom sufficient; always examine a use case to make sure it looks clear in context.
Clarity is more important than brevity. Although Swift code can be compact, it is a non-goal to enable the smallest possible code with the fewest characters. Brevity in Swift code, where it occurs, is a side-effect of the strong type system and features that naturally reduce boilerplate.
Include all the words needed to avoid ambiguity for a person reading code where the name is used.
Omit needless words. Every word in a name should convey salient information at the use site.
Name variables, parameters, and associated types according to their roles, rather than their type constraints.
Include all the words needed to avoid ambiguity for a person reading code where the name is used.
employees.remove(at: x)
// :(
employees.remove(x)
// unclear:
// are we removing x or are we removing at?
// :)
extension List {
public mutating func remove(at position: Index) -> Element
}Omit needless words. Every word in a name should convey salient information at the use site.
//Bad :(
public mutating func removeElement(member: Element) -> Element?
allViews.removeElement(cancelButton)
//Good :)
public mutating func remove(member: Element) -> Element?
allViews.remove(cancelButton) // clearerName variables, parameters, and associated types according to their roles, rather than their type constraints.
// :(
protocol ViewController {
//Everyone knows what a view is. Describe what kind of view.
associatedtype ViewType : View
}
// :)
protocol ViewController {
associatedtype CircularSliderView : View
}Prefer method and function names that form grammatical English phrases.
// :(
x.insert(y, position: z)
x.subViews(color: y)
x.nounCapitalize()
// :)
x.insert(y, at: z) // x, insert y at z
x.subViews(havingColor: y) // x's subviews having color y
x.capitalizingNouns() // x, capitalizing nounsName functions and methods according to their side-effects
Use the “ed/ing” rule to name the non mutating counterpart of a mutating method
x.sort()
x.sorted()
x.append(y)
x.appending(y)
x.stripNewlines()
x.strippingNewlines()
// In each case
// The example alters the original.
// The original doesn't change. Instead it returns an altered copy. These conventions allow you to know exactly what a method is doing without reading any source code or documentation and requires minimal memorization.
Don't surprise your readers. Consistent and obvious patterns throughout the code base make development easier for both beginner and expert developers.
Only overload methods when they have the same basic meaning.
extension Shape {
/// Returns `true` iff `other` is within the area of `self`.
func contains(other: Point) -> Bool { ... }
/// Returns `true` iff `other` is entirely within the area of `self`.
func contains(other: Shape) -> Bool { ... }
/// Returns `true` iff `other` is within the area of `self`.
func contains(other: LineSegment) -> Bool { ... }
}
extension Database {
/// Rebuilds the database's search index
func index() { ... }
/// Returns the `n`th row in the given table.
func index(n: Int, inTable: TableID) -> TableRow { ... }
}
extension Box {
/// Returns the `Int` stored in `self`, if any, and
/// `nil` otherwise.
func value() -> Int? { ... }
/// Returns the `String` stored in `self`, if any, and
/// `nil` otherwise.
func value() -> String? { ... }
}What not to do...
Reveal Intention
int d; // elapsed time in days
int daysSinceCreation;Avoid disinformation
Account[] accountList;
boolean notActive;
Make meaningful distinctions
void arrayCopy(char[] a1, char[] a2);
void arrayCopy(char[] source, char[] destination);Pronounceable
String evtStCd, evtAudtg;Searchable
Date date, transactionDate;
public class RequestBuilder { ...Solution/Problem relevant
int tableUsage, loadFactor;
Node tortoise, hare;"Programs must be written for people to read and only incidentally for machines to execute" - Hal Abelson
The best solution is to write easily comprehensible code.
Code can't explain why the program is being written, and the rationale for choosing this or that method. Code cannot discuss reasons certain alternative approaches were taken.
Comments are best used to provide contextual information that makes it easier to understand the code.
Single line comments are usually unnecessary and should only be used if the operation is complex.
j = j + 1; //Increment j
int a = c * 100; //convert to cents
double avg = a / n; //average cents per customer
int totalCents = totalDollars * 100;
double averageCentsPerCustomer = totalCents / customerCount;Instead of writing comments that are designed to make code more readable, rewrite the code.
BAD
GOOD
Do not release with TODOs or commented-out code
https://google-styleguide.googlecode.com/svn/trunk/javaguide.html
http://lars-lab.jpl.nasa.gov/JPL_Coding_Standard_Java.pdf
Common rules:
Follow team and company rules