Swift/Swift GuideLines

Swift GuideLines - 5.Naming(defaultParameter)

728x90

 

일반적인 사용을 단순화 할 수 있다면, defaulted parameters를 사용하세요.

일반적으로 사용되는 파라미터가 default로 사용될 수 있습니다.

예를들어 아래의 경우 default parameter를 사용해서 가독성을 높일 수 있습니다.

let order = lastName.compare(royalFamilyName, options: [], range: nil, locale: nil)

가독성높이기

(, options: [], range: nil, locale: nil 값들을 default로 넘겨버림)

let order = lastName.compare(royalFamilyName)

Bad

extension String {
	/// ...description 1...
	public func compare(_ other: String) -> Ordering
 
	/// ...description 2...
	public func compare(_ other: String, options: CompareOptions) -> Ordering

	/// ...description 3...
	public func compare(_ other: String, options: CompareOptions, range: Range) -> Ordering

  /// ...description 4...
}

method famliy라고 부름.

개별적으로 주석을 달아서 사용자가 사용할 때마다 뭐가 다른지 봐야하기 때문에 가독성이 떨어짐


default parameter을 파라미터 끝부분에 선언하는걸 선호함

func compare( options: CompareOptions, range: Range,_ other: String,) -> Ordering

⇒ 이런식으로 default paramter가 앞으로 가게되면 default paramter을 사용하냐 사용하지 않느냐에 따라 함수의 길이가 달라짐. 일관적이지 않게됨

Good

// 코드에 필수적으로 들어가야하는 부분이 지맘대로임. 일관적이지 않음
compare("A")
compare(range: nil, "A")
compare(options: nil, range: nil, "A")

//위에꺼보단 일관적임 필요한게 붙은느낌
compare("A")
compare("A", range: nil)
compare("A", options: nil, range: nil)


Label을 써도 유용하게 구분이 되지 않는다면 모든 Label을 생략하세요.

e.g) min(number1, number2), zip(sequence1, sequence2)

값을 유지하면서 타입변환을 해주는 initializer에서, 첫번째 argument label을 생략하세요.

e.g) Int64(someUInt32), String(123) 같은것

값의 범위가 좁혀지는 타입 변환의 경우, label을 붙여서 설명하는 것을 추천합니다.

extension UInt32 {
	/// Creates an instance having the specified 'value'
	init(_ value: Int16)

	// 64비트에서 32비트로 변환하면, 기존값에서 손실이 발생하기 때문에 label을 붙이는것을 추천한다.
	init(truncating source: UInt64)
}

첫 번째 argument가 전치사구의 일부일 때, argument label로 지정합니다.

argument label은 보통 전치사로 시작합니다.

eg. x.removeBoxes(havingLength: 12)

func(havingLength length) {}

처음에 나오는 2개의 argument들이 단일 추상화를 표현하는 경우는 예외입니다.

Bad

a.move(toX: b, y: c)
a.fade(frmoRed: b, green: c, blue: d)

Good

이런 경우, 추상화를 명확히 하기 위해 전치사 뒤에 argument label을 시작합니다.

a.moveTo(x: b, y: c)
a.fadeFrom(red: b, green: c, blue: d)

만약 첫번째 argument가 문법적 구절을 만든다면 label은 제거하고, 함수 이름에 base name을 추가합니다.

// Good
view.dismiss(animated: false)
let text = words.split(maxSplits: 12)
let studentsByName = students.sorted(isOrderedBefore: Student.namePrecedes)

구절이 정확한 의미를 전달하는 것이 중요합니다. 다음 예시는 문법적이지만 모호한 표현을 하고 있습니다.

// Bad
view.dismiss(false) // Don't dismiss? Dismiss a Bool?
words.split(12)     // Split the numer 12?

나머지 모든 경우, argument들을 Label을 붙여야 합니다.


tuple members와 closure parameters에 Label을 붙이세요.

import Foundation

struct Storage {
    func doSomething() -> (reallocated: Bool, capacityChanged: Bool) {
        return (false, false)
    }
}

let storage = Storage()

let result = storage.doSomething()

// 이름이 없다면, 0,1로 접근해야함
result.0
result.1

// 이름이 있다면 expressive access를 제공함
result.reallocated
result.capacityChanged

// byteCount가 closure의 parmeter Label임
mutating func ensureUniqueStorage(
    minimumCapacity requestedCapacity: Int,
    allocate: (_ byteCount: Int) -> UnsafePointer<Void>
) -> (rellocated: Bool, capacityChanged: Bool)

⇒ tuple의 경우 이름을 지어주면 호출하는 곳에서 이름으로 접근을 할 수 있다.

⇒ closure의 경우엔 호출하는 곳에서 이름으로 접근 할 수 없다.


overload set에서의 모호함을 피하기 위해, 제약 없는 다형성에 각별히 주의하세요.

e.g) Any, AnyObject, unconstrained generic parameters

Bad

struct Array<Element> {
    /// Insert 'newElement' at 'self.endIndex'
    public mutating func append(_ newElement: Element)
    
    /// Inserts the contents of 'newElements', in order, at
    /// 'self.endIndex'
    public mutating func append(_ newElement: S)
    Where S.Generator.Element == Element
}

// append에 여러개 더하는것과 하나하나 더하는것이 모호하다.
var values: [Any] = [1, "a"]
values.append([2, 3, 4]) // [1, "a", [2,3,4]] or [1, "a", 2, 3, 4]

Good

⇒ 모호한 append를 label을 넣어서 보다 명확하게 하자.

struct Array<Element> {
    /// Insert 'newElement' at 'self.endIndex'
    public mutating func append(_ newElement: Element)
    
    /// Inserts the contents of 'newElements', in order, at
    /// 'self.endIndex'
    public mutating func append(contentOf newElement: S)
    Where S.Generator.Element == Element
}

values.append(contentsOf: ["1,2,3"]) //  [1, "a", 2, 3, 4]

swift 에서 실제로 append에 contentsOf:같은 label을 사용하는 이유가 보다 명확하게 표현하기 위해서 였구나라는 걸 알 수 있다.

 

 

후기

ios 앱 개발을 시작하면서 점점 코드가 많아지는데 네이밍은 어떻게 해야할지 convention을 찾아다닌적이 있는데 이렇게 강의 까지 있을 줄은 몰랐다.  가만히 듣기만하면 머릿속에 안남을 거 같아서 따라 작성을 했는데 혼자서 하는 것 보다 편해서 좋았다.

 

2시간정도 소요된 것 같은데 한번 들어보는 것도 괜찮다.

 

읽기 좋은 코드 작성하기 - Swift API Design Guidelines - 인프런 | 강의

이 강의를 통해 이해하기 쉬운 코드가 무엇인지 제대로 된 기준을 잡을 수 있습니다. 단기간에 코드 컨벤션에 관한 많은 노하우를 배울 수 있을 것입니다., - 강의 소개 | 인프런...

www.inflearn.com

 

반응형