Swift API Design Guidelines - Naming

고라니·2023년 10월 12일
0

TIL

목록 보기
41/67

Swift에서는 이름이 정말 중요하다 이번에는 Naming에 대해 알아보면서 코드의 가독성과 유지 보수를 위한 올바른 이름짓기를 알아보도록 하자

Naming

Promote Clear Usage(명확하게 사용하기)

코드를 읽는 사람들이 모호하지 않도록 필요한 모든 단어를 포함한다.

컬렉션 내 주어진 위치의 요소를 제거하는 메서드를 예시로 보자

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

해당 메서드에서 'at'이라는 단어를 생략하면, 제거할 요소의 위치를 나타냈다기 보다 'x'같은 요소를 제거한다는 의미로 보일 수 있다.

❌
empolyees.remove(x) // X를 제거?(불분명)

불필요한 단어는 생략한다.

이름안의 모든 단어는 사용 위치에서 핵심정보를 전달해야 한다.
코드를 읽는 사람이 이미 알고 있는 정보와 중복되는 단어는 생략, 특히 타입 정보를 단순히 반복하는 단어는 생략

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

allViews.removeElement(cancelButton)

Element라는 단어는 호출 위치에서 중요한 정보를 제공하지 않는다. 다음의 코드처럼 개선하는게 더 나음

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

allViews.remove(cancelButton) // 명확함

타입 정보를 표현하는게 더 명확한 경우도 있지만 일반적으로는 타입보다는 매개변수의 역할을 설명하는 단어를 사용하는 것이 더 좋다.

변수나 매개변수의 이름은 해당 변수나 매개변수의 타입보다는 역할에 따라 짓기

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

위 코드 같은 방식으로 타입 이름을 재사용하는 것은 명확성과 표현력을 최적화 하기 좋지 않다. 대신 역할을 표현하는 이름을 지정하기 위해 노력해야 한다.

var greeting = "Hello" // 실제 의미에 더 가깝게
protocol ViewController {
  associatedtype ContentView : View // "내용을 표시하는 뷰"의 의미를 더 잘 나타냄
}
class ProductionLine {
  func restock(from supplier: WidgetFactory) // 마찬가지 역할을 중점으로
}

연관 타입이 특정 프로토콜과 너무 밀접하게 연결되어 충돌할 위험이 있다면, 프로토콜 이름에 Protocol을 추가하는것이 좋다.

protocol Sequence {
  associatedtype Iterator : IteratorProtocol
}
protocol IteratorProtocol { ... }

Iterator는 연관 타입 이름이지만, 이미 Interator라는 이름의 프로토콜이 존재할 수 있음 -> InteratorProtoco 이름 사용

약한 타입 정보를 보완하여 매개변수의 역할 명확하게 하기

특히 약한 타입 정보를 가진 매개변수(매개변수 유형이 NSObject, Any, AnyObject이거나 Int 또는 String과 같은 기본 유형인 경우) 선언부에서는 명확해 보일 수 있지만 호출부에서는 유형 정보 및 의도를 완전히 전달하지 못할 수 있다.

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

grid.add(self, for: graphics) // 모호함

함수 선언은 꽤 명확해 보이지만 실제로 함수를 사용할 때 어떤 역할을 하는지 명확하지 않다.

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

명확성을 위해 역할을 나타내는 명사를 사용한다. 약한 타입 정보를 가진 매개변수 앞에서는 그 매개변수의 역할을 설명하는 명사를 사용하여 함수를 더 명확하게 만들어야 한다.

Strive for Fluent Usage(자연스럽게 읽히도록 하자)

사용 위치에서 메서드와 함수의 이름이 영어 문법에 맞게 지정 하는것이 좋다.

✅
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”

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

하지만 모든 전달 인자에 대해 완벽한 자연스럽움을 유지하는것은 필수는 아니다, 특히 해당 전달 인자가 메서드나 함수의 주요 의미와 관련이 없을 때는 자연스러움이 서하되어도 괜찮다.

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

팩토리 메서드의 이름을 'make'로 시작해라

x.makeIterator()

팩토리 메서드?
: 특정 객체나 인스턴스를 생성하고 반환하는 메서드. 이런 메서드의 이름을 정할 때 'make'라는 단어로 시작하는 것이 관례적으로 권장 됨

초기화 및 팩토리 메서드 호출의 첫 번째 인자의 라벨이 연속적으로 이어져서 문장의 형태를 이루는 것을 피해햐 한다.

(처음엔 무슨말인가 했다... 즉 함수명과 첫번째 인자가 하나의 문장처럼 보이게 만들지 말라는 뜻!)

아래 코드의 첫 번째 인자들은 기본 이름과 동일한 문장으로 읽히지 않음

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

아래의 잘못된 코드의 경우 첫 번째 인자가 이름과 함께 문장으로 읽힘

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

대부분의 경우 첫 번째 인자에는 라벨을 붙여야 한다. 단, 함수가 단순히 값을 다른 형태로 바꾸는 것만을 목적으로 할 때는 예외적으로 라벨 생략 가능하다.

let rgbForeground = RGBColor(cmykForeground)

함수와 메서드의 이름은 해당 함수나 메서드가 미치는 부수적인 효과(Side-effects)에 따라 결정되어야 한다

부수 효과가 없는 함수나 메서드의 이름은 명사구처럼
ex) x.distance(to: y), i.successor()

부수 효과가 있는 함수나 메서드의 이름은 명령형 동사구처럼
ex) print(x), x.sort(), x.append(y)

또한, 객체를 직접 수정하는 변환 메서드와 새로운 값을 반환하는 비변환 메서드의 이름은 일관성 있게 지어야 한다.
1. 동사로 자연스럽게 설명되는 경우: 변환 메서드는 동사의 명령형 사용, 비변환 메서드는 ed, ing 접미사 사용

2. 명사로 자연스럽게 설명되는 경우: 변환 메서드는 form 접두사 사용, 비변환 메서드는 해당 명사 사용

비변환인 경우 Boolean메서드와 Boolean프로퍼티는 수신자에 대한 주장처럼 읽여햐 한다.

ex) x.isEmpty(비어있는가?), line1.intersects(line2)(교차하는가?)

무엇인지를 설명하는 프로토콜은 특정 객체나 클래스의 본질적인 특성이나 속성을 나타내야 한다.

따라서 이런 프로토콜의 이름은 간단하고 명사형태로 지어야 한다.
ex) Collection

기능이나 동작 능력을 설명하는 프로토콜은 주로 'able', 'ible', 'ing' 접미사를 포함하여 해당 능력을 명확하게 나타내야 한다.

ex) Equatable, ProgresswReporting

다른 타입, 프로퍼티, 변수, 상수들은 주로 데이터를 저장하기 때문에 명사 형태로 읽히게 이름을 지어야 한다.

Use Terminology Well(올바른 용어 사용하기)

일반적인 단어로도 충분히 의미전달 가능하면 모호한 전문용허는 피하기

ex) ✅피부, ❌표피

전문용어 사용시 그 의미를 충실히 사용

줄임말 사용을 지양하기

프로그래밍 분야에서 널리 알려진 용어나 표현 등 선례를 따르기

ex) ❌verticalPositionOnUnitCircleAtOriginOfEndOfRadiusWithAngle(x), ✅sin(x) : 선례가 줄임말을 쓰지 않는 규칙보다 우선 적용.


참고: Swift API Guidelines, yagom-academy

profile
🍎 무럭무럭

0개의 댓글