[PL] about frameworks
framework에 대한 짤막한 얘기
framework는 library와 조금 다르다. framework의 다른점은 inversion of control이란 용어로 설명이 되는데, 다음 그림을 보자.

Figure 1: fraemwork
이 그림은 인터넷에 돌아다니는건데, library가 framework를 꼭 포함해야 하는것은 아니다. 여튼 여기서는 framework의 특징만 알면 된다. user가 작성한 code는 일반적으로 code에서 함수를 호출한다. library의 함수던, code에서 정의된 함수던, 함수를 호출하는건 user의 code다. 반면 framework는 user가 function을 정의해 놓기만 한다. 그러면 누군가가 호출한다. 언제 호출하는지는 framework맘이다. 그리고 어떤 함수를 정의해야 하는지도 framework맘이다.
user가 함수를 정의만 하고 언제 호출하는지 모른다? 또한 어떤 함수를 정의해야 하는지도 framework가 정한다. 이것은 언뜻 이해가 가지 않을 수 도 있다. 예를 들면, c나 java의 paint(), flutter에서 보면 build()가 flutter framework가 호출하는 함수다. 미리 정의되었고, 호출은 보통 event에 의해서 처리된다. 이런 구조가 만들어진건 두개의 call flow가 있기 때문이다.
우리는 보통 생각한다. call flow는 하나라고, 그런데 두개다. programmer가 program을 작성하고 compile,link,load를 통해 memory에 code를 올리고 실행한다. 그러면 cpu가 entry point부터 순차적으로 실행하는 call flow가 있다. library의 function을 호출하는것도 이런 main call flow의 순차적 실행이다. library는 I/O device를 사용하는 코드가 포함되어 있을 수 있다. 또 다른 하나는 I/O event에 대한 처리루틴이다. I/O device는 event를 발생할 수 있다. 이것은 user code의 실행방향과 다르다. I/O device를 사용하면, user code에서 I/O device를 사용하기위한 함수를 정의하고 호출도 할수 있게 하지만, 역으로 event처럼 I/O device에서 user code의 정보가 필요할 수도 있고 정보를 알려줄수도 있다. 이게 좀 이상할 수도 있지만, 다음을 생각해보자. I/O Device들은 독립적인 하나의 system이다. cpu+memory로 이루어진것을 system이라고 하듯이, I/O device들도 계산할수 있는 cpu와 저장할수 있는 memory를 가진 하나의 system이다. 그리고 각각의 system은 연결되어 있는 것이다. 예를 들어 graphics system을 보자. graphics system은 display와 연결되어 주기적으로 화면에 보여줄 data를 보내준다. 대략적으로 60hz, 즉 1초에 60번 gpu에 rendering이 끝난 frame buffer를 display에 전달해준다. 그런데 gpu에 있는 framebuffer는 user code가 graphics framework를 사용했을때, 이용할 수 있다. gpu는 주사율 60HZ에 맞춰서 1초에 60번 framework로 event를 날려준다. 그러면 framework에서 적당한 처리를 해서 gpu에 넘겨주고 gpu에서 rendering처리를 해서 화면에 보여주는 식이다. 예를 들어, flutter framework는 build()를 호출한다. 이것이 call back 함수다. framework에서 미리 정해둔 함수다. 이렇게 해서, framework과 device들이 역으로 I/O device가 원하는 data를 얻는 것이다. rails framework도 비슷하다. rails framework은 network device와 database와 연결되어 있다. 상대방으로 부터 접속 연결이나 요청이 오면 header를 분석해서 routes.rb를 수행한다. routes.rb는 미리 framework에서 정해진 형식으로 만들어진 callback함수다. 그리고 or mapper라고 class를 db table변환을 할수 있게 database도 framework에 포함되어 처리한다. 이렇게 framework이라는 것은 device와 연동되어 있다. 해당 device를 이용한 무언가를 해볼려면 framework는 필수적이다. 그리고 plugin처럼 사용할 수 있다. 여기서 착각하지 말아야할 것은 device I/O를 사용하는 것은 내가 주체가 아니다. 내가 화면에 뿌려야지하고 function을 만들어 호출하면 화면에 뿌려지는게 아니라는 것이다. 내 입장이 아닌, graphics system에 맞춰야 한다. graphics system은 1초에 60번 build()로 정해진 곳에 원하는 그림을 그려놔라, 그러면 내가 display에 뿌려줄께하는 하는것이다. graphics system을 이용하려면 graphics system에 맞춰서 일해야 한다. network system도 마찬가지다. 내가 어떤 요청에 응답하겠다고, 응답함수를 만들고 호출하는게 아니라, 어떤 요청이 들어오면 framework는 말한다. 내가 알아서 보내줄테니까, 너는 받고 싶은 요청이 오면 어떤걸 할지 routes.rb에 작성만 해, 그러면 내가 너가 처리한 응답을 알아서 보내 줄께 하는 식이다. 보통 framework은 image를 매번 갱신해서 보여주는 animation을 위해서 graphics device를 사용한다거나, network의 매번 변하는 요청을 처리하는 경우 network i/o device를 처리할 때 framework를 사용해야 한다. 그림이나 animation이 아닌 단순한 문자열은 gpu를 사용하지 않고 바로 display만 사용하기 때문에, user code에서 print함수를 통해서 바로 display에 전달할 수 있다. 즉 framework를 사용하지 않아도 된다.
framework이 없다면, 고급 프로그램을 짜기 곤란하다. 내가 만든 program이 console i/o, memory,cpu만 사용한다면, 즉, 단순한 program이면 framework가 없어도 된다. 언어에서 제공되는 class, function,variable을 이용해서, 예를 들면, 덧셈,뻴셈,곱셈,나눗셈을 계산하고 print, file로 저장하는 program말이다. 여기에 thread를 사용할 수도 있고, 비동기 코드를 사용할 수도 있다. 하지만, 그럴듯한 프로그램을 만든다는 것은 조금 힘들다.
그럴듯한 프로그램은 framework를 사용하기 때문이다. 왜냐하면 그럴듯한 program은 거의 모두 I/O 필요하기 때문이다. 예를 들어보자. 내가 chatting program을 만들었다. 상대방과 연결해야 한다. 그렇게 하기위해서 while로 무한 loop를 만들고, 상대방으로 부터오는 모든 packet을 분석해서 분기하고, 또다시 packet을 만들어서 return해주는 작업을 user code에서 해줘야 한다. user code에서 network native api도 접근해야 그런 기능들을 사용할 수 있다. 그런데 framework가 있다면, packet을 만들고 return하는 부분이라던가, while로 무한 loop 돌고, 각각을 Thread로 처리하고 하는 머리 아픈 작업을 framework가 대신해준다.
GUI program을 만든다고 하자. 이것도 user code에서 timer loop를 사용해서 매초당 60번 그림을 그리고 native gpu interface api를 접근할 수 있어야 한다. 접근해야 gpu framebuffer에 그림을 놓을 수 있다.
이 모든 것을 framework가 해준다. 말이 길었는데, 여튼 program짜는데 있어서 framework는 없어선 안된다. 참고로, 대표적인 framework로 flutter, rails가 있다. 둘다 framework다. flutter framework는 UI framework다. graphics framework가 아닌 UI framework라고 부르는데, 여기에는 gpu와의 연결처리와 touch와 같은 user input event 관련 I/O를 합해서 UI framework라고 한다.