Low Level 이해도를 높이는 방법
F-Lab : 상위 1% 개발자들의 멘토링
안녕하세요, F-Lab '자바 백엔드, 노드 백엔드, 게임 서버 과정' 멘토 Elkein(엘케인) 입니다. 저는 크래프톤, NHN, 넷마블 출신의 성장과 협업에 관심이 많고 즐거운 프로그래밍 속에 성장이 동반된다고 생각하는 개발자입니다.
개요
나의 취준 시기는 2000년대 초중반 이었다보니, 지금과 많이 달라졌다는 것을 안다. 그 당시가 오히려 CS 기초 무용론, Low Level이 필요 없어지는 시대가 올 것이라는 얘기가, 오히려 나의 취준 시기에 팽배했다는 점이다.
그와 함께 자바를 단기 교육으로 배우기만 해도, 충분히 경쟁력 있는 개발자가 될 수 있음에 대한 이야기가 나온 시기기도 하고, C언어를 배우지 않는 대학교 커리큘럼에 대한 논란이 있기도 했다. 시간이 좀 더 지나며 결국 Low Level에 대한 이해도가 중요하다는 것을 많은 사람이 공감한 시대로 돌아와 내가 취준생일 때 공부했던 것 보다 더 로우 레벨을 공부하는 스터디도 많고, 교육기관도 종종 있으며(교육 기관 중 Low Level 중시형 교육 기관은 상대적으로 적긴하지만 있긴 있다), 많은 면접 피드백으로 CS 기초와 Low Level 이해도에 대한 피드백을 받고 독학을 하는 경우도 꽤 보게 된다.
여기에 도움이 되고자, 내가 컴퓨터 과학 기초를 어떻게 배웠는지에 대한 이야기와, 지금도 꽤 유효한 다양한 컴퓨터 과학 기초를 실습하는 방법과, 고전이지만 로우 레벨 이해에도 도움이 되고 재밌는 책 몇권을 추천해보고자 한다.
내가 취업을 준비하며 읽은 책
1. 대학생을 위한 캠퍼스 C/C++
https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=200486
사실, 이 책은 PC 통신에서 강의가 돌아다니던 시절에 봤으나, 서점에서 동명의 책을 발견하고 구입해 아주 아주 유용하게 읽은 책이다. C언어의 메모리 개념을 이해를 돕는 좋은 내용이 많이 포함되어 있어서 아주 아주 좋았다. 이 책과 함께 포인터와 메모리 개념을 제대로 정립할 수 있었으며, 많은 C언어 입문자의 무덤에서 살아남을 수 있었다.
2. C로 배우는 알고리즘
* 1편 : https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=176870&start=slayer
* 2편 : https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=176871&start=slayer
내 취준생 시절인 2000년대 초, 중반엔 지금과 같은 방식의 코딩 테스트는 없었지만, 핸드 코딩, 페이퍼 코딩 테스트는 있었다. 그 당시, 핸드 코딩으로 퀵 정렬을 짤 수 있어야 한다는 얘기가 많았다. 내가 면접 보러 갔던, 또 다니게 됐던 많은 회사가 실제로 핸드 코딩을 시킨 경우가 많았고, 아무 정렬이나 짜보라는 경우나, LinkedList를 짜라고 하는 경우도 많았지만, 퀵 정렬도 적지 않았고, 혹시 몰라서 준비해둔 퀵 정렬이 큰 도움이 됐었다. 물론 퀵 정렬은 원리 자체는 심플한 편이고, 코딩이 좀 까다로운 편이라서이기도 하지만, 다른 더 쉬운 정렬이나 검색, 그래프 탐색 등을 통해서 자신감을 쌓을 수 있었다고 볼 수 있겠다. 이 두 권은 여전히 합리적인 선택인, 알고리즘 입문 서적이라고 봐도 무방하다.
3. 성공과 실패를 결정하는 1%의 CPU 구조와 원리
https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=423151
이 책을 대표적으로 설명한 이유가 있다. 어느 지식이 쌓이고, 유사 경험, 실습, 실무 경험 등이 시너지가 나기 시작하면 허들이 낮아지기 시작하지만, 그러한 시기가 되기 전까진 나는 무조건 쉬운 책을 읽어야 한다고 생각한다. 그리고, 사실 그러한 역량과 시기가 되어도 쉽게 설명한 책을 읽어서 개념을 잡고, 자신감도 얻고 난 뒤 좀 더 난도가 높은 책으로 넘어가는 방식을 권장한다. 쉬운 책은 절대 나쁜게 아니다. 쉽게 설명해준 책이 저항감과 두려움을 낮춰주는 긍정적 요소로 작용하길 바란다.
4. 해킹/파괴의 광학
https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=292169&start=slayer
해킹이라는 이름이 써있지만, 사실은 윈도우 시스템 프로그래밍 책이다. 또한, 나에겐 어셈블리어에 대한 저항감을 낮춰준 책이었다. 이 책이 온전히 설명해준건 아니지만 메시지 후킹을 통해 알아낼 수 있는 정보, 파일 포맷을 설명해주는데, 이를 통해 악성 코드가 심어질 수 있는 위치, 이에 대한 감지의 원리에 대해 떠올릴 수 있었고, 버퍼 오버 플로우가 왜 보안 취약점이 되는지, 이로 인해 있을 수 있는 사이드 이펙트, 다른 프로세스의 메모리를 열어보는 방법 (윈도우의 보안이 강해지면서 어렵거나, 불가능한 경우가 많다. 특히 관리자 권한으로 실행되지 못하면 쓸 수 없는 API나 방식이 많다), DLL 인젝션을 통한 권한 탈취 등에 대해서 알 수 있다.
네트워크와 암호화에 대한 관심을 가지게 도와줬는데, 페이지 수를 보면 알 듯 심도 있게 설명해주었다기 보다는, 대략의 개념을 설명해주는데 이를 바탕으로 다른 책들과 주제에 대한 관심사를 넓히기 좋은 책이었다.
5. C와 어셈블리어의 만남
https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=176935
위에 언급한 ‘해킹/파괴의 광학’ 을 통해서 저항감을 갖추고, 어셈블리어를 익혀서 C/C++ 어플리케이션 디버깅에 활용하고자 했다. 사실, 나의 커리어 초창기의 프로젝트 들은 C++이 주를 이루었고 inline assembly (C/C++ 코드안에 어셈블리어 코드를 탑재해 동작 시키는 작업이다.) 코드가 꽤 있었는데, 이러한 코드 분석과 이후 덤프 분석, 디버깅 등에서 아주 유용하게 써먹을 수 있었다.
6. OS 제작의 정석
https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=263760
나에겐 꿈이 있었다. 나만의 OS를 만들어보는 것. 결과론적으론 이 책이 아닌 다른 OS 제작 서적을 따라하기 + @ 정도만 한 수준이기에, 나만의 OS를 만드는 일은 결국 달성하지 못했고, 아직도 마음 한켠에 아쉬움으로 남아있지만, 이 책이 그 꿈을 갖게 해주었고, 이후에 나온 다양한 OS 제작 관련 서적이 도움이 됐다.
OS 제작에 관련된 책은 현재도 꽤 꾸준히 나오고 있는데, 이러한 책을 통해서 익혀야 할 것은 OS의 원리 이해라고 생각한다. 혹시나 궁금해하실 분들을 위해서 OS 관련 서적 몇권을 더 추가로 기재하도록 하겠다.
다양한 컴퓨터 과학 기초 실습 주제
멘토링을 진행하면서 멘티 분들과의 대화에서 컴퓨터 과학 기초에 대한 니즈를 느끼신 분들이 많았는데, 그 중에서도 특히 실습을 어떻게 할지 몰라 이론과 실습의 시너지를 내지 못하신 케이스가 많았다.
그래서 몇가지 컴퓨터 과학 기초를 실습 할 수 있는 주제를 공유해보도록 하겠다.
중요한 것은, 이론과 실습은 시너지가 나야 한다는 점이고, 이론만 파고 들어서도, 실습이나 샘플 프로젝트만 돌려봐서도 잘 와 닿기 어렵다는 점이다. 이 점만 유의해서 실습과 이론을 병행 했으면 좋겠다.
0. 성능 개념 잡기
아래 모든 실습에서 대입해보면 좋은 주제다. 자료구조의 선택이 적절했는지, 그리고 자료구조를 잘 고르는 것이 가져다 주는 유의미한 차이, 그리고 그것을 확인, 증명하는 방법에 대한 이해를 높인다면 컴퓨터 과학 기초와 로우 레벨의 중요성을 더 잘 알 수 있게 될 것이다.
적절한 자료구조 사용했는지 판단
- 1초에 천만번 연산이라는 가정
- 데이터 건수가 작으면 대충 골라도 문제 없음
데이터 건수가 많으면 시간 복잡도 고려
- 시간 복잡도만 보지 말고, 데이터의 분포나 갯수, 상태 (정렬 상태 등)를 반드시 고민해야 한다.
- 데이터 개수를 보고 적절한 시간 복잡도의 알고리즘 선택
- 메모나 드로잉을 바탕으로 알고리즘을 먼저 풀어보고 코딩해라
- 자료구조와 알고리즘에 익숙하지 않을 경우에는 그림 그려가면서 과정을 숙지하는 것도 아주 유용하다.
- 수행 횟수 역시 (로깅이 아주 큰 비용이긴 하지만), 로깅이나 카운팅 등을 통해서 명확히 확인하다보면 시간 복잡도의 개념이나, 수행 횟수 등에 대해서 조금 더 감을 잡기 좋아진다.
1. DB 원리 이해하기
- 토큰화하여 저장, 검색
- or 조건, and 조건에 따른 데이터 검색
- 태그 입력 된 것을 조건으로 검색
- or 조건, and 조건에 따른 데이터 검색
- 데이터를 파일로 저장, 불러오기, 삭제, 갱신 하는 소형 파일 DB 만들기
- 멀티 스레드 실습 이후
- 풀 텍스트 서치
- 큰 문서가 존재한다고 가정
- MD 구문 별로 파싱한다고 가정
- 문자열이 포함되는 태그를 추출
- 간단한 파일 시스템 구현
- 간단한 파일 시스템을 모델링하고 파일과 디렉터리를 관리하는 프로그램을 개발
- 파일과 디렉터리 생성, 삭제, 읽기, 쓰기 등의 기능을 구현하며, 간단한 할당 방법 (연속 할당, 연결 할당 등) 을 이해하기
2. 멀티 스레드
- 스레드 10000개 만들기
- 스레드 1개당 메모리
- CPU 사용률
- 스레드 Sleep이 없다면, 어떤 일이 벌어지는지 체감
- 스레드 100개가 하나의 변수 접근하기
- 값의 결과
- 특정 스레드에서 메시지 처리기 만들어보기 (Worker)
- 안전하게 동기화
- 성능 개선해보기
- 가상 스레드 직접 만들어보기
3. 메모리
- 메모리 할당 해제
- 특정 사이즈의 메모리 할당/해제 반복
- 어느 시점에 느려지는가?
- 메모리 단편화
- 메모리 풀
- 특정 사이즈의 메모리 할당/해제 반복
- 메모리 단편화 발생 X
- 다양한 사이즈의 메모리 할당/해제 반복
- 이젠 메모리 풀이 관리하는 메모리의 단편화?
- 이에 대한 개선안 및 구현
- 단편화가 발생하지 않는가?
- 메모리 접근 비교
- 변수 접근 인접 메모리와 먼 거리 접근
- 예를 들어, 연속된 메모리 접근(배열 순서대로)과, 끝에서 끝을 반복하며 접근했을 때의 성능 비교
- 혹은, 2차원 배열에서 열 단위 / 행 단위로 순차 접근
- 메모리 관리 시뮬레이션
- 간단한 가상 메모리 시스템을 시뮬레이션하는 프로그램을 개발합니다.
- 프로세스의 주소 공간과 물리적 메모리를 모델링하고, 페이지 교체 알고리즘('LRU', 'FIFO' 등)을 구현하여 페이지 부재를 시뮬레이션
4. 운영체제
- 간단한 스케줄러 구현
- 간단한 프로세스 스케줄링 시뮬레이터 만들어 보기.
- 프로세스들의 도착 시간, 실행 시간 등을 입력받아 다양한 스케줄링 알고리즘 (FCFS, Round Robin 등) 을 구현하고 시뮬레이션
- 프로세스 통신 시뮬레이션
- 프로세스 간의 통신과 동기화 메커니즘을 시뮬레이션
- 간단한 IPC (Inter-Process Communication) 메커니즘을 구현하고, 뮤텍스나 세마포어와 같은 동기화 도구를 모델링
- 부팅 로더 또는 간단한 커널
- 간단한 부팅 로더나 초기 커널을 개발하여 실행할 수 있는 형태로 만들어본다.
- 컴퓨터 부팅 시에 메모리 초기화, 간단한 출력 등을 수행해보며 운영체제의 부팅 프로세스에 대한 이해도를 높인다.
- 커맨드 라인 셸
- 간단한 커맨드 라인 인터페이스를 개발.
- 사용자의 명령어 입력을 받고 해당 명령어를 실행하는 기능을 구현하여 프로세스 생성, 파일 입출력, 기본적인 명령어 실행 등을 만들면서 이해도를 높인다.
5. 네트워크 어플리케이션
- TCP 소켓 채팅 서버 만들기
- 동일한 패킷 구조 (프로토콜)로 소통하는, TCP 소켓 클라이언트/서버를 짝으로 만들고, 콘솔로 입력한 텍스트를 주고 받는 채팅 서버를 만들어 본다.
- 이를 통해 TCP 소켓을 통한 통신 기초를 이해하게 된다.
- 웹 서버 만들기
- TCP 소켓으로 HTTP 서버를 만들어보면서, 스프링의 원리와 개념 습득
- UDP 채팅 프로그램 만들기
- UDP를 통한 비연결성 통신 기능을 개발
- Reliable UDP 채팅 프로그램 만들기
- UDP 소켓에 신뢰성을 더한 Reliable UDP 채팅 프로그램을 만들기
- 이 과정에서 TCP가 신뢰성을 보장하기 위해 어떠한 많은 요구 사항을 충족 시키면서 동작하는지를 배우게 됨
- 패킷 스니퍼
- 패킷을 캡쳐하고, 해당 패킷의 정보를 읽어오는 프로그램을 만들기
- 이로 인해 HTTPS가 왜 나왔으며, 패킷의 정보를 손쉽게 열어볼 수 있었던 과거의 네트워크 보안에 이슈, HTTP 프로토콜이 왜 위험한지를 이해
- Ping
- ICMP(Internet Control Message Protocol)을 사용하여 호스트의 응답 시간을 측정하는 간단한 “ping” 프로그램을 구현해보기.
- 해당 프로그램은 호스트로 ICMP 에코 요청을 보내고, 응답 시간을 측정하여 네트워크의 상태를 확인할 수 있습니다. 이를 통해 ICMP 프로토콜과 시간 측정에 대한 이해를 높일 수 있음
- 파일 업로드
- 파일 업로드 서버를 만들어 보시면서, 파일을 핸들링 하고, 파일의 시작과 끝을 감지해서 완성된 파일을 만들어내는 방법 혹은 재전송 등에 대한 예외처리도 가능하면 시도
- ARP 스푸핑 방지 도구: ARP(Address Resolution Protocol)
- 스푸핑 공격을 탐지하고 방지하기 위한 도구를 개발하는 프로젝트
- 네트워크 내의 호스트들 간의 ARP 요청 및 응답을 모니터링하고, 이상한 동작을 탐지하여 ARP 스푸핑을 차단하거나 경고하는 기능을 구현
- UDP 기반 DNS 쿼리 프로그램
- DNS(Domain Name System) 서버에 UDP를 사용하여 도메인 이름에 대한 IP 주소를 조회하는 프로그램을 만들어 본다.
- 사용자로부터 도메인 이름을 입력받아 DNS 서버에 UDP로 쿼리를 보내고, 서버로부터 응답을 받아 해당 도메인의 IP 주소를 획득하는 과정을 이해할 수 있다.
- HTTP 요청 분석 도구
- 주어진 URL에서 HTTP 요청을 분석하고 필요한 정보를 추출하는 도구를 개발한다.
- URL에서 호스트명, 포트, 경로, 쿼리 매개변수 등을 추출하고, 이를 통해 주어진 URL이 어떤 웹 서버와 어떤 자원을 요청하는지 분석할 수 있다.
- Java로 Netty 사용한 채팅 서버
- WebFlux 내부 패킷 처리의 기본 엔진으로써 이용되는 Netty를 이용한 패킷 송수신 처리를 직접 구현
- 패킷 처리를 어떤 구조로 구성하느냐에 따라서, 성능 차이를 체감하고, 이를 바탕으로 고성능 웹프레임워크에 대한 이해도와 MQ에 대한 이해도를 높이며, 비동기 이해도도 같이 높이기
- Java로 Akka 사용하기
- Actor 기반 모델 어플리케이션을 작성하면서, 동시성 처리의 색다른 메커니즘을 경험
- Netty를 써서 구현했던 서버와, Akka를 이용한 서버와의 성능 차이, 블러킹 포인트 차이 등을 통해서 비동기와 멀티 스레드 이해도를 새로운 방식으로 폭과 깊이를 늘리는 계기로 삼는 것을 의도한다
실습에 대해서
위에 언급한대로 원리가 궁금했던 주제나, 분석했던 동작들을 구현해보는 것도 좋다. 중요한 것은, 어떠한 실습을 선택하더라도, 어떠한 이해도를 높이기 위해서 선택했는지가 명확할 수록 좋다는 점이다.
마치며
컴퓨터 과학 기초는 재밌다. 다양한 부분에 이해도가 높을 수록 시너지가 나기 시작한다. 동작 원리가 이해되고, 이상 현상이 왜 그런지 이해가 잘 될 수록 자신감도 붙고, 재밌어 질 수 있는 부분이다. 그러기 위해서는 Low Level의 필요성에 대해서 체감하는 것이 중요하고, 이 글이 그러한 계기에 도움이 되었으면 하는 바램이다.
이 컨텐츠는 F-Lab의 고유 자산으로 상업적인 목적의 복사 및 배포를 금합니다.