Software Design

라이브러리 vs 프레임워크, 기준은 '누가 누구를 호출하나' (제어의 역전)

Alamofire는 라이브러리라고 부르고, SwiftUI는 프레임워크라고 부릅니다. 근데 둘 다 "남이 만든 코드를 가져다 쓰는 것" 아닌가요? 뭐가 다른 걸까요.

이석우iOS Developer4분 읽기
라이브러리 vs 프레임워크, 기준은 '누가 누구를 호출하나' (제어의 역전) 대표 이미지

Alamofire는 라이브러리라고 부르고, SwiftUI는 프레임워크라고 부릅니다. 근데 둘 다 “남이 만든 코드를 가져다 쓰는 것” 아닌가요? 뭐가 다른 걸까요.

“프레임워크가 더 큰 거”라는 답을 흔히 듣는데, 크기는 본질이 아닙니다. 작은 프레임워크도 있고 거대한 라이브러리도 있거든요.

진짜 기준은 딱 하나입니다. 누가 누구를 호출하느냐.

이 기준 하나를 잡으면 제어의 역전(IoC)이라는 중요한 개념까지 자연스럽게 연결됩니다. 의존성 주입을 공부할 때도 다시 만나게 될 개념이라, 여기서 제대로 잡아두면 이득이에요.

공구함에서 꺼내 쓰면 라이브러리, 뼈대에 채워 넣으면 프레임워크
공구함에서 꺼내 쓰면 라이브러리, 뼈대에 채워 넣으면 프레임워크

핵심 요약입니다.

  1. 라이브러리: 내 코드가 필요할 때 호출하는 도구 모음. 제어권이 나에게 있다
  2. 프레임워크: 흐름을 프레임워크가 쥐고 내 코드가 호출“당하는” 뼈대. 제어권이 프레임워크에 있다
  3. 이 뒤집힌 호출 방향을 제어의 역전(Inversion of Control)이라 부른다
  4. 할리우드 원칙: “전화하지 마세요, 저희가 연락드릴게요”

라이브러리: 내가 부르는 도구

라이브러리는 특정 기능을 미리 구현해 둔 코드 묶음입니다. 언제 어떤 순서로 쓸지는 전적으로 내 코드가 정해요.

// 흐름의 주인은 내 코드
let json = try JSONDecoder().decode(User.self, from: data)
let hash = SHA256.hash(data: input)

프로그램의 시작과 끝, 전체 흐름을 내가 짜고, 중간중간 필요한 도구를 꺼내 씁니다. 공구함에서 드라이버를 꺼내 쓰는 것과 같아요. 드라이버가 작업 순서를 정하지는 않죠.

Alamofire, Kingfisher 같은 것들이 이 범주입니다. 언제 네트워크 요청을 보낼지, 언제 이미지를 로드할지는 내가 결정합니다.


프레임워크: 나를 부르는 뼈대

프레임워크는 애플리케이션의 전체 구조와 실행 흐름을 미리 만들어 놓은 뼈대입니다. 나는 그 뼈대가 비워 둔 자리에 코드를 채워 넣어요.

iOS 앱을 생각해 보면 명확합니다. 앱의 시작점, 이벤트 루프, 화면 생명주기는 전부 UIKit·SwiftUI가 쥐고 있어요. 내가 작성하는 건 viewDidLoad, body, onAppear처럼 프레임워크가 정해진 시점에 호출해 주는 코드입니다.

struct ProfileView: View {
    var body: some View {   // 내가 호출하지 않는다.
        Text("Hello")       // SwiftUI가 필요할 때 호출한다
    }
}

body를 내 손으로 호출하는 일은 없습니다. 언제 몇 번 호출될지는 SwiftUI가 결정해요. 흐름의 주인이 뒤바뀐 겁니다.

호출 방향이 반대입니다. 이게 제어의 역전이에요
호출 방향이 반대입니다. 이게 제어의 역전이에요

제어의 역전, 그리고 할리우드 원칙

이 뒤집힌 관계에 이름이 붙어 있습니다. 제어의 역전(IoC, Inversion of Control)이에요.

보통의 절차적 프로그램에서는 내 코드가 제어 흐름을 쥐고 외부 코드를 호출합니다. 프레임워크 기반 프로그램에서는 프레임워크가 그 흐름을 쥐고 내 코드는 등록해 둔 지점에서 호출당하죠. 제어권이 반대로 넘어갔으니 “역전”입니다.

이걸 재치 있게 표현한 말이 할리우드 원칙(Hollywood Principle)입니다.

“Don’t call us, we’ll call you.” — 전화하지 마세요, 저희가 연락드릴게요.

오디션을 본 배우가 제작사에 전화를 돌리는 게 아니라, 캐스팅되면 제작사가 연락하는 구조. 프레임워크와 내 코드의 관계가 정확히 이겁니다.

델리게이트 패턴도 같은 원리예요. UITableViewDataSource를 구현할 때 cellForRowAt을 내가 호출하나요? 아니죠. 테이블 뷰가 필요할 때 나를 호출합니다. 프레임워크 세계의 문법이 코드 곳곳에 스며 있는 겁니다.


그래서 실무에서 뭐가 달라지나

학습 방식이 다릅니다. 라이브러리는 “무슨 기능이 있나”를 찾아보면 되지만, 프레임워크는 “언제 나를 불러주나”(생명주기·호출 규약)를 먼저 익혀야 합니다. UIKit 공부가 생명주기 공부에서 시작하는 이유예요.

교체 비용이 다릅니다. 라이브러리는 호출부만 고치면 갈아탈 수 있지만, 프레임워크는 코드 전체가 그 뼈대 위에 올라가 있어서 교체가 사실상 재작성입니다. UIKit → SwiftUI 전환이 함수 몇 개 바꾸는 일이 아닌 이유죠.

테스트 전략이 다릅니다. 프레임워크가 호출해 주는 코드는 프레임워크 없이 단독 실행하기 어렵습니다. 그래서 로직을 프레임워크 비의존 계층(순수 Swift)으로 분리하라는 조언이 반복해서 나오는 거예요.

전화하지 마세요, 저희가 연락드릴게요 — 할리우드 원칙
전화하지 마세요, 저희가 연락드릴게요 — 할리우드 원칙

면접에서 한 문장으로

“라이브러리는 내 코드가 호출하는 도구이고, 프레임워크는 제어 흐름을 쥔 채 내 코드를 호출하는 뼈대입니다. 이 제어권의 방향 차이를 제어의 역전이라고 합니다.”

꼬리 질문은 “IoC의 예를 들어보라”(생명주기 메서드, 델리게이트), “그게 왜 좋나”(흐름을 표준화하고 개발자는 비즈니스 로직에 집중) 순으로 이어집니다.


정리

  • 구분 기준은 크기가 아니라 호출 방향이다
  • 라이브러리: 내 코드가 필요할 때 호출하는 도구. 제어권이 나에게 있다
  • 프레임워크: 흐름을 쥐고 정해진 시점에 내 코드를 호출하는 뼈대. 제어권이 프레임워크에 있다
  • 이 뒤집힌 제어권이 제어의 역전(IoC), 별칭은 할리우드 원칙
  • viewDidLoad·body·델리게이트 메서드는 전부 “호출당하는” 코드다
  • 실무 차이: 프레임워크는 생명주기 학습이 먼저고, 교체가 어려우며, 로직 분리가 테스트의 핵심이 된다