본문 바로가기
🍎 iOS/문서읽기

[iOS] 변수명, 어떻게 지을까? - API Design Guideline(2)

by @Eddy 2023. 3. 28.
728x90

Naming

Promote Clear Usage ( 명확한 사용을 추구해라. )

1. 코드를 읽는 사람을 위해 의미가 모호하지 않도록 필요한 모든 단어를 포함시켜라.

Include all the words needed to avoid ambiguity for a person reading code where the name is used.

For example, consider a method that removes the element at a given position within a collection.

/// - Note: 좋은 예

extension List {
  public mutating func remove(at position: Index) -> Element
}
employees.remove(at: x)


예시처럼, at이라는 단어를 생략한다면 코드를 읽는 사람에게 method가 제거할 요소의 위치를 나타내기 위해 x를 사용하는 게 아닌, x를 검색하거나 제거한다고 이해할지도 모른다.
If we were to omit the word at from the method signature, it could imply to the reader that the method searches for and removes an element equal to x, rather than using x to indicate the position of the element to remove.

/// - Note: 나쁜 예

employees.remove(x) // unclear: are we removing x?

 

2. 불필요한 단어는 생략해라. 

Omit needless words. Every word in a name should convey salient information at the use site.

의미를 명확히 하거나, 모호하지 않도록 더 많은 단어를 사용할 수는 있지만, 이미 알고 있는 정보나 중복되는 단어는 생략되어야 한다. 특히, 단순히 type정보를 반복하는 단어는 생략한다.
More words may be needed to clarify intent or disambiguate meaning, but those that are redundant with information the reader already possesses should be omitted. In particular, omit words that merely repeat type information.

/// - Note: 나쁜 예

public mutating func removeElement(_ member: Element) -> Element?

allViews.removeElement(cancelButton)

 

위의 경우 removeElement() 이름의 'Element'를 호출지점에서 알려줄 필요가 없기에 아래의 API가 낫다.
In this case, the word Element adds nothing salient at the call site. This API would be better:

/// - Note: 좋은 예

public mutating func remove(_ member: Element) -> Element?

allViews.remove(cancelButton) // clearer


가끔 모호성을 피하기 위해 type정보 반복이필요할 수 있지만, 일반적으로 type보다 parameter의 역할을 설명하는 단어를 사용하는 게 좋다.

Occasionally, repeating type information is necessary to avoid ambiguity, but in general it is better to use a word that describes a parameter’s role rather than its type. See the next item for details.

 

3. 변수, 매개변수 및 관련 타입의 이름은 type constraints보다 그 역할에 맞게 작성해라.

Name variables, parameters, and associated types according to their roles, rather than their type constraints.

/// - Note: 나쁜 예

var string = "Hello"
protocol ViewController {
  associatedtype ViewType : View
}
class ProductionLine {
  func restock(from widgetFactory: WidgetFactory)
}

위 방식의 type 이름은 명확성과 표현성을 최적화할 수 없으니, Entity의 역할을 표현하는 이름을 사용하도록 노력해라.
Repurposing a type name in this way fails to optimize clarity and expressivity. Instead, strive to choose a name that expresses the entity’s role.


/// - Note: 좋은 예

var greeting = "Hello"
protocol ViewController {
  associatedtype ContentView : View
}
class ProductionLine {
  func restock(from supplier: WidgetFactory)
}

연관 type이 protocol 이름이 곧 역할인 protocol constraint에 엄격하게 연결되어 있다면, protocol 이름에 Protocol을 추가해 충돌을 피해라.
If an associated type is so tightly bound to its protocol constraint that the protocol name is the role, avoid collision by appending Protocol to the protocol name:

 

4. 매개변수 역할을 명확히 하기 위해 weak type 정보를 보완해라.

Compensate for weak type information to clarify a parameter’s role.

매개변수 유형이 NSObject, Any, AnyObject이거나 Int, String같은 기본 type일 때, 사용 시점의 type 정보와 context가 의도를 온전히 전달하지 못할 수 있다.
Especially when a parameter type is NSObject, Any, AnyObject, or a fundamental type such as Int or String, type information and context at the point of use may not fully convey intent. In this example, the declaration may be clear, but the use site is vague.

/// - Note: 나쁜 예

func add(_ observer: NSObject, for keyPath: String)

grid.add(self, for: graphics) // vague

명확성을 위해 역할을 설명하는 명사를 추가할 수 있다.
To restore clarity, precede each weakly typed parameter with a noun describing its role:

/// - Note: 좋은 예

func addObserver(_ observer: NSObject, forKeyPath path: String)
grid.addObserver(self, forKeyPath: graphics) // clear

 

 

Strive for Fluent Usage (유연한 사용을 위해 노력해라.)

1. 영어 문법에 맞게 Method와 Function 이름 작성헤라. ( 영어식 표현으로 자연스럽게 작성해라. )

Prefer method and function names that make use sites form grammatical English phrases

/// - Note: 좋은 예

