samsung-ga / woody-iOS-tip

🐶 iOS에 대한 소소한 팁들과 개발하다 마주친 버그 해결기, 그리고 오늘 배운 것들을 모아둔 레포
19 stars 0 forks source link

[TIL] 동적, 정적 프레임워크/라이브러리 #28

Open samsung-ga opened 2 years ago

samsung-ga commented 2 years ago

모듈화의 이유

스크린샷 2022-07-23 오후 2 16 38

위 프로젝트를 잠깐 살펴보면, 색깔에 따라서 레이어가 분리되어있다. 게임의 코어한 부분을 담당하는 엔진 레이어와 게임의 점수를 계산하는 스코링 레이어, 그리고 UI를 보여주기 위한 프레젠테이션 레이어, 마지막으로 화면을 구성하는 UI 레이어가 있다. 화살표에 집중해보면 Score레이어에는 화살표가 가지 않고, Engine 레이어에도 Question만 제외하고 의존되지 화살표가 가지 않는다. 이는 의존성을 가지고 있지않다는 의미로 다른 게임앱을 만들거나 프로젝트를 할 때도 사용이 가능하다. UI는 프레젠테이션 레이어에 의존하고 있으며, 이럴경우, 아래 사진과 같이 SwiftUI로 구성을 했지만, UIKit으로 UI 레이어를 재구성할 수 있다는 소리이다.

스크린샷 2022-07-23 오후 2 14 42

모듈화를 하는 장점 중 하나는 위와 같이 다른 모든 레이어를 꺠뜨리지 않고 휘발성 의존성을 제거하고 다른 레이어로 쉽게 교체가 가능하다는 점이다. 또한, Scoring과 Engine 레이어의 각 객체들은 다른 레이어의 다른 구성 요소를 참조하지 않았기에 다른 곳에서 재사용 가능한 모듈로 추출할 수 있다.

위 구성 요소들을 재사용하는 가장 간단한 방법은 복사 붙여넣기이다. 하지만, 모두가 알고있다. 이는 좋은 방법이 아니라고 ㅋㅋㅋ,,, 변경사항이 생길 때마다 붙여넣은 모든 코드를 전부 수정해야한다.

Apple 책에서 모듈에대해 다음과 같이 정의한다.

A module is a single unit of code distribution-- a framework or application that is build and shipped as a single unit and that can be imported by another module with Swift's import keyword

모듈은 단인 코드 배포 단위, swift의 import 키워드를 사용하여 다른 모듈에서 가져올 수 있는 프레임워크 또는 응용 프로그램이다.

즉, 라이브러리와 프레임워크를 만드는 이유는 재사용 가능하게 코드를 복제하지 않고 관리하기 위한 방법이다. 예시로 아래 사진을 보면 Quiz 엔진을 다른 프로젝트로 관리하고 있따. Quiz Engine은 프레임워크이고, 이를 QuizApp에서 dependency로 가지고 import해서 사용한다.

스크린샷 2022-07-23 오후 2 30 00

다이어그램을 다시 살펴보면, Engine에서 나가는 화살표는 하나도 없다. Engine은 어떤 레이어에도 의존하지 않기 때문에 이를 따로 분리할 수 있다. 하나의 프로젝트에서 여러개의 타겟, 프레임워크, 패키지들을 가지고 있으면 관리하기 어려울 수 있다. 이것이 소규모 프로젝트일 경우 오버 엔지니어링이 될 수 있기 때문에 하나의 프로젝트에서 나눌 수도 있다. 하지만, 여기서도 컴포넌트들의 의존도를 지키면서 개발해야 재사용이 가능하다. 만약 대규모 프로젝트일 경우, 협업하는 개발자들과의 충돌을 줄일 수 있을 뿐 아니라, 각자가 작업하고 있는 모듈만 빌드와 테스트를 하기 때문에 개발 속도를 높일 수 있다. 모듈화를 함으로써 생기는 태스크들이 있다. 모듈을 생성하고 기존의 프로젝트에서 코드를 분리하고, 모듈을 기존의 프로젝트에 연결하는 등 모듈과 관련된 태스크들이 생긴다. 하지만 이러한 태스크들은 나만의 스크립트를 만들거나 SPM, cocoapod, carthage 등 다양한 자동화해주는 방법으로 개선할 수 있다. (tuist, xcodegen ..) 그럼 이러한 의존성때문에 앱이 느려질 수 있다고 생각하지만, 프레임워크의 종류와 라이브러리 종류에 따라 앱의 성능과 사이즈가 달라진다. 모듈화를 선택함으로, 두통없이 다양한 이점을 누릴 수 있다. 모듈화를 무시하는 것은 팀속도를 늦추고 앱속도를 늦추는 것이 생각한다.

