프레임워크와 라이브러리는 많이 들어보았지만 차이점을 설명해보라고 한다면 정확히 대답을 못하기에 정리를 해보았다.
먼저 프레임워크와 라이브러리의 개념에 대해 살펴보고 차이점에 대해 알아보겠다.
프레임워크는 Application 개발 시 코드의 품질, 필수적인 코드, 알고리즘, 암호화, 데이터베이스 연동 같은 기능들이 어느 정도 구성 되어있는 뼈대(구조)를 제공하도록 만들어진 것이다. 소프트웨어에서의 프레임워크는 '소프트웨어의 특정 문제를 해결하기 위해서 상호 협력하는 클래스와 인터페이스의 집합'이라 할 수 있으며, 완성된 어플리케이션이 아니기 때문에 프로그래머는 제공된 프레임워크의 구조를 이용하여 어플리케이션을 완성해야 한다.
라이브러리는 특정 기능에 대한 API(도구/함수)를 모은 집합을 라이브러리라고 한다. 그 기능을 사용하기 위해 불러와서 호출하는 방식을 생각하면 쉽다.
위의 내용으로만 봤을 때는 단순히 라이브러리가 모이면 프레임워크처럼 보일 수 있다.
하지만 프레임워크와 라이브러리의 핵심적인 차이는 'Flow(흐름)에 대한 제어 권한이 어디에 있느냐'이다.
프레임워크는 전체적인 흐름을 자체적으로 제어하며 프로그래머는 프레임워크 안에 필요한 코드를 작성한다. 반면에 라이브러리는 전체적인 흐름을 자체적으로 제어할 수 없으며 사용자가 흐름에 대해 제어를 하는 도중 필요한 상황에 가져다 쓰는 것이다.
이 내용을 한 문장으로 정리하면 프레임워크에는 제어의 역전(Inversion Of Control)
이 적용되어 있다는 것이다.
제어의 역전이란 어떠한 일을 하도록 만들어진 프레임워크에 제어의 권한을 넘김으로써 클라이언트 코드가 신경 써야 할 것을 줄이는 전략이다. 이것을 '제어가 역전되었다'라고 한다.
일반적으로 프로젝트를 생성하고 Main 함수를 만들어서 시작 지점을 형성한다. 그리고 Main 함수에서 프로그램의 흐름을 정하는 것은 프로그래머의 몫으로 우리가 어떠한 순서를 부여하느냐에 따라 흐름을 제어하는 것이 일반적인 사고이다. 하지만 여기서 프레임워크는 일반적인 사고와 반대되는 모습을 보여주는데 실행의 흐름을 프레임워크 자체가 가지고 있어서 우리의 코드를 프레임워크 안에 넣어서 개발을 진행해야 한다. 일반적으로 프로그래머가 가지고 있어야 하는 제어의 권한을 프레임워크에게 주었기 때문에 이를 제어의 역전이라고 말한다.
다시 말해, 라이브러리는 이를 가져다가 사용하고 호출하는 측에 전적으로 주도성이 있는 반면, 프레임워크는 그 틀 안에 이미 제어 흐름에 대한 주도성을 내재하고 있다는 것이 핵심이다. 프레임워크는 가져다가 사용한다는 개념보다는 거기에 들어가서 사용한다는 느낌으로 접근할 수 있다.
그렇다면 대체 어떻게 프레임워크가 나의 메소드를 호출할 수 있는가에 대한 의문이 생긴다.
제어를 역전시키는 가장 쉽게 생각할 수 있는 접근 방법은 프레임워크의 event, delegate에 나의 메소드를 등록시키는 것이다.
예를 들면 사용자로부터 몇 가지 정보를 얻는 커멘드라인 프로그램을 작성한다고 하면 다음과 같다.
puts 'What is your name?'
name = gets
process_name(name)
puts 'What is your quest?'
quest = gets
process_quest(quest)
이 상호 작용에서 언제 질문을 할 것인가? 응답을 언제 읽을 것인가? 이 결과들을 언제 처리할 것인가?를 개발자가 결정한다. 즉, 개발자가 코드를 제어하고 있다.
그러나, 윈도우시스템을 위한 작업을 한다면 다음과 같다. 다음의 예시는 파이썬의 TKinter 프레임워크를 사용한 예시이다.
require 'tk'
root = TkRoot.new() //루트 윈도우 생성
name_label = TkLabel.new() {text "What is Your Name?"} // 라벨 위젯
name_label.pack // 위젯을 적당한 곳에 위치시킨다.
name = TkEntry.new(root).pack //입력을 받을 위젯을 생성하고 위치시킨다.
name.bind("FocusOut") {process_name(name)} //위젯 밖으로 나갔을 때 함수 실행
quest_label = TkLabel.new() {text "What is Your Quest?"}
quest_label.pack
quest = TkEntry.new(root).pack
quest.bind("FocusOut") {process_quest(quest)}
Tk.mainloop() //다양한 이벤트로부터 오는 메시지를 받고 전달
커맨드 라인 프로그램에서는 process_name
과 process_quest
메소드를 호출한다.
하지만 윈도우 시스템에서는 폼을 만들 때의 바인딩을 기반으로 개발자가 정의한 메소드를 호출한다. 개발자가 주도적으로 메소드를 호출하는 것이 아니라 프레임워크가 개발자의 메소드를 호출해 실행한다. 이 현상을 제어의 역전이라고 한다.
간단히 정리하자면 라이브러리는 함수나 기능 모음을 가져다가 쓰는 것이고, 프레임워크는 프레임워크가 실행되다가 중간중간에 특정 비지니스나 특정 구현 단에서만 사용자의 코드를 사용하는 형태라고 할 수 있다. 라이브러리와는 달리 프레임워크는 프로그래밍할 규칙이 정해져 있다.
아직 개념이 모호할 것 같아서 예를 들어보겠다.
프레임워크는 공장과 같다. 옷 공장, 신발 공장, 만두 공장 등 공장마다 서로 다른 제품을 생산한다. 각자 목적에 맞는 공장들이 있다.
제품을 만들기 위해 어떤 재료를 사용하냐에 따라 제품의 품질, 디자인 등 여러 면이 달라진다. 하지만 공장이라는 개념만 봤을 경우 재료를 준비하고 가공하고 생산하는 일은 같다. 여기서 공장은 프레임워크이고 재료는 라이브러리이다.
만약, 웹 어플리케이션을 구축한다고 하자. 웹 어플리케이션을 구축하려면 웹에 맞는 환경설정과 DB와 연동하기 위해 무엇을 써넣어야 하는지, 소스 파일을 어느 위치에 넣어야 하는지 정해져 있다. 이렇게 필수적으로 구현해야 하는 코드를 삽입함으로써 프레임워크는 흐름을 주도적으로 제어할 수 있다. 개발자는 그 흐름 안에서 필요한 기능을 넣어서 구현한다. 이것이 프레임워크를 사용하는 것이고, 그 안에 필요한 기능을 넣는 것이 라이브러리이다.
프레임워크를 사용한다면 라이브러리만을 사용해서 만드는 것보다 훨씬 비용과 시간이 적게 든다는 장점이 있다.