์ด ์˜์—ญ์„ ๋ˆ„๋ฅด๋ฉด ์ฒซ ํŽ˜์ด์ง€๋กœ ์ด๋™
์กฐ์ด's log ๋ธ”๋กœ๊ทธ์˜ ์ฒซ ํŽ˜์ด์ง€๋กœ ์ด๋™

์กฐ์ด's log

ํŽ˜์ด์ง€ ๋งจ ์œ„๋กœ ์˜ฌ๋ผ๊ฐ€๊ธฐ

์กฐ์ด's log

Swift API Design Guidelines - 1

  • 2023.03.13 12:46
  • ๊ณต์‹๋ฌธ์„œ ํ†บ์•„๋ณด๊ธฐ/Swift API Design Guidelines

[1] Foundamentals

์‚ฌ์šฉํ•  ๋•Œ ๋ช…ํ™•ํ•˜๊ฒŒ ๋А๋ผ๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋ช…ํ™•ํ•œ ๊ฒƒ์ด ๊ฐ„๊ฒฐํ•œ ๊ฒƒ๋ณด๋‹ค ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

let blackButton (๐Ÿ‘)
let blackBtn  (๐Ÿ‘Ž)

๋ชจ๋“  ์„ ์–ธ์— ๋Œ€ํ•ด ๋ฌธ์„œ ์ฃผ์„(Documentation Comment) ๋ฅผ ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”

/// Writes the textual representation of each  
/// element of `items` to the standard output.
///                                              โ† Blank line ๋นˆ์ค„
/// The textual representation for each item `x` 
/// is generated by the expression `String(x)`.
///
/// - Parameter separator: text to be printed    โŽซ
///   between items.                             โŽŸ
/// - Parameter terminator: text to be printed   โŽฌ Parameters section
///   at the end.                                โŽŸ
///                                              โŽญ
/// - Note: To print without a trailing          โŽซ
///   newline, pass `terminator: ""`             โŽŸ
///                                              โŽฌ Symbol commands
/// - SeeAlso: `CustomDebugStringConvertible`,   โŽŸ
///   `CustomStringConvertible`, `debugPrint`.   โŽญ
public func print(_ items: Any..., separator: String = " ", terminator: String = "\n")

[2] Naming

(1) Promote Clear Usage

ํ•„์š”ํ•œ ๋‹จ์–ด๋“ค์„ ๋ชจ๋‘ ํฌํ•จํ•ด ๋‘์„ธ์š”

employees.remove(at: x) (๐Ÿ‘)
employees.remove(x) (๐Ÿ‘Ž)

๋ถˆํ•„์š”ํ•œ ๋‹จ์–ด๋ฅผ ์ƒ๋žตํ•˜์„ธ์š”

allViews.removeElement(cancelButton) (๐Ÿ‘)
allViews.remove(cancelButton) (๐Ÿ‘Ž)

ํƒ€์ž… ๋Œ€์‹  ์—ญํ• ์— ๋”ฐ๋ผ ๋ณ€์ˆ˜(variables), ํŒŒ๋ผ๋ฏธํ„ฐ(parameters), ์—ฐ๊ด€ํƒ€์ž…(associated types)์„ ๋„ค์ด๋ฐํ•˜์„ธ์š”.

///Good(๐Ÿ‘)
var greeting = "Hello"
protocol ViewController {
    associatedtype ContentView : View
}
class ProductionLine {
    func restock(from supplier: WidgetFactory)
}

///Bad(๐Ÿ‘Ž)
var string = "Hello"
protocol ViewController {
    associatedtype ViewType : View
}
class ProductionLine {
    func restock(from widgetFactory: WidgetFactory)
}

ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ์—ญํ• ์„ ๋ช…ํ™•ํžˆ ํ•˜๊ธฐ ์œ„ํ•ด ๋ถˆ์ถฉ๋ถ„ํ•œ type ์ •๋ณด๋ฅผ ๋ณด์ถฉํ•˜์„ธ์š”

///Good(๐Ÿ‘)
final class MyNotificationCenter{
    private var observers: [String:NSObject] = [:]

    func add(_ observer: NSObject, forKeyPath keyPath: String) {
        observers[keyPath] = observer
    }
}

let center = MyNotificationCenter()
center.add(self, forKeyPat: "mykey")


///Bad(๐Ÿ‘Ž)
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")

(2) 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 nounsโ€


///Bad(๐Ÿ‘Ž)
x.insert(y, position: z)
x.subViews(color: y)
x.nounCapitalize()

๐Ÿง ์˜ˆ์™ธ) ์ฒซ๋ฒˆ์งธ ๋˜๋Š” ๋‘๋ฒˆ์งธ argument ์ดํ›„์— ์ฃผ์š” argument๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์—๋Š” ์œ ์ฐฝํ•จ์ด ๋–จ์–ด์ง€๋Š” ๊ฒƒ์ด ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค.

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

factory method์˜ ์‹œ์ž‘์€ make๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

