선생님, 개발을 잘하고 싶어요.

[생각] 왜 운영체제를 공부하나, 최근 공부하는 것들 본문

일상

[생각] 왜 운영체제를 공부하나, 최근 공부하는 것들

알고싶은 승민 2022. 10. 2. 21:48

러스트

왜 시작했나

안드로이드 개발자로 커리어를 쌓으며 항상 한 쪽에 불안감을 가지고 있다. 내가 지금까지 쌓은 커리어와 지식이 특정 플랫폼에만 종속되는 것은 아닐지, 소프트웨어 개발이라는 커다란 판에서 일회용 코더가 되는 것은 아닐지 하는 불안이다.

러스트는 이런 불안을 해소하기 위해 내가 찾은 공부 거리 중 하나였다. 예전에 웹 프론트 개발하는 친구에게 러스트라는 언어를 들었었고 C와 비슷한 런타임 성능을 내는 낮은 수준의 언어라는 내용이라 흥미를 자극했다.

지난 추석 시간이 남아서 러스트에 대해 본격적으로 알아보기 시작했는데 조금만 검색해봐도 양질의 학습 자료를 찾을 수 있었고, 이 언어는 공부할 만하겠다고 생각했다.

뭐가 재밌나

그리고 실제로 러스트에 다이브했다. 거의 3주 정도 시간을 들여서 러스트 The Book을 독파했다.

그리고 결론은? 러스트는 재밌다는 것

러스트는 왜 재밌을까? 첫 번째는 커다란 개발자 커뮤니티와 그로 인해 잘 정리된 문서를 뽑을 수 있을 것 같다. 내가 읽은 The Book을 포함해서 학습을 위한 양질의 문서가 정리되어있다.

학습은 당연히 책보다 실습이 중요하다. 하지만 실습이 중요하다고 책을 통한 깊은 이해가 도움 안되는 것은 아니다. 나같이 이미 다른 프로그래밍 언어 경험이 있는 경우는 특히나 책을 통해 러스트를 이해하는 데 부스트할 수 있는 좋은 기회가 될 수 있다.

재밌는 두 번째 이유는, 러스트가 해결하고자 하는 문제가 명확하고 그 해결책에서 배울 게 많기 때문이다.

C언어가 가진 장점이자 단점은 프로그래머가 직접 메모리를 힙 영역에 할당하고, 해제하는 작업을 수행해야 한다는 거다. 직접 메모리를 할당, 해제하므로 메모리 관리를 위한 별도의 런타임 오버해드가 없다는 장점을 누릴 수 있지만 실수로 메모리를 해제하지 않을 때 발생하는 많은 이슈를 직접 처리해야 하는 문제가 있다.

자바 진영은 이런 문제를 해결한 언어인데, 가비지컬렉터를 도입해서 프로그래머가 명시적으로 메모리를 해제하지 않아도 회수할 수 있게 만들어서 문제를 해결했다.

C, 자바만 학습해 본 입장에서 메모리 관리 문제를 해결하는 제3의 방법은 고민해본 적도 없었는데, 러스트라는 언어는 다른 해결책을 보여줬다.

자바의 가비지컬렉터는 개발자의 실수를 줄이는 장점은 있지만 런타임에 성능상 비용이 수반되는 단점이 있다. 러스트는 명시적 메모리 해제 문제를 해결하면서도 런타임 시점에 성능 문제를 해결하기 위해서 다른 해결책을 제시한 언어다. 소유권과 borrow의 개념이 러스트가 도입한 해결책이다. (자세한 내용은 생략)

그 외에도 러스트는 다양한 문제를 컴파일 타임에 해결하고자 노력한 언어이고 이 과정을 The Book 등 양질의 학습자료로 확인할 수 있다.

러스트가 기존에 있는 문제를 설명하고 그 해결책을 제시하는 방법에서 C 진영에서 문제가 되던 부분을 간접 학습할 수 있었고, 내가 평소에 얼마나 메모리 고민 없이 코딩을 해왔는지 알 수 있었다.

내가 자주 사용하는 라이브러리

내 개발의 문제점은 무엇인가

러스트를 학습하며 내가 자바 코드를 작성할 때 JVM이 뒤에서 마법처럼 해주는 작업의 메커니즘이 궁금해졌다. 프로그래머라는 사람이 작성하는 코드가 어떻게 동작하는지 설명하지 못하고 마법처럼 사용만 한다니 부끄러웠다.

