써니쿠키의 IOS 개발일기

[번역] API Design Guidelines 번역 (2/3) - Naming 본문

swift 공식문서

[번역] API Design Guidelines 번역 (2/3) - Naming

sunnyCookie 2022. 8. 16. 16:54

원본, 출처 : https://www.swift.org/documentation/api-design-guidelines/

앞으로도 여러 번 두고두고 읽을 내용이기에 번역을 했다.

완벽한 번역본이 아니므로 수정사항 있으면 알려주세요 !

(이름짓기)Naming

1. 사용법을 분명히 하세요

  • 이름이 사용된 곳에서 코드를 읽는 사람이 모호하지 않도록 하기 위해 필요한 모든 단어를 포함합니다.

    예를 들어 컬렉션 내의 주어진 위치에서 요소를 제거하는 방법이 있을 때

    x 번째 요소를 제거하라는건지, x를 제거하라는 건지 불분명 → at을 추가해줌으로서 모호함을 해결

      // ✅Good
      extension List {
        public mutating func remove(**at** position: Index) -> Element
      }
      employees.remove(**at**: x)
    
      // ❌Bad
      employees.remove(x) // unclear: are we removing x?
  • 불필요한 단어는 생략합니다. 이름에 사용된 모든 단어는 사용 영역에서 중요한 정보를 전달하는 게 좋습니다.

    의도를 명확히 하거나 의미를 명확하게 하기 위해 더 많은 단어가 필요할 수 있지만 이미 보유하고 있는 정보와 중복되는 단어는 생략해야 합니다. 특히, 단순히 타입 정보를 반복하는 단어는 생략하십시오.

      //✅ Good
      public mutating func remove(_ member: Element) -> Element?
      allViews.remove(cancelButton) // clearer
    
      //❌ Bad
      public mutating func removeElement(_ member: Element) -> Element?
      allViews.removeElement(cancelButton)

    때로는 모호함을 피하기위해 타입정보를 반복하여 네이밍을 해야하는 경우가 있을 수 있습니다. 하지만 일반적으로 파라미터의 역할로 네이밍하는 것이 타입으로 네이밍하는 것보다 좋습니다. 이에 대해선 아래에서 더 살펴봅시다

  • 타입명보다는 역할에따라서 변수, 파라미터, 연관타입을 네이밍합니다.

      //❌Bad
      var **string** = "Hello"
      protocol ViewController {
        associatedtype **View**Type : View
      }
      class ProductionLine {
        func restock(from **widgetFactory**: WidgetFactory)
      }

    위와 같이 타입 이름을 네이밍하면 명확하게 표현하기가 어려워집니다. 대신 entity의 역할을 표현하는 이름을 써봅시다

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

    만일 associated type이 프로토콜 제약 조건에 너무 밀접하게 연결되어 프로토콜 이름이 역할을 표현할 경우 ‘protocol’을 프로토콜 이름 마지막에 추가하여 충돌을 방지합니다.

      protocol Sequence {
        associatedtype Iterator : Iterator**Protocol**
      }
      protocol Iterator**Protocol** { ... }
  • 파라미터의 역할을 분명히 하기 위해서 불충분한 타입의 정보를 보충하세요.

    특히 파라미터 타입이 NSObject, Any, AnyObject 또는 Int 또는 String과 같은 기본 유형인 경우 사용 시 타입 정보나 사용 포인트에서 문맥에서의 의미를 완전히 전달하지 못할 수 있습니다

    아래예시를 보면 정의는 충분히 명확함에도 사용하는 곳에서는 메소드의 의도가 애매합니다

      //❌Bad
      func add(_ observer: NSObject, for keyPath: String)
      grid.add(self, for: graphics) // 의도가애매함
    
      //✅Good
      func add**Observer**(_ observer: NSObject, for**KeyPath** path: String)
      grid.addObserver(self, forKeyPath: graphics) // 명확

    이러한 모호함을 없애기 위해서는 타입자체에서 많은 정보를 얻을 수 없는 파라미터앞에 역할을 설명해주는 명사를 붙여주는게 좋습니다.


2. 유창하게 사용될 수 있도록 노력하세요