struct List {
    func makeIterator() -> IteratorProtocol {
        Iterator(self)
    }
}

x.makeIterator()

initializer์˜ argument์™€ factory method ํ˜ธ์ถœ์—๋Š” ๊ฒฝ๋กœ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ตฌ์ ˆ๋กœ ๊ตฌ์„ฑํ•˜์ง€ ๋งˆ์„ธ์š”

//Good(๐Ÿ‘)
///#1
struct Color {
    init(red: Int, green: Int, blue: Int) {}
    func makeWidget(gears: Int, spindles: Int) -> Widget{ Widget() }
}
let foreground = Color(red: 32, green: 64, blue: 128)
let newPart = factory.makeWidget(gears: 42, spindles: 14)

///#2
struct Link {
    init(target: Destination) {}
}
let ref = Link(target: destination)

///#3
struct RGBColor{
    init(_ cmykColor: CMYKColor) {}
}
let rgbColor = RGBColor(cmykColor)


//Bad(๐Ÿ‘Ž)
///#1
struct Color {
    init(havingRed red: Int, green: Int, and Blue: Int) {}
    func makeWidget(havingGearCount: Int, andSpindleCount: Int) -> Widget { Widget() }
}
let foreground = Color(havingRGBValuesRed: 32, green: 64, andBlue: 128)
let newPart = factory.makeWidget(havingGearCount: 42, andSpindleCount: 14)

///#2
struct Link {
    init(to target: Destination) {}
}
let ref = Link(to: destination)

๋ถ€์ˆ˜ํšจ๊ณผ(side-effect)๋ฅผ ๊ธฐ๋ฐ˜ํ•ด์„œ function ๊ณผ method์˜ ๋„ค์ด๋ฐ์„ ํ•˜์„ธ์š”.

  • side-effect๊ฐ€ ์—†๋Š” ๊ฒƒ์€ ๋ช…์‚ฌ๋กœ ์ฝํ˜€์•ผ ํ•จ. e.g.) x.distance(to:y), i.successor()
  • side-effect๊ฐ€ ์žˆ๋Š” ๊ฒƒ์€ ๋™์‚ฌ๋กœ ์ฝํ˜€์•ผ ํ•จ e.g.) print(x), x.sort(), x.append(y)
  • mutating/nonmutating method์˜ ์ด๋ฆ„์„ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ง“๊ธฐ.
    • operation์ด ๋™์‚ฌ๋กœ ์„ค๋ช…๋˜๋Š” ๊ฒฝ์šฐ: mutating์—๋Š” ๋™์‚ฌ์˜ ๋ช…๋ นํ˜•(sort(), append())์„ ์‚ฌ์šฉ, nonmutating์—๋Š” 'ed', 'ing'๋ฅผ ์ ‘๋ฏธ์‚ฌ๋กœ ๋ถ™์—ฌ์„œ(sorted(), appending()) ์‚ฌ์šฉํ•จ
  • operation์ด ๋ช…์‚ฌ๋กœ ์„ค๋ช…๋˜๋Š” ๊ฒฝ์šฐ: mutating์—๋Š” form์ ‘๋‘์‚ฌ ๋ถ™์—ฌ์„œ ์‚ฌ์šฉ(formUnion, formSuccessor), nonmutating์—๋Š” ๋ช…์‚ฌ ํ™œ์šฉ(union, successor)

nonmutating์ธ Boolean ๋ฉ”์†Œ๋“œ์™€ ํ”„๋กœํผํ‹ฐ๋Š” ํ˜ธ์ถœ๋˜๋Š” ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ฃผ์žฅ๋ฌธ์ฒ˜๋Ÿผ ์ฝํ˜€์•ผ ํ•œ๋‹ค

x.isEmpty , line1.intersects(line2)

์–ด๋–ค ๊ฒƒ์ด ๋ฌด์—‡์ธ์ง€๋ฅผ ์„ค๋ช…ํ•˜๋Š” ํ”„๋กœํ† ์ฝœ์€ ๋ช…์‚ฌ๋กœ ์ฝํ˜€์•ผ ํ•ฉ๋‹ˆ๋‹ค

Collection

๋Šฅ๋ ฅ์„ ์„ค๋ช…ํ•˜๋Š” ํ”„๋กœํ† ์ฝœ์€ able, ible, ing๋ฅผ ์‚ฌ์šฉํ•œ ์ ‘๋ฏธ์‚ฌ๋กœ ๋„ค์ด๋ฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

Equatable , ProgressReporting

protocol ProgressReporting{}

extension ProgressReporting{
    func reportProgress() {
    }
}

๋‚˜๋จธ์ง€ types, properties, variables, constants๋Š” ๋ช…์‚ฌ๋กœ ์ฝํ˜€์•ผ ํ•ฉ๋‹ˆ๋‹ค