그런데 생각해보니 내가 밥 먹듯이 사용하는 마법은 비단 JVM만 있는 게 아녔다. json parsing 라이브러리는 어떻게 동작하는지, http 통신을 위한 라이브러리는 어떻게 작동하는지, 모든 게 마법처럼 느껴졌다. 내가 자주 사용하는 기능도 기능명세만 보고, 사용법만 익히고 관습적으로 사용하고 있었다.

결론은? 나는 개발을 할 때 내 코드에 대한 자신감을 가질 수 없다. 내가 작성한 코드가 왜 꼭 필요한지 설명할 도리가 없다. json parsing이라는 문제를 해결하는 많은 라이브러리 중에 지금 내가 사용하는 라이브러리를 사용하는 이유는 무엇인지, 꼭 그것을 써야만 하는지와 같은 기준이 없었다.

내 코드 한줄 한줄에 당위성을 가지고 싶다. 어떤 일이 일어나고 어떤 트레이드 오프가 있는지 명료하게 설명하고 설득할 수 있었으면 좋겠다.

라이브러리 분석

시작은 당연 안드로이드 진영에서 자주 쓰이는 거의 표준에 가까운 라이브러리 분석부터 시작하면 좋겠다. 카테고리를 나누고 분석할 라이브러리 표를 만들었다.

첫 시작은 가장 많이 사용하는 Sqaure사의 라이브러리, 그 중에서도 다른 모든 Sqaure 라이브러리가 기반으로 사용하는 okio부터 시작했다.

어떤 문제를 해결하기 위한 라이브러리인지, 어떤 모듈 구조를 가지고 있는지, 문제 해결을 위해 어떤 자료구조와 알고리즘을 선택했는지 등 살펴볼 것이 많았다.

okio를 보면서 재밌었던 것은 okio가 java의 기본 InputStream의 문제인 데이터 복사를 해결하기 위해서 들고 온 해법이 rust에서 학습했던 소유권 개념이라는 점이다. 비싼 복사 대신 값싼 소유권 이전을 선택한 것이다. 비단 rust뿐 아니라 call by value니, call by reference니 하는 내용을 설계에 녹인 것처럼 느껴졌다.

또한 원본 byteArray를 소유권 이전한다는 개념을 구성하기 위해 커스텀 자료구조인 Segment를 만들었는데 이때 원형 링크드리스트로 구현한 게 눈에 띄었다. 자료구조 학습을 하면 가장 처음 나오는 자료구조인데 생각해보면 실제로 내가 그 구조를 실무 프로젝트에 도입해서 문제 해결한 경우는 없는 것 같다는 생각이 들었다. 직접 구현된 원형 링크드리스트가 어찌나 어색하게 보이던지 재밌었다.

보다 보니 설계는 크게 두 가지 부분으로 생각할 수 있을 것 같다.

하나는 실제 문제 해결을 위한 자료구조와 알고리즘이 위치한 내부 구현 설계,

나머지 하나는 그 코드의 사용자 편의성 있고 확장성 있는 인터페이스를 설계하는 API 설계다.

나는 한동안 API 설계에 대한 학습만 중요하다고 생각하고 있었는데 정작 자료구조와 알고리즘으로 실제로 동작하는 내부 구현 학습은 소홀히 했다는 점 알게 됐다.

알맹이가 없는데 껍데기 포장하는 방법만 학습하고 있으니, 내가 왜 공부는 하는데 남는 게 없다고 느꼈는지 이해가 되는 대목이다.

알맹이를 채우는 작업이 필요하다. 그리고 나는 그 알맹이를 채우는 과정을 즐기는 편이라는 걸 안다.

운영체제

자료구조 학습하기

링크드리스트가 무엇이냐, 해시맵이 무엇이냐 물어보면 잘 안다고는 할 수 없어도 기본적인 동작 방식은 설명할 수 있다. 하지만 그런 얕은 지식이 중요한 게 아니란 생각이 들었다. okio 라이브러리가 문제를 해결한 방법이 기술적으로 어려웠느냐면 아녔다. 이미 내가 알던 것들을 엮어서 구성한 것이다, 고로 각 자료구조에 대한 부분적 지식이 아니라 문제를 분석하고 해결하는데 적합한 자료구조를 선택 하고 개념을 직접 구현할 수 있는 경지에 올라야 한다고 생각했다.

