Swift/Swift GuideLines

Swift GuideLines - 2.Naming

728x90

네이밍.. 네이밍이 제일어렵다. 사실 네이밍을 작성하는게 어렵다는건 로직에 따른 좋은 이름을 짓고 싶어서 그런게 아닌가 싶다.

어떻게 작성해야 할지 매일 고민하는 부분인데 잘 안되는 부분이다.

 

예시들을 통해 설명해주었는데 정리하면 

 

1.불필요한 단어는 빼자. 

2. 필요한 단어는 넣자.

3.영어 문법처럼 읽히게 작성하자.

4. 네이밍을 타입 위주로 작성하지말고 역할 위주로 작성하자.

5. 파라미터이름이 없을 경우 사용자가 이해가 어렵다면 추가적인 정보를 파라미터에 이름으로 태우자 (at : ) 같은것

 

필요한 단어들을 모두 포함해주세요.

Good

// Good
extension List {
	public mutating func remove(at position: Index) -> Element
}
employes.remove(at: x) // x번째 위치한 employee 제거

Bad

// Bad
// parameter 이름을 제거한 경우 
// 명확하지가 않음
employees.remove(x)

 

Swift에서 Parameter 이름을 따로 받을 수 있었던 이유가 이런 것들때문에 존재 했다는 걸 알게 되었다.


불필요한 단어를 생략하세요

  • 사용되는 시점에 핵심적인 정보만 전달 해야합니다.
// BAD
public mutating func removeElement(_ member: Element) -> Element?

allViews.removeElement(cancelButton)

⇒ Element라는 단어를 썻지만 의미있는 정보가 더해지지 않았습니다.

Good

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

allViews.remove(cancelButton) // clearer

⇒ 더 깔끔해짐


타입 말고 역할로 네이밍을 하는게 좋습니다.

  • 타입 대신 역할에 따라 변수(variables), 파라미터(parameters), 연관타입(asspciated types)을 네이밍하세요.

Bad

// Bad
var string = "Hello"
protocol ViewController {
	associatedtype ViewType: View
}

class ProductionLine {
	func restock(from widgetFactory: WidgetFactory)
}

⇒ 이런 방식으로 타입 이름을 정의하면 명확하게 표현하는 것이 어려워집니다. 대신, 엔티티의 역할을 표현하는 이름을 사용해보세요.

  • 엔티티의 역할? 선언하는 변수, 함수 등의 역할을 말한다.

Bad

타입으로 네이밍을 한 경우(Bad)

import UIKit

// Bad
// 변수의 이름만으로 역할을 구분 할 수 없게됨
var string = "Hello" // 의미를 가지지 않고 Type으로 네이밍한경우
var string2 = "My Name"

protocol ViewController {
    associatedtype ViewType // View가 들어갈것이기 때문에 ViewType으로 썻다.
    associatedtype StringType // String 들어갈것이기 때문에 ViewType으로 썻다.
}

struct MyViewController: ViewController {
    // 어떤 View를 지정해야할지,
    // 어떤 String을 지정해야할지 혼란스러운 결과가 발생합니다.
    typealias ViewType = <#type#>
    typealias StringType = <#type#>
}

class ProductionLine {
    // widgetFactory는 타입의 이름에 따라 지어버린 경우임
    // widgetFactory가 어떤 용도로 사용될지 모를 수가 있음
    func restock(from widgetFactory: WidgetFactory) {
        
    }
}

⇒ 변수의 이름만으로 역할을 구분 할 수 없게됨.

⇒ 네이밍에 맞는 값을 넣어야하는데 혼란스러운 결과가 발생함.

⇒ widgetFactory가 어떤 용도로 사용될지 모를 수가 있음.

Good

// Good
var greeting = "Hello"
var name = "My Name"

protocol ViewController {
    associatedtype ContentView
}

class ProductionLine {
    // suplier 이라는 역할을 하고있다
    // 명시적으로 적어주는게 좋습니다.
    func restock(from suplier: WidgetFactory) {
        
    }
}

예외

Protocol의 이름이 해당 역할을 표현하는 경우 구분짓기 위해 Protocol을 뒤에 추가함

