Feel free to critique. Also see: this and this.
Be both brief and clear. Add nouns to contextualize verbs and prepositions. Prefer removeObject(object, atIndex: index)
over remove(object, at: index)
. Clarity should never suffer from an excess of brevity.
Avoid abbreviations. Prefer printError(myError)
to printErr(myErr)
and setBackgroundImage(myImage)
to setBGImage(myImg)
. Although Apple offers a list of “acceptable” abbreviations, avoid them in Swift outside of gimmes like max and min.
Avoid ambiguity. Consider whether a function or method name has multiple interpretations. For example, in displayName
, is the word display a noun or a verb? If it’s unclear, re-work the name to remove that confusion.
Be consistent. Use the same terms throughout your apps and libraries to describe concepts. Avoid using fetchBezierElements()
in one method and listPathComponents()
in another.
Don’t reference constructs. Avoid struct, enum, class, instance, and object in your names. Prefer buildDeckOfCards()
to buildDeckOfCardsStruct()
.
Use lower-case for method names. Although most developers use lower-case for functions outside a type scope, you can capitalize without committing a moral crime. Uppercase function names immediately differentiate themselves from methods even though they are currently out of fashion. I’ve capitulated for the most part but this may be a battle worth fighting again. This practice was quite common up to and including name-spacing when it suddenly went extinct. It’s like a million capitalized voices cried out and were suddenly silenced
Skip “get”. Functions that retrieve state information should describe the thing they’re returning. Prefer extendedExecutionIsEnabled()
or isExtendedExecutionEnabled()
to getExtendedExecutionIsEnabled()
. Limit get to cases where data is returned through a parameter.
Describe arguments with labels. Encourage reading past the function name to incorporate labels into how the function describes itself. The results create descriptors that incorporate prepositions like with, of, and between. You “construct color with red, green, and blue”, test the “length of string”, or “test equality between x and y”.
A natural fluency relates a function name and its labels to a story about how the function will be used. The result is self-documenting, without relying on memory or look-up to determine which parameters and types are to be provided in each ordered spot. Prefer withTag:
to tag:
.
Use prepositions, avoid “and”. And is the one word that Apple specifically calls out to avoid. Instead of initializing with view and position, use “view, position” arguments.
If you feel you must use and, reserve it to when there’s a semantic link between a group of arguments, such as constructing colors with “red, green, and blue” floating point values. In such cases, it’s unlikely that future keyword tweaks will interrupt the relationship between these items. Even in such cases, purists will disapprove and treat your use as code smell.
The one case where Apple endorses and use is when a method describes two distinct actions, e.g. openFile(withApplication:, andDeactivate:)
.
Use the word value after a type-based label. Prefer toIntValue to toInt, or withCGRectValue to withCGRect.
Use American phrases where standard. Prefer initialize to initialise and color to colour as these words are Apple-supplied.
When in doubt, mimic Apple. Search for an Apple API with a similar concept and use that method signature as a guideline. Be prepare to be inspired by Objective-C. As a rule, not all Apple APIs have been reviewed for Swift. Their automatic translation may not offer sufficiently well-considered examples.
11 Comments
I come from Ruby and C++ rather than Objective-C. I find the pattern of including the first argument’s name in the method name odd. To use one of your examples above…
> removeObject(object, atIndex: index)
Why not this?
> remove(object: object, atIndex: index)
Perhaps a more extreme example would make my point better:
> drawRectangleWithHeight(height andWidth: width)
height and width are peers here. So why does one make it into the name, and the other is buried in the arguments?
> drawRectangle(withHeight: height andWidth: width)
or
> drawRectangle(height: h, width: w)
(apologies for copy-paste — e)
The Swift 2.0 convention that skips the first label mimics Objective-C descriptive signatures that extend beyond the function name to include parameter labels. This 2.0 language version matters as different rules held sway prior to 2.0. The change in convention made label rules apply more consistently across most use cases.
In Swift 2.0, you adapt a function name to incorporate the first parameter label, as you see in the following sample calls.
constructColorWithRed(0.2, green: 0.3, blue:0.1)
lengthOfString(“Hello”)
testEqualityBetweenX(3, andY:3)
Each of these examples encourages you to continue reading past the function name to incorporate labels into how the function describes itself. The results create descriptors that incorporate prepositions like with, of, and between. You “construct color with red, green, and blue”, test the “length of string”, or “test equality between x and y”. A natural fluency relates the function name and its labels to a story about how the function will be used. The result is self-documenting, without relying on memory or look-up to determine which parameters and types are to be provided in each ordered spot.
Without this convention, calls are terser and drop helper words that encourage you to relate parameters to their roles. Here are the same calls in their less fluent form.
constructColor(red:0.2, green: 0.3, blue:0.1)
length(string: “Hello”)
testEquality(x:3, y:3)
removeObject(object, atIndex: index) is a holdover from Objective-C. Putting the name of the first argument outside of the parentheses suggests that it has some greater importance than all other arguments, which should not be assumed. I do not agree with the way Swift is currently handling this, and eagerly await the day that I don’t have to double up the majority of my first parameter names.
remove(object object: Object, at index: Index)
Agreed. It’s concise and yet still keeps the meaning of the func clear
What’s your stance on constant naming? I’ve seen examples mimicking C macros like: let FAHRENHEIT or Hungarian notation: let kFahrenheit. Or even commenting their use in (///) comments (so you can just OPT + click them). So far I’m using just: let fahrenheit. But I can see the appeal of readily identifying constants when far from their declarations.
In Swift, you would mostly use constants anyway (let) so it seems pointless to give them special attention. If you’re asking about Global constants, grouping them in a struct (or enum) is a clean solution but that shouldn’t affect their naming convention
Very nice! Thanks for the Struct tip!
In my opinion, calling
`array.remove(object: someObject, atIndex: 5)` // The object parameter is named
feels cleaner than
`array.removeObject(someObject, atIndex: 5)`
Perhaps the function name should consist of a verb and the parameters should be nouns
I would argue that methods that merely return a state or computed value without any state change or action made (such as I/O, for instance) should be replaced with a computed property instead of a method.
I am referring to the isExtendedExecutionEnabled example.
Also the “get” is useful when meaning/intending to share the raw reference to a mutable object.
Finally… Thanks for your blog.
“Don’t reference constructs.” While I don’t reference objects, structs, enums etc. I do label collections: recipesMArray, peopleDict, shapesTuple, etc. I know this is considered bad style in Cocoa programming, but I really like this convention in my code. Yes I could scroll up to figure out what kind of collection or right click on the variable to see it’s type, but it’s so much easier to read the code without having to worry about what kind of collection a variable is. I also use a bit of Hungarianesque notation for my local variables. I prefix local variables that don’t return with a “t” and those that return with “r.” My internal parameters variables are prefixed with “the.” This makes scope immediate and obvious. It also makes autocompletion easier as well.
I’d be curious to hear why these personal conventions are so terrible from someone I have a lot of respect for and who has a ton of experience reading good/bad code over the years.
As far as naming collections, I think the idea is that your code should be concise and readable enough so that you don’t have to name your array of People “peopleArray”. But then again, to each their own 🙂