그러기 위해서 당연 선결적으로 자료구조 학습이 잘되어있어야 한다고 봤다. 어떻게 자료구조를 학습할까 고민해보고 검색도 해보고 추천 자료도 알아봤다. 잘 정의된 자료구조를 맨땅부터 한땀 한땀 구현해보는 것은 당연히 가능하겠지만 학술적인 체크리스트 말고 좀 더 실용적인 접근이 필요하다고 느꼈다.

운영체제를 배우자

결국 실용적인 접근은 당연히 코드다. 실제 널리 쓰이는 프로젝트다. 이를 위한 자료는 생각보다 내 주변에 깔려있었다. 바로 오픈소스 프로젝트다. 정말 다양한 프로그램이 오픈소스로 깔려있고 잘 동작하고 있다. 그래서 분석할 만한 오픈소스를 좀 찾아봤다. 아까 했던 대로 라이브러리 분석도 그 출발점 될 수 있고 내가 사용하는 유틸리티성 프로젝트부터 시작해도 좋을 것이다.

하지만 이런 프로젝트들은 처음 진입할 때 분석이 어렵고 특정 도메인에 강하게 얽혀있었다. okhttp를 분석한다면 HTTP 포맷부터 시작해서 웹표준에 대한 깊은 이해가 수반되어야 한다. 물론 좋은 일이지만 자료구조와 알고리즘을 이해한다는 입장에서는 조금 떨어져 있었다.

더 생각을 이어가다가 운영체제에 다다랐다. 운영체제 도메인은 당연히 프로그래머라면 마주하게 되는 질문에 통찰력을 주는 것이고 (e.g. 스레드는 어떻게 동작할까? 프로그램은 어떻게 실행될까?) 정말 복잡한 문제를 해결하는 영역인 것이다. 운영체제의 특성상 극도로 높은 성능을 내야하고, 신뢰성 있어야 한다. 그러면서 잘 정리되고 연구된 것이다. 한마디로, 자료구조, 알고리즘 학습을 뛰어넘어 알맹이 충만한 학습을 위해서 보물 같은 필드인 것이다.

여기까지 조사하니 정말 운영체제를 알면 좋겠다는 생각이 들었다. 우선 내가 몸담고 있는 안드로이드 자체가 오픈소스 운영체제 아니던가? 운영체제를 깊게 학습하면 자연스레 안드로이드에 대한 이해를 높일 수 있을 것이고 더 재밌는 일들을 해볼 수 있을 것 같다. 또한 내가 맨날 사용하는 기계들은 모두 OS 위에서 동작하지 않는가? 그게 어떻게 실행되는지 그 원리를 이해하는 과정은 너무도 자명하게 지적 즐거움이 될 것이다.

다행히도 인터넷에 좋은 자료가 많았다.

OSTEP : https://pages.cs.wisc.edu/~remzi/OSTEP/

공룡책 : https://os-book.com/OS10/index.html

결론

나는 계획을 잘 못 세우는 편이다. 항상 즉각적인 보상을 원하는 경향이 있고 그래서 즉흥적인 선택을 하게 된다. 그래도 동시에 그 즉흥적인 선택이 내 성향과 맞고 흥분된다면 깊게 몰입하는 경향이 있다. 양날의 검 같은 것이다.

요즘에 정신 차려보니 OS를 공부하고 있더라 정말 재밌게 공부를 이어 나가고 있는데 누군가 물어보더라 왜 운영체제를 공부하냐고 순간 멍했다. 왜 이렇게 열심히 공부하고 있지? 분명히 맥락이 있었는데 기억이 안 나 그래서 대답은 “그냥 재밌어서”로 끝났다.

근대 대답한 이후 찝찝함이 남아있었다. 코드를 작성할 때 왜 그 라인이 있어야 하는지 명확한 이유를 대고 싶은 마음이 있는 개발자가 본인이 시간을 투자하며 “지금” 열심히 학습하는 걸 왜 학습해야 하는지 이유를 대지 못한다는 게 우습게 느껴졌다.

혹시 헛공부하고 있는 게 아닐까 걱정도 들었기에 그래서 생각을 정리해보았다. 그리고 생각을 정리하니 더 명확하다. 이 공부는 꼭 오래 할 것이다. 운영체제 공부가 내 지적 만족과 커리어를 위해서 좋은 투자라는 생각이 더욱 확고하게 든다.

참고자료

러스트 : https://doc.rust-lang.org/book/

okio : https://github.com/square/okio

OSTEP : https://pages.cs.wisc.edu/~remzi/OSTEP/

Comments