 Apple Lover Developer & Artist

영속적인 디자인에 현대의 공감을 채워넣는 공방입니다

 Apple/iOS Dev Challenges

[Challenge] 라이브러리 관리 기술 살펴보기

singularis7 2023. 12. 19. 17:32
반응형

Overview

이전 포스팅 [Challenge] 데이터 암복호화 모델 개발 에서 생산한 코드를 타 프로젝트에서도 재사용할 수 있도록 모듈화 시켜본다.

지구 반대편 개발자와의 협업

소프트웨어 개발자가 혼자서 코드를 작성하여 프로젝트를 구현하는 경우는 없다고 생각한다. 저수준의 운영체제 API부터 GitHub에 배포된 오픈소스까지 타인이 개발한 소프트웨어와 협력하여 프로젝트를 개발한다고 생각한다. 지구 반대편 개발자와의 협업 근간에는 라이브러리와 프레임워크가 주요한 역할을 하고 있다.

라이브러리 vs 프레임워크

라이브러리와 프레임워크는 무엇일까? 이 질문에 답하는 것은 쉬운 일이 아니다. 겉보기에는 타인이 작성한 소프트웨어를 재사용한다는 점에서 차이가 없어 보이기 때문이다. 도구 사용성 관점에서 둘의 차이를 구분해 보자면 프로그램 제어 흐름의 주도권을 누가 쥐고 있는가로 살펴보면 비교적 손쉽게 구분 가능하다.

라이브러리는 개발자가 필요할 때 가져다 쓸 수 있는 도구 모음이다. 개발자가 제어 흐름을 갖고 있으며 필요시 라이브러리를 호출하거나 사용한다. 예를 들어 iOS 오픈소스 라이브러리를 생각해 볼 수 있다. 네트워크 요청을 쉽게 처리하는데 사용되는 Alarmofire나 오토레이아웃 코드의 관리를 도와주는 SnapKit 등을 생각해볼 수 있다.

프레임워크는 프레임워크 도구 자체가 소프트웨어의 제어흐름을 가지고 있다. 개발자는 프레임워크의 제어 정책이나 규칙에 맞추어 코드를 작성하며 프레임워크가 이를 실행시킨다. 예를 들어 iOS 네이티브 앱 개발 프레임워크인 UIKit을 생각해볼 수 있다. App, Scene, View의 생명주기에 맞추어 상황별로 호출해 주는 Delegate 메서드를 정의해 두었다. 프로그래머는 UIKit 프레임워크가 규정하는 상황이나 시점에 맞추어 실행되어야 할 코드를 Delegate 프로토콜을 구현함으로써 앱을 개발하게 된다.

라이브러리 사용 기술

대부분의 앱 기능은 실행 가능한 코드 라이브러리에서 구현된다. 개발자가 작성한 소스 코드에서 앱 실행파일이 도출되기까지 거치는 과정이 있다. 크게 소스 코드를 컴파일하여 Object 코드를 만든 후 라이브러리 코드와 링킹 과정을 거쳐서 실행파일이 도출된다.

여기서 라이브러리를 사용하기 위해 앱에 연결(Link)하는 방식은 다음과 같이 크게 두 가지 종류가 있다.

  • Static 링킹
  • Dynamic 링킹

두 링킹 기술의 동작 방식에서 차이는 라이브러리를 연동할 때 무엇을 링크하는가에 있다. Static 링킹은 최종 도출할 실행 파일에 라이브러리 코드를 포함시킨다. Dynamic 링킹은 실행 파일에 라이브러리의 주소값을 기록해 두고 런타임에서 라이브러리를 불러온다는 점에서 차이가 있다.

이 둘의 차이점을 왜 고민해야 하는지 생각해 보겠다. 먼저 앱의 성능 지표 상의 차이점이다. 앱의 성능을 결정하는 두 가지 중요한 요소는 시작 시간과 메모리 공간이다. 라이브러리 코드가 언제 메모리에 적재되고 어떻게 불러와지는지에 따라 성능 지표가 영향을 받게 된다.

정적 링킹 방식을 사용하면 초기 앱 실행 시 메모리 적재 용량이 커지며 이에 시작 시간이 영향을 받아 느려진다. 반면에 동적 링킹 방식을 사용하면 런타임에 실제 필요할 때 라이브러리를 메모리에 적재시킨다. 따라서 앱에서 사용되는 초기 메모리 용량을 줄일 수 있다. 다만, 런타임에서 라이브러리를 불러오기에 런타임 사용자 경험을 해칠 수 있기에 trade-off 적인 성격이 있다고 생각한다.