(3) Use Terminology Well

  1. ์ผ๋ฐ˜์ ์ธ ๋‹จ์–ด๊ฐ€ ์˜๋ฏธ๋ฅผ ๋” ์ž˜ ์ „๋‹ฌํ•œ๋‹ค๋ฉด ์ž˜ ์•Œ๋ ค์ ธ ์žˆ์ง€ ์•Š์€ ์šฉ์–ด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์„ธ์š”.
  2. ์ „๋ฌธ ์šฉ์–ด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋Œ€์ค‘์—๊ฒŒ ์ธ์ •๋ฐ›๋Š” ์ •์˜ ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
  3. ์•ฝ์–ด(์ค„์ž„๋ง, abbreviations)์„ ํ”ผํ•˜์„ธ์š”
  4. ๊ด€๋ก€๋ฅผ ๋”ฐ๋ฅด์„ธ์š”.

์ฐธ๊ณ 

  • ๊ณต์‹ ๋ฌธ์„œ: https://www.swift.org/documentation/api-design-guidelines/
  • ๋ฒˆ์—ญ๋ณธ: https://cozzin.gitbook.io/swift-api-design-guidelines/naming/strive-for-fluent-usage
์ €์ž‘์žํ‘œ์‹œ (์ƒˆ์ฐฝ์—ด๋ฆผ)

'๊ณต์‹๋ฌธ์„œ ํ†บ์•„๋ณด๊ธฐ > Swift API Design Guidelines' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Swift API Design Guidelines - 2  (0) 2023.03.13

๋Œ“๊ธ€

์ด ๊ธ€ ๊ณต์œ ํ•˜๊ธฐ

  • ๊ตฌ๋…ํ•˜๊ธฐ

    ๊ตฌ๋…ํ•˜๊ธฐ

  • ์นด์นด์˜คํ†ก

    ์นด์นด์˜คํ†ก

  • ๋ผ์ธ

    ๋ผ์ธ

  • ํŠธ์œ„ํ„ฐ

    ํŠธ์œ„ํ„ฐ

  • Facebook

    Facebook

  • ์นด์นด์˜ค์Šคํ† ๋ฆฌ

    ์นด์นด์˜ค์Šคํ† ๋ฆฌ

  • ๋ฐด๋“œ

    ๋ฐด๋“œ

  • ๋„ค์ด๋ฒ„ ๋ธ”๋กœ๊ทธ

    ๋„ค์ด๋ฒ„ ๋ธ”๋กœ๊ทธ

  • Pocket

    Pocket

  • Evernote

    Evernote

๋‹ค๋ฅธ ๊ธ€

  • Swift API Design Guidelines - 2

    Swift API Design Guidelines - 2

    2023.03.13
๋‹ค๋ฅธ ๊ธ€ ๋” ๋‘˜๋Ÿฌ๋ณด๊ธฐ

์ •๋ณด

์กฐ์ด's log ๋ธ”๋กœ๊ทธ์˜ ์ฒซ ํŽ˜์ด์ง€๋กœ ์ด๋™

์กฐ์ด's log

  • ์กฐ์ด's log์˜ ์ฒซ ํŽ˜์ด์ง€๋กœ ์ด๋™

๋ฉ”๋‰ด

  • ํ™ˆ
  • ํƒœ๊ทธ

๊ฒ€์ƒ‰

์นดํ…Œ๊ณ ๋ฆฌ

  • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (12)
    • iOS ์ฐจ๊ณก์ฐจ๊ณก (1)
    • ๊ณต์‹๋ฌธ์„œ ํ†บ์•„๋ณด๊ธฐ (2)
      • WWDC (0)
      • Swift API Design Guidelines (2)
    • ํ›„๊ธฐ (9)
      • ํ”„๋กœ์ ํŠธ ํšŒ๊ณ  (0)
      • ์ฑ… (5)
      • ํ…Œํฌ talk (4)
    • ์—๋Ÿฌ๋…ธํŠธ (0)

๋‚˜์˜ ์™ธ๋ถ€ ๋งํฌ

์ •๋ณด

์กฐ์ด๐Ÿ˜ƒ์˜ ์กฐ์ด's log

์กฐ์ด's log

์กฐ์ด๐Ÿ˜ƒ

๋ธ”๋กœ๊ทธ ๊ตฌ๋…ํ•˜๊ธฐ

  • ๊ตฌ๋…ํ•˜๊ธฐ
  • RSS ํ”ผ๋“œ

๋ฐฉ๋ฌธ์ž

  • ์ „์ฒด ๋ฐฉ๋ฌธ์ž
  • ์˜ค๋Š˜
  • ์–ด์ œ

ํ‹ฐ์Šคํ† ๋ฆฌ

  • ํ‹ฐ์Šคํ† ๋ฆฌ ํ™ˆ
  • ์ด ๋ธ”๋กœ๊ทธ ๊ด€๋ฆฌํ•˜๊ธฐ
  • ๊ธ€์“ฐ๊ธฐ
Powered by Tistory / Kakao. © ์กฐ์ด๐Ÿ˜ƒ. Designed by Fraccino.

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”