[Swift] `날 것`에 의미를 부여해보자!: NameSpace

코드를 작성하다보면 날 것의 숫자나 텍스트를 적용해야 하는 경우가 있습니다. 예를 들어 JSON 파일로부터 데이터를 불러올 때, 파일의 이름을 작성한다거나, UI 요소에 적용될 접미 접두사 같은 요소들이 있겠죠.

이와 같은 날 것의 코드는 최초 작성자를 포함하여 동료들까지 실수를 일으킬 수 있는 요소가 될 수 있기에 별도의 장소에 함께 작성해두었다가 불러서 사용하는 것이 더 좋은 선택일 수 있습니다. 날 것의 코드에 의미를 부여해줄 수 있기도 하구요.

예시 하나.

으잉? "exposition_universelle_1900"이 뭐람.. 파일 이름인가? 파일 이름 바뀌면 다른 곳에서도 다 바꿔야겠네.. 애초에 파일 이름이 맞는지도 잘 모르겠어.

충분히 이런 생각을 할 수 있다고 생각합니다. 이를 미연에 방지하려면 이러한 날 것의 코드를 모아서 관리하는 Name space를 만들 것을 고려해볼 수 있습니다. 아래 코드를 보실까요?

enum ExpoData {
  static let expoIntroduction: String = "exposition_universelle_1900"
  static let artworks: String = "items"
  static let posterImage: String = "poster"
}

Expo라는 것이 프로젝트임을 알고있다면, 이 열거 타입은 데이터와 관련된 타입이라는 것을 알 수 있겠네요. 소개와 관련된 자료는 expoIntroduction이, 미술품과 관련된 자료는 artworks가 가지고 있는 것도 파악이 가능할 것입니다. 그럼 이미지로 보여드렸던 내용도 아래와 같이 적용할 수 있겠죠.

파일 이름이 변경돼도 이 코드에서 변경할 점은 없겠네요. ExpoData라는 Name space에서 변경해주면 다른 파일에서 적용한 내용들도 함께 변경할 수 있으니까요.

예시 둘.

마찬가지로 UI 요소에 적용되는 날 것의 텍스트도 이러한 방식으로 관리할 수 있습니다. JSON 데이터에서 48130300이라는 숫자만 제공하는 상황에서 아래 이미지와 같이 방문객: , 에 해당하는 내용을 접두, 접미어로 붙여주어야할 때 아래와 같이 적용하시면 됩니다.

어떤가요? 저는 날 것의 텍스트가 코드에서 살아 숨쉬는 것 보다 훨씬 좋다고 생각합니다. 텍스트 뿐만 아니라 정수나 소수 모든 타입을 이러한 형식으로 선언하여 원하는 때마다 반복적으로 꺼내 쓸 수 있습니다!

아래가 궁금하시다면 계속해서 읽어주세요~!

좀 더 깊게 알고 싶어요. 왜 열거 타입에 타입 프로퍼티를 선언해서 사용하나요?

사실 Name space를 정의하는데 열거 타입을 꼭 사용하여야 하거나 타입 프로퍼티를 활용하지 않아도 됩니다. 구조체를 이용하거나 열거 타입의 case - rawValue를 활용해도 되죠. 이를 활용하면 아래와 같이 작성이 가능합니다.

// 구조체로 Name space를 작성하는 경우
struct ExpoData {
  static let expoIntroduction: String = "exposition_universelle_1900"
  static let artworks: String = "items"
  static let posterImage: String = "poster"
}

// 열거 타입의 case - rawValue 형식으로 작성하는 경우
enum ExpoData: String {
  case expoIntroduction = "exposition_universelle_1900"
  case artworks = "items"
  case posterImage = "poster"
}

실제로 위와 같은 형식으로 사용하기도 하는데요, 저는 개인적인 이유로 case가 없이 타입 프로퍼티만으로 작성된 열거 타입을 활용합니다. 그 이유는 의도치 않은 인스턴스를 생성하지 않을 수 있기 때문이에요.

1. 구조체와 비교

예를 들어, 위 예시와 같이 구조체로 Name space를 작성한 경우 ExpoData()를 통한 인스턴스 생성이 가능합니다. 아무 기능이 없더라도 의도치 않은 것임에는 틀림없죠. 이는 아래와 같이 이니셜라이저에 접근제한을 걸어둠으로써 인스턴스 생성을 방지할 수 있습니다.

// 구조체로 Name space를 작성하는 경우
struct ExpoData {
  static let expoIntroduction: String = "exposition_universelle_1900"
  static let artworks: String = "items"
  static let posterImage: String = "poster"
  
  private init() { }
}

저는 이렇게 이니셜라이저에 접근제한을 설정하는 것 또한 case 없는 열거 타입에 비해 불필요한 코드가 추가되는 것이라 생각해서 선호하지 않습니다.

2. 열거 타입의 case - rawValue로 정의된 경우와 비교

두 번째 예시를 다시 가져와 보겠습니다.

// 열거 타입의 case - rawValue 형식으로 작성하는 경우
enum ExpoData: String {
  case expoIntroduction = "exposition_universelle_1900"
  case artworks = "items"
  case posterImage = "poster"
}

제가 위와 같이 사용하지 않는 이유는 아래와 같습니다.

  • 해당 요소를 호출할 때 말미에 .rawValue를 추가해야 한다는 번거로움이 있습니다. ExpoData.artworks.rawValue처럼요. 저는 이렇듯 불필요하게 추가되는 요소를 선호하지 않습니다.
  • case가 존재하는 열거 타입의 경우 rawValue를 활용해서 이니셜라이징할 수 있으므로 구조체와 마찬가지로 의도치 않은 인스턴스를 생성할 수 있다는 단점이 존재합니다.
  • 열거 타입의 rawValue가 하나의 타입 (위 예시의 경우 String)으로 고정되므로 관련 있는 여러 타입을 하나의 Name Space에서 관리할 수 없습니다.

하지만 이 모든 것은 제 선호일 뿐이고 사용하시는 분들이 자유롭게 취사선택하시면 되겠습니다.

오늘도 읽어주셔서 감사합니다. 즐거운 하루 보내세요~!

좋은 웹페이지 즐겨찾기