= (코드가 읽힐 때 영어 문장을 읽히는 것처럼 느껴지도록 네이밍하세요)

  • 메소드와 함수는 영어문장처럼 사용할 수 있도록 하세요

      //✅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)**
  • 팩토리 메소드의 이름은 “make”로 시작합니다

      x.makeIterator()
  • 이니셜라이저(initializer) 및 팩토리메소드(factory methods) 호출에 대한 첫 번째 인자(argument)는 기본 이름으로 시작하는 구문의 형태가 아니어야한다.

    예를들어 아래와 같은 경우 첫 번째 인자는 앞서 보여준 것과 같이 구문의 형태로 읽지 않습니다.

      //✅Good
      let foreground =Color(red: 32, green: 64, blue: 128)
      let newPart =factory.makeWidget(gears: 42, spindles: 14)
      let ref =Link(target: destination)
    
      //❌Bad
      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-effect)을 고려하여 함수와 메소드 이름을 짓습니다

    1. 부수작용이 없는 것은 명사로 읽혀야 함

      x.distance(to: y)
      i.successor()
    2. 부수작용이 있으면, 필수적으로 동사 처럼 읽혀야 함

      print(x)
      x.sort()
      x.append(y)
    3. mutating(가변) / non-mutating(불변) 메소드 한 쌍의 이름은 일관되게 짓습니다. ****가변 메소드는 종종 불변과 비슷한 의미로 변형되지만, 인스턴스를 갱신하는 것보다 새로운 값을 반환하는게 낫습니다.

      • 동작이자연스럽게 동사로 설명될때, 가변 메소드에 대해 동사의 명령형을 사용하고 불변 메소드 이름을 보완하기 위해 접미사로 ed나 ing를 추가합니다.

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

        동사의 과거 분사(일반적으로”ed"를 붙임)를 사용하여 불변 메소드와 다른 이름을 선호한다.

          /// Reverses `self` in-place.
          mutating func reverse()
        
          /// Returns a reversed copy of `self`.
          func revers**ed**() -> Self
          ...
          x.reverse()
          let y = x.reversed()

        “ed” 를 추가할때 동사가 목적어를 가지고 있기 때문에 문법에 맞지 않는 경우, 동사의 현재 분사를 사용하여 ing를 붙여 불변 메소드와 다른 이름이 된다.

          /// Strips all the newlines from `self`
          mutating func stripNewlines()
        
          /// Returns a copy of `self` with all the newlines stripped.
          func stripp**ing**Newlines() -> String
          ...
          s.stripNewlines()
          let oneLine = t.strippingNewlines()
    4. 동작이자연스럽게 명사로 설명될때, 불변 메소드에 대해 명사로 사용하고, 가변쪽에는 이름앞에 form 을 붙인다.

      출처:

      Mutating Nonmutating
      y.formUnion(z) x = y.Union(z)
      c.formSuccessor(&i) j = c.successor(i)
  • 불변(nonmutating)으로 사용할때 Boolean 메소드와 프로퍼티 사용은 수신자에 관한 주장처럼 읽어야 한다.

    • 예) x.isEmpty, line1.intersects(line2)
  • 무언가를 설명하는 프로토콜은 명사처럼 읽어야 한다.

    • 예) Collection
  • able, ible, ing 이름에 접미사를 사용하여 프로토콜이 할수 있는 능력을 설명한다.

    • 예) Equatable, ProgressReporting
  • 다른타입, 프로퍼티, 변수, 상수의 이름은명사처럼 읽어야 한다.


3. 전문용어를 잘 사용한다 (Use Terminology Well )

용어집(Term of Art)

명사(noun) - 특정분야 또는 작업 내에서 정확하고 전문화 된 의미를 갖는 단어나 문장

  • 일반 적인 단어가 의미를 더 잘 전달 할수 있다면, 애매한 전문용어는 피한다 (Avoid obscure terms). skin(피부)가 목적을 전달 할수 있다면, epidermis(표피)라고 하지 않는다. 전문용어는 필수적인 커뮤니케이션 도구이지만, 반드시 사용해야만 의미가 전달 될 때만 사용한다.

  • 이미 정의되어있는 전문용어를 사용해라.

    기술적인 용어를 사용하는 이유는 무언가에 대해 일반적인 단어보다 더 정확하게(precisely) 표현하기 때문이다 (그렇지 않으면 모호하거나 불분명할것이다.) 그러므로, API는 엄격하게 허용된 의미에 따라서 용어를 사용해야 한다.

    • 전문가를 놀라게 하지 말라 : 새로운 의미를 만들어 내면, 용어에 익숙한 사람은 놀라게 되고, 화를 낼것이다.
    • 초보자에게 혼동을 주지 말라 : 용어를 배우려는 사람은 웹 검색을 하여, 전통적인 의미를 찾으려 할것이다.
  • 약어를 피하라. 약어, 특히 표준이 아닌 약어는 소수만이 아는 전문용어이고 완전한 내용을 아는 경우에만 정확히 전달된다. 역에 의존해서 이해하기 때문에, 용어집이 효과적이다.약어에 대한 의미는 웹 검색으로 쉽게 찾을 수 있다.

  • 선례를 받아들인다. 기존 문화에 부합하지 않는 수고를 들이면서 까지 초보자들을 위한 용어를 최적화 하지 말라.

    연속적인 데이터 구조의 이름은 List처럼 단순한 용어를 사용하는 것보다 Array가 더 낫다. 비록 초보자가 더 쉬운 List의 의미를 파악할수 있더라도 말이다. 배열은 현대 컴퓨터의 기초이다. 모든 프로프래머가 배열이 무엇인지 알고 (또는 곧 배울 것이다)있다. 대부분의 프로그래머들은 익숙한 용어를 사용하고, 웹 검색하고 질문으로 보상을 받을 것이다.

    수학같은 특정 프로그래밍 도메인에서, sin(x)와 같이 널리 알려진 용어는 그대로 사용하는것이verticalPositionOnUnitCircleAtOriginOfEndOfRadiusWithAngle(x) 같은 네이밍보다 더 바람직하다.

    이는 약어를 피하는 것이 아니라 관례를 따르는 것이 더 가중치가 있다는것에 주목해야합니다. 비록 온전한 단어는 sine 이지만 “sin(x)”는 프로그래머들에게는 수십년간, 수학자들에게는 수세기 동안 보편적으로 사용되어 온 관례입니다.

반응형
Comments