올리브영 테크블로그 포스팅 스위프트 매크로_2탄, 어떻게 쓰는건데요?
iOS

스위프트 매크로_2탄, 어떻게 쓰는건데요?

뜻밖의 자아성찰까지...

2024.01.15

지난 글에 이어 이번 포스트 역시 Let'Swift 2023에서도 발표 한 내용입니다.

안녕하세요. 냅다 돌아온 올리브영 모바일앱개발팀 윌입니다. 🙇

지난 글에 이어 이번 포스트에서는 스위프트 매크로를 만들고 적용해 본 경험을 공유해 보겠습니다.

무엇을 매크로로 만들건가요?

매크로가 제공하는 기능을 활용하기 위해서는 코드베이스 안에서 애매한 중복을 찾아야 했어요.

애매한 중복: 상속, 프로토콜 기본 구현 등 기존 방식으론 복붙 외에는 처리할 수 없는 중복 코드를 의미합니다.

애매한 중복을 찾는 것도 어려운데, 모두에게 통용되는 예외처리 케이스를 구현하는 것은 불가능했어요.


URL 인스턴스 하나 만드는 데도 예외 처리 방식이 정말 제각각입니다
fatalError forceUnwrap
returnNil throwError

그래서 제네릭하게 모든 팀에 통용될 수 있는 예외처리를 포함한 매크로는 포기하고 우리 팀에서 즉시 사용할 수 있는 매크로를 고민해보니 만들만한 매크로들이 많이 떠올랐어요.


요구사항을 소개합니다

Codable 좋아하시나요? 많은 프로젝트에서 채택하실 거라 생각합니다.

허나 프로젝트에 따라, 상황에 따라 사용하기 어려운 케이스도 분명히 존재할 거라고도 생각합니다.

예를 들어 XMLParser를 사용하는 프로젝트라든지, WKScriptMessage를 통해 데이터를 전달받는다든지요.

XMLParser -> [String: Any] -> Instance
WKScriptMessage.body: Any -> JSONString -> Instance

이 두 경우만 보더라도 꽤나 많은 중복 코드를 유발할 수 있다고 생각했어요.

  • 두 경우 모두 타입 갯수가 늘어날 수 있고 (스크립트 종류가 늘어나거나, 엔드 포인트 개수가 linear하게 늘어날 수 있죠)

  • XMLParser의 경우에는 메모리에 올리는 데이터 타입 안에 프로퍼티 개수가 늘어난다면 각 키 개수만큼 형변환도 추가를 해줘야 하죠

즉, 새로운 타입이 한 개 추가될 때마다 코드베이스 어딘가에 생성자 코드를 (반복해서) 작성하고 계셨을 거라고 생각합니다.

XMLParser의 경우

let parsedData: [String: Any] = ...

guard
    let propertyA = parsedData["keyA"] as? TypeA,
    ...., // 프로퍼티 갯수만큼 늘어남
    let instanceA = InstanceA(propertyA, ...)
else {
    return nil
}

// do something with instanceA

WKScriptMessage의 경우

let messageData: Any = ...

guard
    let jsonString = messageData as? String,
    let data = jsonString.data(using: .utf8),
    let instanceB = try? JSONDecoder()
        .decode(TypeB.self, from: data)
else {
    return nil
}

// do something with instanceB

문제는 기존 스위프트가 제공하는 방법으로는 (어딘가에서 코드 블록을 복사해와서 약간 고치거나) 묵묵히 작성하는 것 외에는 방법이 없었다는 점입니다.

애매한 중복 코드를 어떻게 줄여 볼 수 있을까요?


HeritageInitializer를 소개합니다

LegacyInitializer 라고 하면 기분이 안좋으니까

HeritageInitializer 라고 이름을 정하고 생성자 매크로를 작성해 보았어요.

전체 코드젠 패키지는 레포지토리에서 확인하실 수 있습니다.


매크로 실행 결과
initFromDict initFromJSONString
@InitFromDict @InitFromJSONString

이제는 중복된 생성자를 일일이 작성하지 않아도 됩니다.

원하는 타입을 선언하고 매크로만 붙여주면 끝이에요.

다만 매크로 패키지 디펜던시를 처음으로 선언하고 빌드하려고 하면 이런 얼럿창이 나오니까 꼭 활성화시켜주세요

apply-macro-first


한번 해보니 어땠나요?

우선 파일을 넘나들면서 이 코드가 중복되는구나 라는 걸 감지하는 눈이 생긴거 같아요. 이전까지는 파일 분리라도 잘 하자 라는 입장이었는데 눈높이를 약간 더 높일 수 있었던 것 같습니다.

또 빠른 피쳐 개발을 최우선으로 생각하다 보니 매년 WWDC에서 새로운 기술들을 소개해 주더라도 나에게 당장 필요한 기술이 아니라면 등한시 하거나, 이론적으로 공부를 하더라도 직접 구현하는 것까지는 하지 않았었거든요. 그러다 보니 시나브로 저도 김부장 처럼 되어가는 걸 은근히 체감하고 있었습니다.

엑셀-팡션

개발자의 공구통에 무언가를 추가하는 경험을 통해 기술적으로도 성장할 수 있었던 것 같습니다.

읽어주셔서 감사합니다. 🙇

그럼 다음에 다시 새로운 내용으로 만나요. 👋

iOSSwiftMacro
올리브영 테크 블로그 작성 스위프트 매크로_2탄, 어떻게 쓰는건데요?
🎮
|
iOS App Engineer
일단 해보는 개발자입니다