x.insert(y, at: z)          “x, insert y at z”
x.subViews(havingColor: y)  “x's subviews having color y”
x.capitalizingNouns()       “x, capitalizing nouns”
/// - Note: 나쁜 예

x.insert(y, position: z)
x.subViews(color: y)
x.nounCapitalize()

일부 Argument가 의미적으로(to the call's meaning) 핵심이 아닐 땐, 조금 부자연스러워도 괜찮다.
It is acceptable for fluency to degrade after the first argument or two when those arguments are not central to the call’s meaning:

AudioUnit.instantiate(
  with: description,
  options: [.inProcess], completionHandler: stopProgressBar)

 

2. Factory method의 이름은 "make"로 시작해라. ex) x.makeIterator().

Begin names of factory methods with “make”, e.g. x.makeIterator().

 

3. Initializer와 Factory methods calls의 인수를 어구(a phrase)로 작성하면 안 된다.

The first argument to initializer and factory methods calls should not form a phrase starting with the base name, e.g. x.makeWidget(cogCount: 47)

For example, the first arguments to these calls do not read as part of the same phrase as the base name:

/// - Note: 좋은 예

let foreground = Color(red: 32, green: 64, blue: 128)
let newPart = factory.makeWidget(gears: 42, spindles: 14)
let ref = Link(target: destination)

아래는, 인수를 사용해 문법적 연속성을 만들려고 한 예시이다.
In the following, the API author has tried to create grammatical continuity with the first argument.

/// - Note: 나쁜 예

let foreground = Color(havingRGBValuesRed: 32, green: 64, andBlue: 128)
let newPart = factory.makeWidget(havingGearCount: 42, andSpindleCount: 14)
let ref = Link(to: destination)


실제로, argument labels에 대한 가이드라인과 함께 이 가이드라인은 호출이(the call) value preserving type conversion을 수행하지 않는다면, 첫번째 arguments가 label을 가질 거라는 것을 의미한다.
단순히 말해, Color는 argument에 red, green, blue만 작성해도 무엇이 필요한지 이해가 되니, red도 필요하고, green도 필요하고, blue도 필요해요. 처럼 구구절절 설명하지 말라는 의미.
( value preserving type conversion은 아래에서 설명. )

In practice, this guideline along with those for argument labels means the first argument will have a label unless the call is performing a value preserving type conversion.

 

4. Side-effect에 따라 Function과 method의 이름을 정해라.

Name functions and methods according to their side-effects

Side-effect가 없으면, 명사 구문으로 읽어야한다. ex) x.distance(to: y), i.successor().
Those without side-effects should read as noun phrases, e.g. x.distance(to: y), i.successor().

Side-effect가 있다면, 명령형 동사 구문으로 읽어야한다. ex) print(x), x.sort(), x.append(y).
Those with side-effects should read as imperative verb phrases, e.g., print(x), x.sort(), x.append(y).

가변적/비가변적인 method pairs는 일관되게 이름지어야한다. 종종 가변 method는 비가번젹언 변수와 비슷한 의미를 가지기도 하지만, 자기자신의 값이 변경되기보다 새 값을 반환하는 차이가 있다.
Name Mutating/nonmutating method pairs consistently. A mutating method will often have a nonmutating variant with similar semantics, but that returns a new value rather than updating an instance in-place.

Operation이 자연스럽게 동사로 설명되면, 가변 method에 대해 동사의 명령형을 사용하고, ed 또는 -ing를 접미에 붙여 비가변 변수의 이름에 적용해라.
When the operation is naturally described by a verb, use the verb’s imperative for the mutating method and apply the “ed” or “ing” suffix to name its nonmutating counterpart.

Mutating Nonmutating
x.sort() z = x.sorted()
x.append(y) z = x.appending(y)

비가변변수는 과거분사(일반적으로 -ed) 사용을 지향해라.
Prefer to name the nonmutating variant using the verb’s past participle (usually appending “ed”):

/// Reverses `self` in-place.
mutating func reverse()

/// Returns a reversed copy of `self`.
func reversed() -> Self
...
x.reverse()
let y = x.reversed()

 

문법적으로 동사가 목적어를 가져야해서 과거분사 사용어 어렵다면, 비가변변수에 동사의 현재분사형(-ing) 이름을 사용해라.
When adding “ed” is not grammatical because the verb has a direct object, name the nonmutating variant using the verb’s present participle, by appending “ing.”

/// Strips all the newlines from `self`
mutating func stripNewlines()

/// Returns a copy of `self` with all the newlines stripped.
func strippingNewlines() -> String
...
s.stripNewlines()
let oneLine = t.strippingNewlines()

 

Operation이 자연스럽게 명사로 설명되어진다면, 비가변변수 method를 명사를 사용하고 가변변수의 접두에 form를 사용해라.
When the operation is naturally described by a noun, use the noun for the nonmutating method and apply the “form” prefix to name its mutating counterpart.

NonMutating Mutating
x = y.union(z) y.formUnion(z)
j = c.successor(i) c.formSuccessor(&i)

 

 

5. Boolean method와 property 사용은 사용이 비가변일 때, 대상(receiver)에 대한 주장(assertion)으로 읽혀야 한다.