모듈화의 장점 정리

모듈화를 무시할 이유가 전혀 없다 ✨

프레임워크, 정적 라이브러리

일반적으로 프레임워크를 선호한다. 이유로는, 관리하기가 더 쉽고 프레임워크에서는 코드를 공유하는 것(재사용) 이상을 공유할 수 있기 때문이다. 번들, Resource(폰트, 스토리보드, nibs), 동적/정적 라이브러리 등, 물론 코드도!

QuizEngine 프레임워크의 빌드 세팅에서 Mach-O을 검색해보면 동적 라이브러리라는 것을 알 수 있다. 이 프레임워크는 동적 라이브러리를 포함하는 프레임워크로 동적 라이브러리로 빌드된다.

정적 라이브러리는 정적 링커에 의해 컴파일타임에 링크가 되고, 동적 라이브러리는 동적 링커에 의해 런타임에 링크가 된다. 그래서 정적 라이브러리가 대개 더 빠르다. 앱이 시작될 때 동적 링커 단계를 건너뛸 수 있기 때문이다. 하지만 모든 라이브러리가 동적으로 연결되어있고 앱이 시작할 때 모든 라이브러리를 부른다면 로드되어야 하기 때문에 속도가 느려질 것이다. 정적 라이브러리는 하나의 실행파일(바이너리) 내에서 모든 코드를 관리한다.

4가지 방법으로 빌드해보기

방법 사이즈 앱 실행 여부
동적 라이브러리 + 임베드 1.4MB O
동적 라이브러리 + 임베드 X 1.3MB X
정적 라이브러리 + 임베드 1.5MB O
동적 라이브러리 + 임베드 X 1.3MB O

퀴즈엔진 종속성을 연결하는 방법과 임베드된 상태에 따라 앱의 크기가 변경한다. 동적 라이브러리인 경우, 바이너리 파일이 따로 존재하여 앱이 시작할 때 (런타임에) 동적링커가 앱의 실행파일에 연결한다. 정적 라이브러리인 경우, 정적링커가 정적으로 링크하였기에 런타임에 로드되지 않고, 동일한 실행파일로 존재한다. 그래서 실행파일의 크기가 크다. 만약 정적 라이브러리인데 임베드까지 할 경우, 퀴즈 엔진은 이미 실행 파일 내에 존재하기 때문에 굳이 필요하지 않다. 하지만 임베드를 하지 않는다면 번들 프레임워크가 없기 때문에 퀴즈 프레임워크에서는 접근이 불가능하다. 즉, 퀴즈앱에서 퀴즈엔진 리소스에 접근이 가능해진다.

만약, 동적 라이브러리인데 임베드하지 않는 경우 동적 링커가 프레임워크를 찾지 못하여 퀴즈앱에 연결할 수 없기 때문에 충돌이 발생한다. 그럼 왜 앱이 실행될 때(런타임)에 로드되는 동적 라이브러리를 원하는가? 우리 앱을 재컴파일, 재배포없이 교체할 수 있다. 동일한 공용 인터페이스를 유지하는 한, 애플리케이션을 다시 컴파일하고 다시 재배포를 안해도 된다. 예를들어 코어데이터가 있다. 하나의 바이너리 파일로 여러 앱에서 재사용할 수 있다. 그런데 충돌이 발생하여 앱이 실행되지 않는다는 문제는 여전하다. 그러므로 무조건 임베드를 해주어야 한다.

Sign 같은 경우.

프레임워크에 sign을 하지 않으면 다시 sign을 해야한다. 프레임워크가 이미 sign되어 있는 경우 sign할 필요가 없다. 그래서 without이라는 선택지가 있다.

그 외

Ref


라이브러리와 프레임워크의 차이는 주체이다.

공통점

차이점

리액트 같은 경우는 라이브러리라고도 하고 프레임워크라고도 할 수 있을 것 같다.