들어가면서
드디어! 5서클의 악명높은 컨테이너 과제를 성공적으로 마쳤다. 처음 이 과제를 마주했을 때에는 도대체 내게 무엇을 원하는 것인지 몰라서 절망한 순간들도 있었지만, 이렇게 과제를 다 마치고 나니 이 과제를 통해서 정말 많은 것들을 배웠던 것 같다. 이제는 42서울 과제 난이도 조정으로 인하여 이너서클의 필수과제가 아니게 되었지만, 옛날에 존재했던 이 컨테이너라는 과제가 도대체 무엇이었을지 궁금할 수 있는 카뎃분들과 내가 이 과제를 통해서 어떤 것들을 배웠는지 남기기 위해서 글로 흔적을 남겨본다.
컨테이너?
컨테이너라고 하면 모두들 어떤 것이 생각나는가? 대부분의 사람들은 부두에서 볼 수 있는 네모네모한 상자들을 생각해낼 것이다. 나는 그래도 프로그래머라고 도커를 가장 먼저 생각했다. 하지만, 이 과제는 도커 과제가 아니다. 이 과제에서 말하는 C++에 있는 STL의 컨테이너이다. 즉, 천재 프로그래머들이 이미 열심히 만들어둔 C++의 표준 자료구조형을 가르키고 있는 것이다. 문제가 가르키는 것이 명확하다는 것은 곧 내가 그것을 해야된다는 것이다. 그렇다 이 과제를 통과하기 위해서는 바로 그 엄청난 자료구조들을 모두 만들어야 한다.
과제를 간단하게 설명하면 아래와 같은 조건을 만족시켜야된다.
1. 사용할 수 있는 외부함수 : 거의 없다. 필요하면 직접만들어라
2. 사용하는 언어 : C++98 11이나 17에서 제공하는 아름다운 기능들은 모두 제한된다.
3. 만들어야되는 것 : Iterator, Vector, Stack, RedBlackTree, Map, Set
* 당연한 이야기지만 해당 컨테이너에 있는 모든 메소드를 구현해야한다.
4. 하면서 느낀점 : 선배 개발자님들 정말정말 감사합니다.. 저도 앞으로 받은만큼 기여하겠습니다...
과제를 마치기 위해서는 총 4개의 컨테이너를 만들어내야된다.
일반적으로는 구현하는 순서는 아래와 같은데, 실제로 나도 아래와 같은 순서로 구현했다.
1. std::vector를 이용하여 stack 제작 이후 enable if 등 필수 메타함수 제작
2. Iterator Traits와 iterator제작을 위해 필요한 필수적인 알고리즘 제작, pair등 map을 위해 필요한 요소 제작
3. RandomAccessIterator, Bidirecton Iterator , Reverse Iterator 제작
4. 자신만의 vector를 구현한 후 stack에 적용된 std::vector를 my::vector로 대체
5. RedBlackTree를 구현(구현과정에 나중에 map과 set에 사용될 수 있도록 설계 필요)
6. 제작된 Tree를 기반으로 map, set 구현
나 같은 경우 이 모든 과정에 소요된 시간은 공부 시간 포함 170시간 이상이 소요되었다. 공부를 하다보니 Template프로그래밍과 SFINE등등에 대해 정확히 어떻게 작동하는지 확인하기 위해 컴파일러를 뜯어보는 시간이 소요되었고, 특히 제네릭 프로그래밍이 어떻게 작동하는지 이해하기 위해서 시간이 더 소요된 것같다. 그렇게 약 14일의 과정을 통해 모든 구성요소를 제작했고, 1~2일의 테스트케이스 제작 및 확인 그리고 디버깅을 통해 과제를 완성할 수 있었다.
과제를 통해서 얻은 것들
'나를 죽이지 못하는 고통은 나를 강하게 만든다'라는 말이 있듯, 컨테이너도 나를 강하게 만들어주는 스트레스였다. 특히, 이번 컨테이너 과제는 남은 것들이 정말 많은 과제였는데 나는 이 과제를 통해 정말 많은 깨달음을 얻었기 때문이다. 일단 이번 과제를 통해 내가 대답할 수 있게 된 것들이 많아졌다. 그 중에 몇 가지 대표적인 것들을 써보자면 아래와 같다.
1. C++에서 컨테이너란 무엇인가?
- 컨테이너와 iterator와의 상관관계는 무엇인가?
- Template 프로그래밍이란 무엇이고 이는 어떻게 작동하는가?
- 템플릿 특수화는 어떻게 할 수 있고 어떻게 작동하는가? 우선순위는 어떻게 되는가?
- 오버로딩과 오버라이딩의 정확한 차이가 무엇인지 알고있는가?
- 왜 Iterator가 필요한가?
2. Generic Programming이란 무엇인가?
- 원시자료형을 쓰지않는 언어의 내부는 어떻게 작동하는가?
- SFINE란 무엇이고 무엇을 의미하는가? 알았다면 왜 그것이 필요한가?
- Container, Iterator, Algorithm간의 상관관계는 무엇이고 이렇게 만든 이유가 무엇인가?
- 컨테이너 과제를 통해서 알 수 있는 추상화란 무엇인가?
3. 시퀀스 컨테이너란 무엇이고 연관형 컨테이너는 무엇인가?
- 이 둘을 구분짓는 이유는 무엇인가?
- 시퀀스 컨테이너(Vector, Stack)은 어떤 자료구조형을 가지는가?
- 연관형 컨테이너(Map, Set)은 어떤 자료구조형을 가지는가?
- 그 둘이 가지는 자료구조가 만든 장단점은 어떤 것들이 있는가?
- 해당 컨테이너들이 가지고 있는 메소드들은 자료구조와 어떤 연관성이 있는가?
- Tree형 자료구조의 장점과 단점은 무엇인가?
- 컨테이너들의 메소드들은 어떻게 구현되어있는가?
- 각각 컨테이너는 어떤 상황에 사용해야되는가?
4. Iterator의 Traits란 무엇인가? 그것은 왜 제작되었고 어떻게 사용되는가?
5. RedBlackTree란 무엇인가?
- 다른 BST들과는 어떠한점이 다른가?
- 특히 DB에 많이 쓰는 B-Tree와는 무엇이 다른가?
- 이 트리의 성능은 어떠하고 어떤 특징을 가지는가?
- 이 트리의 삽입과 삭제는 어떤 과정을 통해서 작동하는가?
- 성능을 측정하는 빅 O의 계산은 어떻게 하고 왜 이것이 중요한가?
42서울 내에서 과제의 완성은 디펜스이다. 주어지는 평가지에 따라서 피 평가자는 평가자를 납득시킬 의무가 있는데, 나는 위의 질문을 하나하나 짚어가면서 평가자를 납득했다. 필요하다면 기본 컴파일러 코드를 보면서 설명했고, 예시가 필요한 부분은 미리 만들어둔 예시를 통해서 설명했다. 한 사람당 평가를 할 때 거의 90분 내외로 걸리다보니 힘들 때도 많았지만, 여러번 반복하면서 설명하다보니 마지막에 가서는 눈 감아도 개념을 설명할 수 있는 지경이 이르렀다.
컨테이너를 보내며
처음에는 과제의 막연함에 화가났고, 처음 참고하기 위해 들어간 gcc의 헤더파일들은 막막했으며, 쳐야하는 코드의 양에 답답함을 느꼈던 컨테이너라는 과제가 끝났다. 미운정이야 말로 인간이 느끼는 강한 정이라고 하지않는가? 나도 이 컨테이너라는 과제에 많이 정든 것같다. 이 과제가 이제 사라져 Deprecated된다는 것에 마음 한켠이 아쉽다. 내 뒷 기수도 이 고통을 맛봐야되는데..
그래도 나는 이 과제 덕분에 이제 헤더파일 보는 것이 두렵지 않게 되었다. 과제 덕분에 #include <vector>처럼 컴파일러가 제공하는 코드들은 이제 친숙하고, 또 덕분에 오픈소스 코드를 읽어도 더 이상 주눅들지 않을 수 있게 되었다. 그리고 가장 중요하게는, 앞으로 사용할 상위레벨 프로그래밍 언어가 어떻게 동작하는지에 대한 단초를 얻었다. 대학생 시절 많이 쓰던 Python의 자료구조형들은 어떻게 되어있을까 많이 궁금했었다. 그 궁금증은 42에 와서 원시 자료형을 주로 사용하다보니 더 커져갔는데, 이번 기회에 어느정도 단서를 찾은 것 같아서 행복하다.
물론, 이 과제를 통해서 얻을 수 있었던 것은 단초일 뿐이다. 이 단초를 어떻게 발전시켜서 내 것으로 만들지는 나의 몫이라고 생각한다. 나는 이 자신감을 바탕으로 앞으로 내가 주력할 언어인 JS와 TS의 코드 구조를 한번 살펴보려고 한다. 어차피 앞으로 많이 쓸 녀석이라면 어떻게 쓰는지만 아는 것이아니라 어떻게 작동하는지까지 알면 좋지 않겠는가?
2월의 성장 포인트, Container. 미운 녀석이지만 덕분에 많이 배우고, 많이 성장했다 고맙다
'프로젝트 > 42과제' 카테고리의 다른 글
[42서울] 인셉션을 마치고(Docker, LXC) (3) | 2023.03.04 |
---|