ex) x.isEmpty, line1.intersects(line2).

Uses of Boolean methods and properties should read as assertions about the receiver when the use is nonmutating, e.g. x.isEmpty, line1.intersects(line2).

 

6. 어떤게 뭔지 설명하는 Protocol들은 명사로 읽혀야 한다. ex) Collection

Protocols that describe what something is should read as nouns (e.g. Collection).

 

7. 기능을 설명하는 Protocol들은 접미에 able, ible, 또는 ing를 사용해야 한다. ex) Equatable, ProgressReporting

Protocols that describe a capability should be named using the suffixes able, ible, or ing (e.g. Equatable, ProgressReporting).

 

8.  그 외 Type, property, variable, constants는 명사로 읽혀야 한다.

The names of other types, properties, variables, and constants should read as nouns.

 

 

User Terminology Well

1. 일반적인 단어로 충분한 의미전달이 가능하다면, 모호한 용어는 피해라. ex) '표피'보단 '피부'

Avoid obscure terms if a more common word conveys meaning just as well. Don’t say “epidermis” if “skin” will serve your purpose. Terms of art are an essential communication tool, but should only be used to capture crucial meaning that would otherwise be lost.

 

2. 전문용어를 사용할거라면, 본질적인 의미에 집중해라.

Stick to the established meaning if you do use a term of art.

  • 일반적인 단어가 아닌, 전문 용어를 사용하는 이뉴는 모호하거나 불분명할 수 있는 내용을 정확하게 표현하기 위해서다. 따라서 API는 허용되는 의미에 맞게 용어 사용을 엄격하게 해야 한다.
  • The only reason to use a technical term rather than a more common word is that it precisely expresses something that would otherwise be ambiguous or unclear. Therefore, an API should use the term strictly in accordance with its accepted meaning.
    • 전문가가 사용하지 않는 단어를 사용하지 마라. 
    • Don’t surprise an expert: anyone already familiar with the term will be surprised and probably angered if we appear to have invented a new meaning for it.
    • 초심자가 이해할 수 있는 용어를 사용해라. 이해를 위해 의미를 찾게 만들지 마라.
    • Don’t confuse a beginner: anyone trying to learn the term is likely to do a web search and find its traditional meaning.

3. 약어나 준말은지양해라. 특히 비표준 약어는 줄임말이 아닌 형태로 정확하게 번역해야하므로 실질적 전문용어이다.

Avoid abbreviations. Abbreviations, especially non-standard ones, are effectively terms-of-art, because understanding depends on correctly translating them into their non-abbreviated forms.

  • 모든 약어의 의미는 쉽게 검색할 수 있어야 한다.
  • The intended meaning for any abbreviation you use should be easily found by a web search.
  • 사람들이 많이 사용하는 용어를 사용해라. 괜히 용어를 최적화하려고 하지 마라.
  • Embrace precedent. Don’t optimize terms for the total beginner at the expense of conformance to existing culture.
    • 초보자가 쉽게 이해할 수 있는 단순한 용어(List)가 있을지라도, 대부분의 프로그래머가 익숙한 용어(Array)를 사용할 때 웹 검색 및 질문에 대해 보상받을 수 있다. (Array는 최신 컴퓨팅의 기본이라서 모든 프로그래머가 알고 있거나 배우게 된다.)
    • It is better to name a contiguous data structure Array than to use a simplified term such as List, even though a beginner might grasp the meaning of List more easily. Arrays are fundamental in modern computing, so every programmer knows—or will soon learn—what an array is. Use a term that most programmers are familiar with, and their web searches and questions will be rewarded.
    • 수학같이 특정 프로그래밍 영역에서는 설명문구(verticalPositionOnUnitCircleAtOriginOfEndOfRadiusWithAngle)보다 널리 사용되는 용어(sin(x), cos(x), tan(x))를 사용하는 게 좋다. 이런 경우는 '약어 지양'보다 '사람들이 많이 사용하는 용어'가 더 중요하다. 본래 용어는 'sine'이지만, 'sin(x)'는 오랜 기간 프로그래머와 수학자 사이에서 일반적으로 사용되어왔다.
    • Within a particular programming domain, such as mathematics, a widely precedented term such as sin(x) is preferable to an explanatory phrase such as verticalPositionOnUnitCircleAtOriginOfEndOfRadiusWithAngle(x). Note that in this case, precedent outweighs the guideline to avoid abbreviations: although the complete word is sine, “sin(x)” has been in common use among programmers for decades, and among mathematicians for centuries.

 

API Design Guideline 원문, 번역본

 

Swift.org

Swift is a general-purpose programming language built using a modern approach to safety, performance, and software design patterns.

www.swift.org

 

API Design Guidelines

API Design Guidelines Table of Contents 기본 개념 가장 중요한 목표는 사용 시점에서의 명료성입니다. 메소드, 속성과 같은 개체들(Entities)은 한 번만 선언되지만, 반복적으로 사용됩니다. API는 이러한 개

minsone.github.io

 

반응형

댓글