앱의 배포 과정의 영향성도 고려해야 한다. 동적 링킹 방식은 배포 유연성을 제공한다는 장점이 존재한다. 앱의 실행 파일에 라이브러리가 포함되어 있는 것이 아닌 런타임에 불러오는 방식이기에 앱을 재컴파일하지 않고도 라이브러리를 수정할 수 있다. 실제로 주요 iOS 및 macOS 시스템 라이브러리에 Dynamic 링킹 방식이 사용되어 운영체제가 업데이트되어도 앱스토어의 모든 앱을 재컴파일해서 배포하는 일이 발생하지 않는다.

문제점

외부 라이브러리를 사용하면 프로젝트 개발 시간을 단축할 수 있다. 다만, 프로젝트에 연동된 라이브러리를 관리하는 비용이 발생할 수 있다.

예를 들어 프로젝트를 개발하면서 라이브러리에서 문제가 발생하여 수정된 버전의 라이브러리를 반영해줘야 하는 경우를 생각해 볼 수 있다. 개발자가 전달받은 라이브러리 파일을 수기로 교체해 주며 프로젝트 개발 환경에 알맞게 설정해주어야 한다고 가정해 보자. 한번 하기도 버거운 작업을 사람이 개별 라이브러리의 버전에 맞추어 프로젝트를 구성하기란 어려울 것이다.

의존성 관리 도구

위 문제를 해결하고자 탄생한 것이 의존성 관리 도구이다. 의존성 관리 도구는 프로젝트가 필요로 하는 라이브러리 관리 과정을 간단한 명령어들을 활용해 자동화시켜 준다. iOS 개발 과정에서 자주 사용되는 대표적인 의존성 관리도구는 CocoaPods, Swift Package Manager 등이 존재한다.

의존성 관리 도구의 종류에 따라 구체적인 사용법은 다를 수 있다. 큰 맥락에서는 유사한 느낌으로 사용할 수 있다. 우선 프로젝트에서 사용할 라이브러리 목록을 선언하고 의존성 관리 도구의 명령어를 통해 라이브러리를 설치한다. 설치가 완료되면 라이브러리 연동이 완료된 프로젝트 파일이 도출되거나 현재 프로젝트에 구성이 완료된다. 개발자는 라이브러리 연동이 완료된 개발 환경에서 소스 코드를 작성해 나가면 된다.

라이브러리 개발 실습

이전 포스팅에서 개발한 암복호화 모듈 코드를 모듈화 해보겠다. 이번에는 의존성 관리 도구 없이 Xcode 프로젝트에 Static 라이브러리를 직접 연동해 보겠다.

Static 라이브러리 연동하기

Xcode에서 새 프로젝트를 생성한다. Static 라이브러리 템플릿을 선택하였다.

프로젝트 이름은 CryptoManagerStaticLibrary로 정했다. 프로그래밍 언어는 기존에 개발해 둔 암호화 라이브러리를 재사용하고자 Objective-C를 선택해 주었다.

자동으로 생성된 Objective-C 파일을 제거하고 새로운 Objective-C 파일을 생성했다. 이름은 구현해 둔 암호화 라이브러리 오브젝트 이름과 동일하게 Crypto Manager을 사용하였다.

Xcode의 IDE 설정에서 Location 탭을 눌러 빌드 결과물이 저장될 디렉터리 위치를 수정해 줄 것이다. Derived Data로 수정해 주면 프로젝트 폴더에서 빌드 결과물도 함께 확인 가능하다.

소스 코드를 빌드한다. 빌드가 완료되면 프로젝트 폴더에 DerivedData/(프로젝트이름)/Build/Products/Debug에 들어가면 .a 파일을 볼 수 있다. 라이브러리 사용자에게 .a 파일과 소스코드의 헤더파일을 함께 전달하면 사용할 수 있다.

새로운 Swift 프로젝트를 생성하여 모듈을 사용해 보겠다. CryptoManagerStaticLibrarySwift라는 macOS CLI 프로젝트를 생성한 후에 앞서 생성한 .a 파일과 헤더 파일을 프로젝트에 추가해 주었다.

브릿징 헤더를 추가해 준 뒤에 CryptoManager.h 헤더 파일을 불러온다.

main.swift에서 CryptoManager 오브젝트를 사용해 본 후 정상적으로 결과가 출력되는지 확인해 본다.

Reference

반응형