제목 : C 와 최소한의 Lib 로 알고리즘 풀어보기 도전
이 도전을 하는 계기
수많은 언어와 라이브러리들은 매우 간편하다.
수많은 언어들은 자체적인 GC(Garbage Collector) 를 갖추고, 특정 언어들은 자체적인 VM 을 갖춰서 실행한다.
이 과정에서 우리는 메모리 관리를 딱히 할 필요가 없으며, 수 많은 타입과 데이터셋에 대한 자체적인 라이브러리를 지원한다.
간편한 언어의 접근성과, 대중적인 라이브러리의 조합은 "프레임워크" 로 탄생했고, 비즈니스 논리에 집중 할 수 있게 해 주었다.
나는 대학교 재학 시절 C 언어를 배우고, Java 언어를 배웠으며, 웹 개발을 위해 JavaScript 를 접하게 되었다.
그리고 프로그래머스 풀스택 부트캠프를 통해 JavaScript 로 작성되는 백엔드 개발을 프로젝트로 수행했었다.
그러면, 잘하는 언어로 취업을 준비하는 것이 맞지 않나?**
나도 이 말에 전적으로 동의한다.
JavaScript(+ TypeScript) 를 잘하는 사람을 원하는 기업이 있으며,
현재 Tomcat 기반이나, Spring API 서버를 이용하는 회사는 Java 를 잘하는 사람을 뽑을 것이다.
특히나 복잡한 현대 세상에서, 확실한 Entity 가 아닌, 행동의 결과물로서 나오는 개념적인 데이터를
컴퓨터로 이식하는 과정에서, 비즈니스 논리에도 집중하기 힘든 세상이 되었다고 생각한다.
얼마나 다양하고 많은 비즈니스 논리가 존재하면,
AOP(관점 지향 프로그래밍) 라는 개념이 중요한 개념이 되었을지 상상이 되지 않는다.
왠만해서도 복잡한 엔터티들도 정규화하여 대중적인 MySQL, Oracle, MS SQL 과 같은
RDBMS(Relational Database Management System) 으로도 충분했을 텐데,
너무나 많은 메타데이터의 출현으로 인해, 카테고리를 딱히 정할 수가 없는 데이터들이 나오기 시작했다.
따라서, 빅 데이터의 중요성이 떠올랐고, 정확한 정규화와 무결성을 목적으로 하지 않는 NoSQL 이 각광받기 시작했다.
다시 돌아와서, "잘하는 언어로 프레임워크를 사용하여, 취업하는것이 맞지 않나?" 라는 의견에는 전적으로 동의한다.
그러나, 내가 여태까지 컴퓨터를 배울 때는
"이 방법론(언어, 라이브러리, 프로그래밍, 프로젝트 구조, 인프라 구조 등등) 을 사용하여 비즈니스를 구현한다"
였다.
그런데, 나는 이러한 방법론들을 이러한 문제들에 "왜?" 적용하는지 이해 할 수 없었다.
이전에 작성했던 나의 포트폴리오들과, 이력서를 살펴보며 나는 무엇에 집중했고, 부족했는지를 살펴보았다.
나의 문제는 이러했다.
- 특정 도메인에 파고들지 않고, 너무 다양한 도메인에 대한 프로그램을 제작했다.
- 하나의 언어에 매우 전문적이지 않다.
- 개발자 전국시대에서 내일 당장 투입할 수 있는 인력은 아니다.
- 내가 대학교 시절에 수행했던 창업에 대한 이야기를 써 놓았는데,
이는 회사 입장에서 creative 하게 보이지 않고, 통제하기 힘든 사람으로 보일 수도 있다. - 실제 클라이언트를 사이트로 유치 해 본 적이 없다.
- 현재 운영중인 사이트가 없다.
- AI API 를 이용한 프로그램이 존재하지 않는다.
이러한 단점을 지금 작성 해 보았는데, 이 중 몇가지는 이미 인지하고 있는 상태이기에, 최근에 진행했던 NestJS 프레임워크에 집중했었다.
이 NestJS 프레임워크를 공부하면서, 백엔드인 WAS 역할로서, Node.js 엔진 기반의 서버는 분명히 한계점에 빠르게 도달하기 마련이며,
대부분이 메타프로그래밍 방식으로 이루어진 NestJS 를 보며, 다른 라이브러리에 지나치게 의존하는 NestJS 의 특성상 기술적 한도도 명확하고,
많은 요청을 처리하기 위해 쓰레드 클러스터를 만들어 분배하거나, 컨테이너 서버 방식으로 여러대를 늘려 서버의 비용을 증가시키기 보단,
그 노력으로 컴파일 된 서버를 운용하는 것이 기술적 부채, 리소스 확장성, 최적화 면에서 압도적으로 유리하다고 생각했다.
이러한 분석적 시각을 다른 언어와 프레임워크에 적용하여 고도화 시킨다면, AI로 쉽게 대체 될 수 있는 프로토타입 WAS 를 만들지 않고,
유니크한 개발 엔지니어가 될 수 있을 것이란 생각에 다다랐다.
NestJS 를 공부하다가 어떤 생각이 들었길래?
나는 웹 개발 커뮤니티와, NPM 모듈의 거대함을 느끼고, 쉬운 언어로서 인식했다.
나는 웹 개발 자체보다는, 인프라와 백엔드에 좀 더 치중되어 있는 사람이다.
이게 굉장히 어색하다는 것을 나중에 알게 되었는데,
인프라와 백엔드에 관심이 있으면, Java, Go 와 같은 언어를 전문적으로 다뤄야 하는데,
NestJS 의 메타프로그래밍 방식의 프레임워크에 호기심을 가져
프로젝트 이후에 따로 깊이 공부를 하게 되었다.
그런데 중요한 것은, NestJS 는 주로 웹 개발과 백엔드 프로토타입을 개발하는 사람이 사용하는 프레임워크라는 것을 나중에 알게 되었다.
나는 NestJS 를 공부하면서, 이것이 왜, 무슨 이유로 사용되는지 알기 위해 Node.js 공부를 병행했다.
이 과정에서 단일 스레드에, 이벤트 기반 I/O 로 작동하는 Node.js 의 구조와,
단일 콜스택 스레드를 타파할 수 있는 방식 중 Worker
라는 기본 라이브러리를 알게 되었다.
이를 통해, 메인 스레드는 클라이언트의 비즈니스 논리에 집중하고,
방대한 계산이 필요한 논리는 만들어진 Worker
스레드에 넘겨 최적화했다.
이 과정에서, 나는 Spring 과 NestJS 간의 성능 차이를 보게 되었고,
NestJS 가 Node.js 베이스인 만큼, 메모리 사용량이 높으며, 속도가 느릴 수 밖에 없다는 것을 인지했다.
따라서, Worker
를 배우게 되었는데, 나는 더 나아가서 Worker
에 .wasm
(웹 어셈블리) 를 적용했다.
테스트에서 속도는 월등히 빨라졌다.
그러나, 나는 이 과정과 결과에서 엄청난 회의감을 느낄 수 밖에 없었다.
차라리 저 수준 언어와 라이브러리를 사용하는 것이 낫겠는데?
나는 웹 어셈블리를 Worker
이라는 새로운 스레드에 반영하는 과정에서,
AssemblyScript 를 사용하게 되었고, 이 언어는 마치 타입스크립트와 비슷하다.
그러나, 이 작성 방식은 개발자 사이에서 주된 방식은 아니며, 주로 웹 어셈블리 모듈(.wasm
) 은
C++ 이나 Rust 로 주로 작성되었다.
웹 어셈블리 모듈을 제작하는 수많은 예제들을 보면서,
내가 AssemblyScript 로 모듈을 작성하기 위해 설정하는 노력보다,
저 수준의 언어로 모듈을 작성하는 것이 훨씬 낫다는 생각을 했다.
그래도, JavaScript 와 TypeScript 가 가진 방대한 모듈과 접근성을 위해서라면,
언어가 어려워지기 보다는 좀 더 쉬워서 커뮤니티 크기를 유치하는 것이 더 유리하겠다는 생각이 들었다.
JavaScript 를 익히며 느낀 회의감이 왜 C 로 알고리즘을 푸는 것으로 이어지나?
나는 이전에 알고리즘을 풀 때, Java 로 해결했다. (정확히 java 11)
물론, 기업들이 알고리즘 테스트를 진행하기 때문에 시작하긴 했다.
이 과정에서, 입출력, 배열 관리, 인덱싱(색인), DP, 그리디, BFS, DFS, Set, Map, Binary Search, Tree 등등.. 을 사용하여 문제를 풀었다.
물론, 정렬 방법론에서 log_2 N 을 대부분 보장하는 Merge(병합 정렬), Heap(힙 정렬) 과 같은 정렬도 직접 구현했다.
위의 과정은 그냥 Arrays.sort(정렬할 배열)
하면 자동으로 해 준다. or Collections.sort(...)
그런데, 이 중 Set
, Map
에 대한 것을 java 의 기본 라이브러리인 java.util 에서 가져온다는 것에 집중했다.
Set 과 Map 자료구조 클래스는 왜 특정 메서드만 가지고 있는 것인지, 어떤 확장성을 가지고 있는지, 실제로 어떻게 작동했는지 궁금했다.
따라서, Set
, Map
을 직접 구현하며 재귀에 대한 추가적인 지식과,
레벨링이 2 이상 차이나지 않게 조절하도록 알고리즘을 만들었다. EX - LeftRotate, RightRotate
물론, JVM 이 메모리 관리를 수행하기 때문에, (Eden, Old 분류 덕분) 내가 직접 조절 할 필요는 없었지만,
실제로 Tree 의 구성과 관리, 어떤 자료구조(클래스) 가 필요한지, 속성이 필요한지,
이 상황에서 어떤 정렬이 효과적인지, 백준에서 각 문제별로 정렬 알고리즘의 메모리 사용량과 시간을 비교하며 문제를 풀었다.
특히, heap 정렬은 재귀적인 특성이 강하고, 매 랜덤 배열마다 하나의 재귀가 어느 깊이까지 갈지 모르기 때문에 log2N 을 충족하기 힘들어
시간과 메모리가 많이 소요될 것이라고 생각했는데, 가장 메모리와 시간을 적게 먹어서 놀랐던 경험이 있다.
요약하자면 : 나는 방법론 보다는, 이것이 어떻게 동작하고, 왜 사용해야 하는지에 집중했다.
내가 부트캠프에서 배우고, 프로젝트까지 진행했던 JS + TS 의 언어적 한계점과, Node.js 의 성능적 한계점을 알게 된 뒤,
나는 내가 배우고 있는 프레임워크 자체에 빨려들어가고 있다고 자각했다.
즉, 프레임워크가 편하여 이를 마치 언어처럼 배우고 있었다.
나는 빠르게 발전하는 것을 넘어, 지속적으로 변화하는 개발 트렌드에도 나 자신을 맞추기가 어렵다고 생각한다.
이것을 어떻게 해소 할 수 있는가? 를 지속적으로 고민했다.
그 결과로, 다양한 언어들이 참고했으며, 패러다임을 참고 한 곳, 바로 C 언어였다.
웹 개발을 하면 당연하게도 JavaScript 를 사용하겠지만, Was 환경에서 JS 를 사용할 수 밖에 없다면,
내가 직접 모듈을 저수준 언어로 개발하여 장착 할 수도 있겠다는 생각이 들었다.
그리고, C 를 사용하며 불편함을 느낄 텐데, 이러한 불편함은 내가 편한 언어를 사용하며 놓친 컴퓨터 지식이라고 생각하고,
더욱 공부하려고 한다.
사실 이미 C 언어에서 알고리즘 문제 1개를 풀었는데,
나는 scanf
대신에, fgets
를 사용하여 한 줄의 입력을 받았으며,
이를 토큰화 한 뒤, 숫자로 만들어서 계산하고,
이를 출력했다.
printf
는 fputs
로 할 수 있었는데,
숫자를 다시 문자로 바꾸는 과정까지 만들면 일단 300 줄이 넘어갈 것 같아서 다음 문제부터 구현하려고 한다.
'백준-단계별로 풀어보기' 카테고리의 다른 글
C 언어 - stdio.h 만 가지고 백준 문제 풀어본 결과 (2) | 2025.06.06 |
---|