// 문제: Iterator가 어디서 받아온거지?
// Iterator: Iterator에서 protocol타입명을 붙여주어야 명확해짐.
protocol Sqeuence {
    associatedtype Iterator: Iterator
}

protocol Iterator { }

// 해결
// protocol이름 자체가 해당 역할을 표현한다면, 구분을 짓기 위해
// protocol을 뒤에 추가합니다.
protocol Sqeuence {
    associatedtype Iterator: IteratorProtocol
}

protocol IteratorProtocol { }

파라미터의 역할을 드러내기 위해 weak type information을 보충하세요.

  • 파라미터의 이름을 역할에 맞는 이름을 추가적으로 넣어줘라
  • 특히 파라미터가 기본타입(Int, String...) 또는 NSObject, Any, AnyObject일 경우 파라미터의 이름에서 사용하는 의도를 파악하게끔 작성을해라

Bad

func add(_ observer: NSObject, for keyPath: String)
grid.add(self, for: graphics) // for가 뭘 의미하는거지? 애매함

⇒ for파리미터를 보다 명확하게 작성해야함

Good

func addObserver(_ observer: NSObject, forKeyPath path: String)

grid.addObserver(self, forKeyPath: graphics) // 명확함

⇒ forKeyPath path로 변경함으로써 더 명확해짐

? allViews.removeElement(cancelButton) → allViews.remove로 바뀌었는데 왜 addObserver가 되었을까 생각을 해봤는데 전달되는 파라미터에서 Observer에 대한 정보를 알 수 없어서 추가한 것 같다.

그러니까.. 이게 Observer가 추가되는지 뭔지 알수가 없음

Bad

import Foundation

final class MyNotificationCenter {
    private var observers: [String: NSObject] = [:]
    
    func add(_ observer: NSObject, for keyPath: String) {
        observers[keyPath] = observer
    }
}

let center = MyNotificationCenter()
center.add(self, for: "key")

Good

import Foundation

final class MyNotificationCenter {
    private var observers: [String: NSObject] = [:]
    
    func addObserver(_ observer: NSObject, forKeyPath path: String) {
        observers[path] = observer
    }
}

let center = MyNotificationCenter()
center.addObserver(self, for: "key")

유창한 사용을 위해 노력하세요(Strive for Fluent Usage)

  • method와 function을 영어 문장처럼 사용할 수 있도록 하기
  • 영어를 잘하는 사람이 유리하겠는데..

Good

x.insert(y, at: z) "x, insert y at z"
x.subViews(havingColor: y) "x's subviews having color y"
x.capitalizingNouns() "x, capitalizing nonus"

Bad

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

예외

  • 첫번째 또는 두번째 argument 이후에 주요 argument가 아닌 경우에는 유창함이 떨어지는 것이 허용됨
AudioUnit.instantiate(
	with: description,
	options: [.inProcess], completionHandler: stopProgressBar
)

factory method의 시작은 make로 시작합니다.

  • x.makeIterator()
// Good 
struct List {
    func makeIterator() -> IteratorProtocol {
        Iterator(self)
    }
}
  • initailizer의 argumnet와 factory method 호출에는 구절을 구성하지 마세요
    • 영문법 구성할려고 하지말아라
    • eg) bad x.makeWidget(cogCount: 47)
    GoodBad예외
    struct RGBColor {
        
        // cmyKColor가 들어와서 RGBColor로 들어가기 떄문에
        // 값이 보존 된다고 할수있다.
        // 그럴 경우 파라미터 네임을 생략한다.
        init(_ cmykColor: CMYKColor) {
            
        }
    }
    
    let rgbColor = RGBColor(cmykColor)
    
  • 값이 보존되는 경우 파라미터 네임을 생략한다.
  • let foreground = Color(havingRed red: Int, green: Int, andBlue: Int) let newPart = factory.makeWidget(havingGearCount: 42, andSpindleCount: 14) let ref = Link(to: destination) struct Link { init(to target: Desctionation) { } }
  • let foreground = Color(red: 32, green: 64, blue: 128) let newPart = factory.makeWidget(gears: 42, spindles: 14) let ref = Link(target: destination)

반응형