시리

SIRINI`s Blog

web always win!
나의 미니 PC 홈서버 활용기
0

2025-01-10

10 min read

나의 미니 PC 홈서버 활용기

지금은 이 곳 tsboard.dev 웹사이트가 카페24의 가상 서버 호스팅을 이용하고 있습니다만, 처음부터 호스팅을 이용하진 않았습니다. 처음에는 N100 cpu가 탑재된 알리/테무 발 미니 PC를 싸게 구매해서 ASUS 공유기에 물려준 후 포트포워딩, DDNS를 활용하여 홈서버로 운영을 했었죠. 그러면서 다른 사진 커뮤니티 서비스도 올리고 하다가 하필이면 긱뉴스(Geek News)에서 유입되는 트래픽이 많았던 날 접속 장애를 일으키는 바람에 결국 호스팅을 이용하게 되었습니다.지금도 사실 접속 장애 문제가 가끔 있지만, 대용량의 저장 공간이 필요한 사진 커뮤니티를 차마 호스팅까지 구매해서 운영할 용기가 나지 않아서 계속 홈서버를 운영하고 있습니다. 그러면서 문득, 이 활용기를 공유하면 어떨까 싶어서 글을 남겨봅니다.왜 미니 PC를 구매했나?미니 PC는 인텔의 저전력 CPU인 N100의 가성비에 기반하여 지금까지도 꾸준히 주목을 받고 있습니다. 지금 제가 사용하고 있는 맥미니도 미니 PC 범주에 들어가죠. 예전과 달리 지금의 미니 PC는 성능도 훌륭하고, 전성비도 좋은데다 가격도 나름 합리적 입니다. 맥미니는 옵션을 올리기 시작하면 가성비라는 말이 쏙 들어가지만, 적어도 깡통 기준으로는 가성비가 맞습니다.서버라면 우선 24시간 동작을 해야 하고, 집에서 구동한다면 아무래도 부피가 작은게 좋죠. 그렇다보니 자연스럽게 저전력과 작은 폼팩터를 찾게 되었고 마침 중국에서 불어온 N100의 열풍에 탑승하여 Beelink MINI S12 PRO를 구매했습니다. (광고 아닙니다!) 인텔이 해당 CPU가 인기 많을 걸 알았는지, 메모리 상한을 16GB로 잡은 것이 조금 아쉬웠지만, 어차피 Ubuntu Linux (server) OS를 설치해서 사용하니까 메모리도 크게 제약이 있는 건 아니었습니다. (참고로 코어는 저전력 코어로 총 4개입니다)지금은 해당 모델보다 좀 더 고사양의 Genmachine RYZEN cpu 탑재 모델을 사용하면서 메모리도 32GB까지 올려두었습니다만, 그 때나 지금이나 미니 PC의 역할은 변함 없습니다. 여전히 집안 내부의 스토리지 허브 같은 역할도 하면서, 사진 관련 커뮤니티 사이트를 (가끔 접속 장애를 일으키며) 운영하는 중입니다. 그리고 외부에서 급하게 코드를 수정해야 할 때 code-server 도 활용하면서 전천후 개발 서버 및 취미 서비스를 운영중입니다.홈서버, 어떻게 구성하는걸까?홈서버라고 말하면 뭔가 막연하게 만들기 어렵지 않나? 생각하실 수도 있는데, 실제로는 그렇게 어렵진 않습니다. 물론 잘 운영하는 건 어렵지만, 시작하는 건 쉽다고도 할 수 있지요. Namecheap 같은 곳에서 도메인을 구매한 다음에, 내 공유기에서 설정한 DDNS까지 오기만 하면 거의 절반은 성공한 셈입니다. 추가로 해야할 건 포트 포워딩인데, 이건 공유기 설정에서 쉽게 조정할 수 있습니다.대략적인 구성 방식은 아래와 같습니다.웹호스팅이나 AWS같은 클라우드 서비스를 이용하면 없어도 되는 과정 2가지가 추가되는데, 중앙에 있는 DDNS 그리고 내 집 공유기의 포트 포워딩입니다. DDNS 설정은 유/무료 서비스들이 많이 있습니다만, 저는 개인적으로 공유기 제조사에서 제공하는 서비스를 추천드립니다. KT같은 망 사업자는 주기적으로 각 가정에 할당한 IP주소들을 필요에 따라 바꾸는데, 공유기가 이를 감지해서 자기네 DDNS 서비스에 갱신을 해줄 수 있기 때문에 관리가 좀 더 편하거든요. (물론 공유기 제조사의 DDNS 서비스가 안정적이냐? 하는 것과는 별개입니다만)DDNS를 공유기 제조사 서비스로 하겠다고 하면, DDNS와 포트 포워딩 모두 공유기 설정화면에서 진행 할 수 있습니다. 각 제조사마다 WAN 같은 메뉴에서 설정할 수 있게 해두었는데, 용어가 좀 생소할 수는 있어도 설정해야 하는 내용은 쉽습니다. 저는 ASUS 공유기를 주로 사용하고 있어서 WAN 항목의 가상 서버 / 포트 포워딩 메뉴와 DDNS 메뉴에 필요한 설정들을 해두었는데, 위에 설명이 잘 되어 있어서 설명대로 추가하면 됩니다.내 집 방구석에서 돌아가고 있는 미니 PC까지 사이트 접속 요청이 오는데 꽤나 많은 과정들이 있지만, 어쨌든 이 과정 자체는 대게의 경우 잘 됩니다. 여러분의 홈서버에 올려진 서비스를 이용해 보고자 하는 방문객은 여러분이 구매한 도메인만 보이니까, 뒤의 복잡한 접속 과정은 보이지도 않고 알 필요도 없지요. 또한 조금 느리게 접속되는 것 정도야 큰 문제는 아닐 겁니다. 홈서버 운영의 어려운 점은?위의 설명에는 생략된 부분들이 많습니다. 예를 들어 구매한 도메인으로 CNAME 설정을 어떻게 해야 DDNS에 등록한 도메인으로 올 수 있는가? 같은 부분이 되겠죠. (이 부분은 정말 쉽습니다. 검색하면 나오니까요.) 하지만 가장 많이 생략된 부분은 트러블슈팅이 되겠습니다.일단 여러분의 미니 PC는 집 안에서 전기를 먹으면서 일을 하고 있습니다. 그 말은, 저희 집처럼 별도의 정전 방지 시스템이 준비되어 있지 않다는 것이죠. 대부분은 다음 번에 켰을 때 문제 없이 다시 서비스를 운영할 수 있겠지만, 운이 나쁘면 어떨까요? DB가 깨지거나 잘 되던 서비스가 무슨 이유에서인지 잘 안되는 등의 상상도 하기 싫은 문제가 발생하게 됩니다. 할 수 있는 게 많진 않은데, 고가의 멀티탭에 전원 선을 꽂아두는 것 정도가 되겠네요.더 큰 문제는 전원 뿐만 아니라 공유기 자체도 24시간 혹사 당하는 기기다보니 어쩌다 동작이 느려지거나 요청이 제대로 전달되지 않는 문제가 왕왕 발생합니다. 때문에 더 환장하는 건 내 서비스가 현재 제대로 운영되고 있는지 아닌지를 수시로 확인해야 한다는 점이죠. 설령 접속 장애를 알아차린다 하더라도, 바로 해결하기 어려운 순간들이 많다는 점이 가장 큰 문제입니다.마지막으로 사용하는 DDNS의 접속 장애도 고려해야 합니다. 제가 사용하고 있는 ASUS의 DDNS는 접속 장애가 생각보다 자주 있습니다. 이게 정말 환장하는게, DDNS는 제가 운영하는 게 아니다 보니까 ASUS같은 공유기 제조사에서 별도로 조치를 취하기 전까지는 할 수 있는 게 없다는 점입니다. 내 서비스가 멀쩡하게 잘 띄워져 있다고 해도 이 경우에는 손가락만 빨 수 밖에 없습니다.홈서버 운영, 그럼에도 권하는 이유는?여러 어려움과 예상치 못한 장애 상황에도 불구하고, 홈서버 운영에는 몇가지 장점이 있습니다. 일단 가장 큰 장점은 낮은 하드웨어 가격으로 비교적 높은 성능을 확보할 수 있다는 점입니다. 특히 용량 문제를 언급하지 않을 수 없는데, 저의 경우 취미가 사진이다보니 사이즈가 큰 사진 원본들을 보관하기 위해서라도 2TB NVMe 같은 게 간절했습니다. 만약 클라우드 등의 서버를 이용한다면 어쩔 수 없이 원본 사진은 삭제하고, 사진도 최대한 압축해서 보관해야만 하겠죠. 홈서버는 그럴 필요가 없습니다. 필요하면 내가 직접 스토리지를 추가하면 되니까요.다음으로는 내가 필요로하는 라이브러리나 운영체제등을 좀 더 자유롭게 선택할 수 있다는 점입니다. 물론 요즘에는 도커도 잘 되고 가상 서버 같은 경우에도 내가 필요로 하는 대부분이 문제 없이 지원되지만, 그럼에도 본인만의 필요에 의해 희귀한 라이브러리를 써야 한다거나 혹은 특정 하드웨어 부품이 요구되는 상황이 있을 수도 있으니까요. Ubuntu server 말고 전혀 다른 리눅스 배포판을 써보고 싶다거나 할 경우 언제든지 그렇게 해볼 수 있습니다.마지막으로, 접속 장애가 왕왕 생기긴 하지만 그럼에도 대부분의 시간 동안은 예상 외로 제대로 동작합니다. 미니 PC를 24시간 365일 구동한다고 해서 전기세가 많이 나오냐? 하면 꼭 그렇지도 않구요. (한 달 5천원 미만으로 보시면 됩니다) 예상 외로 잘 동작하고, 운영 비용도 동등 사양의 서버 호스팅이나 클라우드에 비해 말도 안되게 저렴합니다. 미니 PC 가격이야 좋은 운동화 한켤레 수준이니 말 다했죠. 홈서버를 운영하면서 저의 경우에는 code-server를 설치해두고 급하게 외부에서 컴퓨터 없이 작업해야 할 때도 유용하게 사용했습니다. 삼성의 DeX와 크롬 브라우저, 그리고 홈서버의 code-server 데몬이 함께 있다면 어디서든 개발이 가능해집니다. (아, 물론 모니터 키보드 마우스는 별도입니다 ㅎㅎ) 사실상 개발용 서버를 겸하게 되는데, 오래 걸리는 컴파일 작업을 미리 걸어두고 싶다거나 할 경우에는 그냥 스마트폰에서 SSH로 접속한 다음 작업을 시켜 놓으면 되니까 편리함이 이루 말 할 수가 없습니다. (가끔 접속 장애가 날 때는 화딱지가 나지만요!)여러분의 집에서도 홈서버가 함께하길 바라며저의 경우 책상 밑 한 켠에 지금 이 순간에도 미니 PC가 RGB를 휘날리며 열심히 팬을 돌리고 있습니다. 없을 때는 몰랐는데, 생기고 나서는 이 녀석을 여기저기 활용해보고 싶어서 근질근질 합니다. 비록 TSBOARD 사이트는 접속 장애가 없길 바라는 마음에 호스팅 업체로 이사를 보냈지만, 여전히 남아있는 사진 커뮤니티는 지금도 조용히 운영이 되고 있습니다. 접속 장애 상황을 만날 때마다 그걸 해결하는 과정에서 노하우가 쌓이는 상황이라 이제는 즐기면서 장애를 해결해가며 운영중입니다. 이 글을 읽어주신 분들 중에서, 나도 홈서버를 운영해 볼 수 있을까? 하고 고민하는 분들이 계시다면 흔쾌히 한 번 도전해 보시라고 권해보고 싶습니다. 막상 해보면 별 거 아니고, GPT 선생님과 함께라면 한 두시간 정도면 완성 하실 수 있습니다. 도전해 보시다가 혹시 막히시는 분들은 댓글 남겨주시면 GPT 선생님 정도는 아니지만 그래도 함께 고민해 보겠습니다. 마지막으로 제가 (홈서버에서) 운영중인 사진 커뮤니티는 https://sensta.me 주소로 방문해 보실 수 있습니다. 제가 실수로 멀티탭 전원 버튼을 발로 누르거나 랜선을 건드리지 않았다면, 접속이 되실 겁니다. ㅎㅎ 쓰다보니 또 길어졌는데, 읽어주셔서 감사합니다!
시리시리니
읽어 보기
JS 월드에서 GO 월드로 이사한 후기
0
TSBOARD를 개발하면서 여러 도전들이 저를 기다리고 있었지만, 이번 백엔드 교체가 어쩌면 지금까지의 도전들 중 가장 험난하고도 다이나믹한 도전이 아니었나 생각합니다. 저의 도전기가 또 다른 누군가의 모험심을 자극시켜 줄 수 있다면 좋겠다는 생각으로 (조금 졸린 와중입니다만 ㅎㅎ) 두서 없이 이것 저것 기록의 파편들을 남겨보고자 합니다.새로운 언어는 어떻게 배우는가 이 곳에서도 언급한 적이 있었지만, 저에게 있어 웹은 곧 PHP이고, PHP가 곧 웹개발을 뜻했습니다. 이제는 10년도 더 된 이야기 입니다만, 제가 처음 웹 프로그래밍이라는 걸 접했던 때는 제로보드4가 웹 세상을 지배하고 있던 때였고, 저는 그 때 스킨 같은 걸 만들어보면서 이것 저것 만드는 재미로 PHP4 라는 희대의 스크립트 언어를 배웠습니다. 당시에 사용했던 자바스크립트는 jQuery 의 다른 말이었기 때문에 jQuery도 필요에 의해 조금 배워서 썼던 때였네요.당시에는 구글링이 곧 프로그래밍이었습니다. 스택오버플로우와 누군가의 블로그를 구글링으로 찾아가면서 궁금한 걸 해결해가는 과정이 저에게 있어 새로운 언어나 라이브러리를 배우는 과정이었습니다. 그러다가 직장인이 되고, 필요에 의해서 C++을 만지기 시작하면서 회사에서 제공하는 교육들을 통해 조금쯤은 더 체계적으로 새로운 언어나 프레임워크에 대해서 익혔던 것 같네요.이번 TSBOARD의 새로운 백엔드는 고(Go) 언어로 작성되어 있습니다. 이전에 단 한 번도 써본 적이 없는 언어인데, 이번에는 어떻게 배웠을까요? 이번에는 책을 사거나 누군가의 블로그들을 구글링하거나 혹은 동영상 강의를 듣지 않았습니다. TSBOARD를 시작할 때는 그래도 패스트캠퍼스와 같은 동영상 강의 플랫폼에서 Vue 와 같은 프레임워크를 어떻게 쓰는지 등을 배웠었는데, 이번에는 아예 그런 과정도 없었습니다. 그저, ChatGPT를 옆에 켜두고, 처음부터 언어의 특징에 대해서 물어보고 제가 기존에 익혔던 언어와 유사점과 차이점을 계속 물어보면서 예제 코드를 받아보고, 제가 작성한 코드에 어떤 문제가 있는지 검토를 부탁하는 식으로 개발을 진행했습니다. 기존에 책이나 블로그 등을 통해서 학습하는 방식에 비해서, 효율성이 일단 두말 할 나위 없이 좋아졌고 이해가 더 잘되었습니다. 구글링 조차도 이제는 LLM이 대신 해주니까 새로운 언어를 배우는데 있어서 학습이 문제가 되거나 하진 않았습니다. 지금 시대에 태어났더라면 프로그래밍을 더 잘했을텐데 하는 아쉬움까지 들 정도입니다. ㅎㅎ만약 새로운 언어를 배우는게 이전처럼 많은 시간과 노력을 요구했거나, 제가 그런 어려움을 극복할 정도의 필요를 느끼지 못했더라면 이번 백엔드 교체는 아마도 상당히 미뤄졌거나 어쩌면 불가능 했을 겁니다. 다행히도 GPT 덕분에 새로운 언어를 배워서 써야 한다는 부담은 적었고, 어쩌면 조금 만만하게(?) 생각할 수 있었던 것 같습니다. 물론 실전에 투입되고보니 결코 만만치 않았다는 점은 지나고보니 깨달은 것이지만요.고(Go) 언어, 대체 어떤 언어인가 아직 고(Go)라는 언어를 그렇게 오랜 기간동안 사용해보진 않아서, 솔직하게 말씀드리면 잘 모르겠습니다. 겉보기에는 더할 나위 없이 심플한데다 고루틴이라는 막강한 동시성 제어까지 만능 언어처럼 느껴지기도 하는데, 일단 써보면 꼭 그렇진 않다는 걸 금방 알게 됩니다. 그러고보니 일전에 긱뉴스에서 Go vs Bun 비교(https://tsboard.dev/blog/sirini/41)하는 내용의 이 곳 블로그 글을 요약해서 공개한 적이 있었는데, 그 때 어떤 고 언어 사용자분께서 자칫 Go 언어에 대한 잘못된 편견이나 선입견을 줄 수 있다고 지적해주신 게 생각이 나네요. 어떤 마음으로 의견을 전해 주셨는지 이해가 되는 한 편, 그럼에도 어디까지나 도구로서의 언어는 목적에 맞게 평가되어야 한다는 생각이 그럼에도 들었습니다. 제가 배우고 사용해보면서 느낀 고 언어는 정말 절제된 언어라는 점이었습니다. 변수명도 길지 않고, 명시적으로 무언가를 거창하게 하지 않습니다. 반복문, 타입 정의 등은 모두 키워드가 하나이고 그 마저도 사용 방식이 정해져 있습니다. 처음 접하면 좀 이상하다 싶은 건 인터페이스 정도인데, 이제는 좀 적응이 되었습니다. 포인터 같은 건 기존에 C 계열 언어를 써보면 익숙하니까 반갑기도 했구요. 이런 단순하고 절제된 설계 덕분인지 모르겠지만 컴파일 언어 치고는 컴파일이 정말 빠릅니다. 외부 모듈 의존성 관리하는 것도 이 정도면 정말 깔끔하구요. 나무랄 부분이 별로 없습니다.그럼에도, 감히 말씀드리자면 아쉬운 부분들이 적진 않았습니다. 일단 가장 큰 불만사항은 생각보다 쓸만한 라이브러리가 다양하지 않다는 점입니다. 이미징 라이브러리의 경우만 보더라도 일단 몇 개 뿐이고, 그 마저도 성능 측면에서 괜찮아 보이는 건 libvips 같은 외부 라이브러리를 사용하는 것 정도입니다. Go 언어가 스크립트 언어에 비한다면 충분히 의미있게 빠르겠지만, 이렇게 핵심적인 라이브러리들이 다 C 기반 라이브러리에 여전히 의존하는 점은 역설적이게도 Go 언어의 한계를 보여주는 부분이라고 생각합니다. 즉 C나 C++을 대체하는 언어는 아니라는 점입니다. 지향하는 바가 다르다는 걸 느낄 수 있었습니다.그리고 가끔 왜 이렇게 했을까? 하는 부분들이 있는데, 2가지 정도만 언급해 보겠습니다. 첫번째는 if err ≠ nil { … } 과 같은 에러 핸들링입니다. 에러 처리는 Go 언어에서 즉시 하도록 설계되어 있고, 나중으로 미루거나 한 번에 모아서 한다 같은 개념은 없습니다. 물론 여러 개의 에러들을 핸들링하는 공통 로직이 있다면 그걸 묶어서 다시 에러 처리를 하면 되겠지만, 어쨌든 저 에러 처리 구문은 계속 등장합니다. 정말 나중에는 if err 코드를 입력하는 것 조차 짜증이 날 때가 있습니다. defer 같은 키워드도 제공해주면서 에러 처리는 왜 저렇게 하도록 하는 걸까 싶네요. 굳이 장점으로 뽑자면, 에러가 생기는 즉시 핸들링을 명시적으로 하기 때문에 문제를 빠르게 확인할 수 있다…? 잘 모르겠습니다. 일단 저렇게 해야 하니까 해야죠 뭐.두번째는 슬라이스인데, var results []Result 이 코드와 results := make([]Result, 0) 의 차이입니다. Go 언어가 저보다 더 생소하실 분들을 위해 설명드리면, 두 코드는 기본적으로 같은 목적으로 사용됩니다. results 라는 변수는 슬라이스 변수인데, C 언어스럽게 표현해보면 일종의 배열의 포인터를 가지고 있는 변수입니다. 그래서 둘 중 어느 방식으로 변수를 선언하더라도, results = append(results, item) 처럼 배열에 값을 더 추가하거나 등의 작업을 할 수 있습니다. 여기까지만 읽으면 뭐가 문제지? 라고 생각하실 수 있는데… 문제는 저 코드들이 서로 다른 표현을 하는 이유가 있다는 점입니다.var results []Result 같은 경우에는, 초기값이 nil 입니다. C++ 에서 말하는 nullptr 이랑 같다고 보시면 되고, 자바스크립트에서는 null 과 같다고 보시면 됩니다. 그리고 results := make([]Result, 0) 이 코드에서 results 는 nil 이 아닙니다. 빈 배열 슬라이스를 가지며 단지 크기가 0 일 뿐입니다. 좀 더 생각해보면, 초기화가 어쨌든 되어 있습니다. 응? 초기화가 안되어도, 초기화가 되어도 동작이 똑같다고?? 그렇습니다. 둘의 차이는 초기화의 차이지만, 동작은 동일합니다. 그럼 대체 뭐가 문제일까요? 문제는 아무런 값도 추가하지 않고 그냥 변수만 선언한 상황에서 값을 반환할 때 입니다. 특히 JSON 형태로 클라이언트에게 값을 전달해줘야 하는 경우를 생각해 볼 수 있습니다. 우리가 자바스크립트로 예를 들어서 서버로부터 넘어온 값을 받는다고 합시다. 이 때 results 라는 이름의 배열에 값들이 하나도 없을 경우, 우리는 무엇을 기대할 수 있을까요? 당연히 [] 입니다. 이렇게 넘겨 받아야 빈 배열이니까 results.length 같은 걸 사용 할 수 있겠죠.results := make([]Result, 0) 으로 작성한 코드는 우리의 기대대로 동작합니다. 초기화가 되어 있고, 빈 배열 슬라이스를 가지므로 JSON으로 리턴할 때 [] 으로 리턴됩니다. 하지만 var results []Result 는 [] 을 리턴하지 않습니다. 이 코드는 null 을 리턴합니다. 초기화가 되어 있지 않기 때문에, nil 값이 JSON 형태로 변환되면서 null 이 됩니다. 그럼 results.length 같은 걸 쓸 수 있을까요? 안되죠. 추가적으로 클라이언트에서는 null 검사를 해줘야 합니다. 그냥 빈 배열로 넘어오면 되는 문제인데, 생각지도 못하게 일이 꼬일 수가 있습니다. 저처럼 Go 언어에 익숙하지 않은 사람들은 이 함정에 생각보다 쉽게 빠질 수 있어서 주의가 필요합니다. 언어 자체적으로 비슷하게 동작하지만 서로 다른 결과를 낼 수도 있는 방식을 제공하는 건 조금 의외였습니다. 그 흔한 while 문도 없고 for 문으로 통일했으면서 왜 저건 저렇게 두는 건지 의아했습니다. 물론 제가 아직 잘 몰라서 그런 것이겠지만, 처음 접하는 입장에서는 저 차이를 모르고 그냥 막 썼다가 피를 보고나니 조금 물음표가 생기게 된 것도 사실입니다. 물론 저거 말고도 있습니다만, 장점도 그에 못지 않으니 이 정도로 마무리 하겠습니다. 장점 하니까 생각나는데, 아까 말씀드렸던 defer 키워드는 그래도 쓸만합니다. 예를 들어 어떤 핸들러를 열어놓고, 해당 코드를 포함하는 함수가 리턴하기 직전에 항상 닫아야 할 경우, Go 언어는 중간에 그 많은 if err ≠ nil { … } 코드마다 핸들러의 자원을 해제하는 코드를 추가해야 합니다. 끔찍하죠. 그러나 defer 키워드가 있으면 언제 로직이 종료되고 함수를 떠나더라도 그 직전에 항상 자원 해제 코드를 실행해 줍니다.// 대시보드용 최근 게시글 목록 가져오기 (TSBOARD admin_repo.go 발췌) func (r *TsboardAdminRepository) GetDashboardPosts(bunch uint) []models.AdminDashboardLatestContent { items := make([]models.AdminDashboardLatestContent, 0) // 빈 배열 슬라이스는 반드시 make로! query := fmt.Sprintf("SELECT uid, board_uid, user_uid, title FROM %s%s ORDER BY uid DESC LIMIT ?", configs.Env.Prefix, models.TABLE_POST) rows, err := r.db.Query(query, bunch) if err != nil { return items } defer rows.Close() // GetDashboardPosts 함수가 종료되는 시점에 맞춰서 호출해줍니다. for rows.Next() { item := models.AdminDashboardLatestContent{} var boardUid, userUid uint err = rows.Scan(&item.Uid, &boardUid, &userUid, &item.Content) if err != nil { return items } boardId, boardType := r.FindBoardIdTypeByUid(boardUid) item.Writer = r.FindWriterByUid(userUid) item.Id = boardId item.Type = boardType items = append(items, item) } return items } defer 키워드가 없었더라면 정말 어땠을지 끔찍하네요. 이 키워드 만큼은 특별히 예제 코드로 소개해 드리고 싶어서 가져왔습니다. JS 월드에서 GO 월드 이사 후기 어쩌다보니 글이 또 길어졌는데, 이제 마무리 할 겸 이사 후기를 말씀드리겠습니다. 이제 저에게 JS 월드는 좀 익숙해진 바이크같은 느낌입니다. 배달용 스쿠터 말고 할리 데이비슨같은 그런 멋진 바이크요. 여러 대를 굴리면 가슴이 웅장해지고, 나름 쾌적하게 서비스를 운영할 수 있습니다. 물론 규모가 커지게 되면 여러 대의 바이크를 굴려야 하는 단점이 있지만, 그럼에도 작은 서비스나 빠르게 가야 할 때는 가끔 찾게 될 것 같습니다. 반면 GO 월드는 좀 이게 맞을지 모르겠는데 11인승 승합차같은 느낌입니다. 이것 저것 필요한 걸 잔뜩 실어두고 여러 명이 탑승해서 목적지까지 갈 수 있고, 고속도로에서 나름 속도도 낼 수 있는 그런 승합차를 타는 느낌입니다. 가까운 목적지(= 상대적으로 작은 작업) 부터 비교적 먼 거리(= 상대적으로 큰 규모의 작업)까지 두루 편하게 이용할 수 있다는 느낌입니다. 저의 경우에는 멋진 할리 데이비슨 바이크도 좋지만, 성향상 11인승 승합차가 더 편하고 익숙한 것 같습니다. 새로운 언어에서 느껴지는 익숙한 승차감이라고나 할까요?만약 새로운 백엔드 작업이 있고, 사용자의 규모면에서나 서버 자원의 풍족함 등을 감안해야 할 경우 저는 이제 두 번 고민하지 않고 Go 언어로 작업을 하게 될 것 같습니다. 앞서 여러 불만사항들을 말했지만 그럼에도 이 언어는 충분히 배우고 부딪쳐 볼 가치가 충분한 언어라고 생각합니다. TSBOARD 뿐만 아니라 다른 목적으로도 충분히 활용 가능한 언어이니만큼, 이번에 Go 언어를 처음 접해보신 분들이라면 한 번쯤 본인의 프로젝트에도 활용해 보시는 걸 추천드리고 싶습니다. 언젠가 Go 언어에 충분히 능숙해지면 그 때 또 후기 비스무리하게 글을 끄적여 볼께요. 😊
시리시리니
읽어 보기
Mac mini pro 간단 사용기
0

2024-12-10

3 min read

Mac mini pro 간단 사용기

아주아주 간단하게 남겨보는 맥미니 프로 사용기입니다. (지금도 맥미니에서 작성중)상세한 사용기는 한 달 이상 쓰고 나서 그 때 좀 더 업데이트를 해보도록 하겠습니다. 참고로 이전에 사용한 기기는 Mac Studio (M1 Max) 입니다!정말 작고 조용하다이렇게 작을 줄 몰랐습니다. 가볍기도 정말 가벼워서, 미니PC 살 돈을 두세번 모아서 차라리 맥미니를 사는 게 어떨까 싶을 정도로 괜찮습니다. 입력 포트도 이정도면 훌륭하네요. (아쉬운 건 USB-A 타입 포트랑 SD카드 리더기가 없다는 것)정말 조용합니다. 팬이 달려는 있는 건가? 싶었는데 가끔 존재감을 살짝 느끼게 해주고 다시 잠잠해지는 게, 홈서버로 쓰면 어떨까 싶을 정도입니다. 음, 홈서버로 쓸까 했는데 가성비가 좋진 않겠네요. ㅎㅎ진짜 빠르다이전에 사용한 Mac Studio (M1 Max) 대비해서도 굉장히 빠른 반응입니다. 이건 뭐 비교하기가 조금 미안한 수준일 듯 하고, 제가 주로 사용하는 프로그래밍 관련 도구들에서도 좀 더 쾌적함을 느낄 수 있었습니다.아직 써보진 않았는데, 예전에 많이 쓰던 파이널컷 기준으로 하면 맥미니 프로 정도에서 왠만한 작업은 무리없이 소화 가능하다고 합니다. 저도 기대중인데, 앞으로 영상 작업하시는 분들은 굳이 맥 스튜디오 구매하지 않으셔도 되지 않을까 싶습니다.하지만 가격이 사악해첫 시작 가격은 정말 좋은데, 저처럼 프로 모델을 고민하시거나 램 혹은 저장 공간을 늘리고 싶은 분들은 이 사악한 가격 정책에 소름 돋으실 겁니다. 진짜 너무 비싸요.불행인지 다행인지 썬더볼트 인터페이스를 이용한 SSD를 사용하거나 하면 저장 공간 문제는 좀 자유로워질 수 있는데, 램은 그게 안됩니다. 그래도 애플 인텔리전스 덕분에 시작 용량을 16GB로 해서 얼마나 다행인지, 이게 바로 혁신인 걸까요?만약 저처럼 맥 스튜디오를 사용하시면서 32GB 램은 필수지! 하셨던 분들이 계시다면, 맥미니 프로에서 24GB 램으로 내려오셔도 괜찮지 않을까 싶습니다. 램이랑 CPU/GPU 숫자가 더 많아야 하시는 분들은 내년 상반기까지 맥 스튜디오 기다리시면 되는데, 솔직히 이제는 맥미니 프로 정도면 어지간한 작업들은 그냥 가능해서 더 올라갈 필요는 없어 보입니다. 그리고 모르긴 몰라도 맥미니 프로 가격들을 보니까 내년 상반기의 맥 스튜디오는 가격이 정말 사악하게 나올 가능성이 높습니다. 저는 맥미니 프로에서 몇 년 더 존버하면서 버티다가, 또 성능 향상이 큰 폭으로 생기는 시점에 업그레이드를 노려볼까 합니다. ㅎㅎ
시리시리니
읽어 보기
Go vs Bun, Go언어는 정말 JS 런타임보다 빠를까?
0
정말 오랜만에 (아마도 장문이 될) 주제로 블로그에 글을 쓰는 것 같습니다. 먼저 서두에 밝혀두고 싶은 점은, 이번 벤치마크는 완전히 변수들을 통제한, 정말 제대로 각잡고 한 벤치마크는 아니라는 점입니다. 어디까지나 리얼 월드에서 과연 어느 정도의 차이가 벌어지는지 실제 프로젝트로 비교해본 것이라는 점을 밝혀둡니다.먼저 제 글을 시작하기 전에, 한 번쯤 봐두면 좋을 다른 분의 블로그 글을 소개해 드립니다.https://medium.com/deno-the-complete-reference/bun-vs-go-native-hello-world-performance-006791174df2위 블로그의 글을 요약하면, “생각보다 Go가 그렇게 빠르진 않네?” 라는 결론이 나옵니다.그리고 본 글에서도 결론은 동일합니다.결론 먼저, Go 언어는 때때로 빠르지 않습니다.Go언어는 단순하면서도 꽤나 빠른 속도로 동작한다고 알려져 있습니다. 그리고 실제로 여러 벤치마크를 통해 알려진 것처럼, Rust나 C++에 비할 정도는 아니어도 꽤나 빠릅니다. 특히 자바스크립트 런타임들이 가지고 있는 태생적인 한계인 CPU 집약적인 연산이나, 여러 병렬 처리 및 동시성 제어 등에서 정말 큰 장점들을 가지고 있습니다. 저도 TSBOARD의 새로운 백엔드를 Go언어로 재작성 하면서, 이런 점들을 확실히 알게 되었고 이 언어가 지향하는 곳이 클라우드라는 점도 명확히 알게 되었습니다.우선 아래의 표를 먼저 살펴보시죠.M1 Max(Mac Studio)Go (1.23.3)Bun (1.1.37)Test PathNumber of RequestsNumber of WorkersRequests per secondMemory (MB, peak)Requests per secondMemory (MB, peak)/home/tsboard100,0001066923.2821.361038.0199.5(No DB conn.)100,00050118127.2421.364482.7899.5100,000100125999.2421.264933.3899.3(참고: hey 라는 Go 언어로 작성된 도구를 이용하여 측정한 결과입니다.)// /home/tsboard 접속 시 출력되는 내용, DB 연결 없음 { "success": true, "error": "", "result": { "success": true, "officialWebsite": "tsboard.dev", "version": "1.0.0-beta1", "license": "MIT", "github": "github.com/sirini/goapi" } }실제로는 서두에 언급한 것처럼 완벽하게 동일한 비교가 아니고, Go언어에서 출력해줘야 하는 데이터가 좀 더 많습니다. (Go의 요청 별 응답 크기: 160 bytes / Bun 응답 크기: 114 bytes) 그럼에도 불구하고, Go는 Bun과 비교했을 때 더 높은 초당 요청 처리횟수를 보여주면서도 메모리는 Bun 대비 20% 수준만 사용하고 있습니다. 물론 CPU 사용량은 Bun 대비 2~3배 가량 높았지만, 그럼에도 이 결과만 두고 봤을때는 정말 놀라운 수준입니다.아니, 그럼 결론을 제가 잘못 말한 게 아닌가 싶겠지만…! 이제 아래의 표도 같이 살펴보시죠.M1 Max(Mac Studio)Go (1.23.3)Bun (1.1.37)Test PathNumber of RequestsNumber of WorkersRequests per secondMemory (MB, peak)Requests per secondMemory (MB, peak)/home/latest1,0001070.9835101.45142.5100 posts1,0005067.9987.9104.6194.9per request1,00010067.97159.5102.57250.5(참고: 이번에도 Go의 요청 당 응답 크기가 더 높은 패널티가 있습니다 ▸ Go: 621,343 bytes / Bun: 526,198 bytes)// /home/latest 출력 예시, DB 연결이 요구되며 한 번의 요청에 100건의 최근 게시글을 가져오도록 했습니다. // Go로 백엔드를 재작성하면서, 필요한 데이터가 좀 더 많아져서 요청 당 응답 크기는 Go쪽이 불리합니다. { "success": true, "error": "", "result": [ { "uid": 1234, "title": "제목 예시 (실제로는 더 긴 데이터가 출력 되었습니다)", "content": "내용 예시", "submitted": 1732253323985, "modified": 1732276827209, "hit": 1, "status": 0, "category": { "uid": 1, "name": "일반" }, "cover": "/upload/thumbnails/2024/11/22/this_is_sample_output.avif", "comment": 4, "like": 0, "liked": false, "writer": { "uid": 1, "name": "홍길동", "profile": "/upload/profile/2024/11/16/hong_gil_dong.avif", "signature": "어디까지나 예시용 데이터입니다" }, "id": "photo", "type": 1, "useCategory": false }, // ... 이하 99개의 최근 게시글 반환 ] }거듭 말씀드리지만, 완벽하게 공정한 비교는 아닙니다. Go언어로 재작성 하면서 출력해야 할 데이터가 약간 늘어나긴 했거든요. 그걸 감안하고 데이터를 보더라도, 처음에 봤던 테이블과는 사뭇 다른 결과를 보실 수 있습니다. 메모리 사용량은 여전히 Bun 런타임 대비 현저히 낮지만, 초당 요청 처리 건수는 확연히 떨어지는 걸 보실 수 있습니다.혹시 Go언어에 익숙하지 않은 저의 잘못으로 인해 이런 일이 발생한 걸까요? 저도 제가 뭔가 잘못된 코드를 작성해서 이런 사태가 벌어진 거면 좋겠지만… 수많은 여러 테스트와 코드 수정을 통해서 다다른 결론은, Go언어가 생각만큼 늘 빠르지는 않다는 점입니다. 오히려 DB 입출력이 잦은 리얼 월드에서는 Bun 런타임과 Elysia 웹프레임워크, 그리고 mysql2 라이브러리의 조합이 예상 외로 훌륭한 결과를 보여주었습니다. 동시 요청이 많아도 Go가 보여주는 것만큼의 안정적인 동작을 보여주었고, 미약해 보였던 싱글 스레드 기반의 이벤트 루프는 비동기 I/O와 함께 의외의 슈퍼 파워를 보여주었습니다.Go의 표준 HTTP 라우터는 쓰지 마세요, 느립니다TSBOARD의 새 백엔드를 작성할 때, 처음에는 Go 1.23에서 소개된 표준 HTTP 라우터만 사용했습니다. 동시 접속자가 적은 실제적인 상황에서는 꽤나 훌륭하게 동작했고, 별 문제가 없어보여서 그대로 진행하려고 했죠. 하지만 이미 Bun과 Elysia 조합으로 작성된 백엔드가 있었기 때문에, 정확히 어떤 부분들이 개선되었는지 확인이 필요했습니다. 그래서 hey 도구를 이용해서 부하 테스트를 진행했는데, 세상에… 앞서 보여드린 결과보다 더 열악한 결과만 나왔습니다. 동시 요청이 많아질수록 고루틴 간에 자원을 대기하는 기간이 늘어지고, DB 풀을 대기하면서 CPU 클럭만 차지하는 경우가 많아졌습니다.응답 속도를 Bun보다 높게 하기 위해서 몇가지 도전적인 작업을 해보았지만, 빠른 응답을 위해 유실되는 응답이 많아져 이 길은 아니라고 생각하여 포기하였습니다. 어쩔 수 없이 웹 프레임워크를 쓰기로 결정하고 Fiber가 가장 마음에 들어서 선택하였습니다. 그 후 테스트를 해보니 이제서야 Bun(Elysia) 조합에 크게 떨어지지 않는 응답 속도를 회복할 수 있었습니다.// Go의 표준 HTTP 라우터에서 실제로 구현했던 핸들러 예시입니다 func LoadAllPostsHandler(s *services.Service) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { actionUserUid := utils.FindUserUidFromHeader(r) sinceUid64, err := strconv.ParseUint(r.FormValue("sinceUid"), 10, 32) if err != nil { utils.Error(w, "Invalid since uid, not a valid number") return } // ... utils.Success(w, results) } }Go언어의 새로운 기능이라서 유튜브 등에서 이 표준 HTTP 라우터를 써보라고 권하는 분들이 계실 수도 있지만, 저는 권장하고 싶지 않습니다. 기능 자체는 동작하지만 프로덕션 레벨에서 빠릿하게 동작하는 수준은 결코 아닙니다. 제가 선택한 Fiber 혹은 다른 종류의 웹 프레임워크를 선택하시길 바랍니다.// Fiber v3 기반으로 다시 변경한 핸들러 예시입니다 func (h *TsboardHomeHandler) LoadAllPostsHandler(c fiber.Ctx) error { actionUserUid := utils.ExtractUserUid(c.Get("Authorization")) sinceUid64, err := strconv.ParseUint(c.FormValue("sinceUid"), 10, 32) if err != nil { return utils.Err(c, "Invalid since uid, not a valid number") } // ... result, err := h.service.Home.GetLatestPosts(parameter) if err != nil { return utils.Err(c, "Failed to get latest posts") } return utils.Ok(c, result) }물론, TSBOARD가 처음에 선택했던 Bun과 Elysia의 조합은 여러분들이 상상하시는 것보다 더 바르고 빠르게 동작합니다. 높은 성능과 개발 생산성을 생각한다면 굳이 Go 언어를 고민하실 필요가 없습니다.무엇이 잘못된걸까?여러 가지 원인이 있을 수 있지만 (그 중에서 가장 좋은 이유라면 제가 뭔가를 잘못한 것이겠죠?!), 제가 생각한 문제는 데이터베이스 드라이버입니다. Go 언어에서 MySQL/MariaDB에 연결해서 작업을 하려면 가장 많이 쓰는 go-mysql-driver를 사용해야 합니다. 이 드라이버는 여러 기능들을 갖추고 제대로만 사용하면 자원 할당/해제는 기대한 대로 동작합니다. 실제로 이 글에서 언급하지 않은 수많은 다른 테스트에서도 안정성 만큼은 문제가 없었습니다.// 기존 TSBOARD에서 DB 연결에 사용한 코드입니다. // pool을 생성한 후, 전역 변수에 두고 필요할 때마다 pool에서 연결을 가져와 쓰고 반환하는 식으로 썼습니다. import mysql, { ResultSetHeader, RowDataPacket } from "mysql2/promise" const pool = mysql.createPool({ host: process.env.DB_HOST,user: process.env.DB_USER,password: process.env.DB_PASS, database: process.env.DB_NAME, waitForConnections: true, connectionLimit: 10, maxIdle: 10, idleTimeout: 60000, queueLimit: 0, enableKeepAlive: true, keepAliveInitialDelay: 0, socketPath: process.env.DB_SOCK_PATH, }) // SELECT 쿼리문을 실행하는 헬퍼 함수를 아래처럼 구현해서 사용했습니다. export async function select(query: string, values: string[] = []): Promise<RowDataPacket[]> { let result: RowDataPacket[] = []const db = await pool.getConnection() try { const [rows] = await db.execute<RowDataPacket[]>(query, values) if (!rows[0]) { return result } result = rows } catch (e: any) { console.log(`[error/select] ${query} (${e})`) } finally { db.release() // 명시적으로 사용이 끝나면 pool에 연결을 반환합니다. } return result }그러나, 이 드라이버는 제가 생각했던 것보다, 그리고 다른 언어에서 구현한 MySQL / MariaDB 드라이버보다 느리게 동작합니다. 자바스크립트 생태계에서 주로 사용하는 mysql2과 같은 드라이버는 go-mysql-driver만큼이나 다양한 기능들을 제공하지만, 결과적으로 더 빠르게 동작했습니다. 물론 이것만으로 범인을 특정(?!)하는 것은 문제가 있습니다만, 자바스크립트 생태계에 있을 땐 단 한 번도 고민하지 않았던 DB I/O 성능 이슈를 Go언어에서 겪게 되고, DB 연결이 필요 없는 작업과 비교해서 결과를 보니 의심을 지우긴 어렵습니다.// Go언어로 작성한 TSBOARD 백엔드에서 DB에 접속하는 함수입니다. // 여기서 반환된 *sql.DB 포인터는 DB 작업이 필요한 Repository 에 전달됩니다. // DB Pool을 생성하고, 반환하는 등의 작업이 단일 포인터에서 모두 이루어집니다. func Connect(cfg *configs.Config) *sql.DB { addr := fmt.Sprintf("tcp(%s:%s)", cfg.DBHost, cfg.DBPort) if len(cfg.DBSocket) > 0 { addr = fmt.Sprintf("unix(%s)", cfg.DBSocket) } dsn := fmt.Sprintf("%s:%s@%s/%s?charset=utf8mb4&loc=Local", cfg.DBUser, cfg.DBPass, addr, cfg.DBName) db, err := sql.Open("mysql", dsn) if err != nil { log.Fatal("❌ Failed to connect to database: ", err) } if err = db.Ping(); err != nil { log.Fatal("❌ Database ping failed: ", err) } maxIdle, err := strconv.ParseInt(cfg.DBMaxIdle, 10, 32) if err != nil { maxIdle = 20 } maxOpen, err := strconv.ParseInt(cfg.DBMaxOpen, 10, 32) if err != nil { maxOpen = 20 } db.SetMaxIdleConns(int(maxIdle)) db.SetMaxOpenConns(int(maxOpen)) db.SetConnMaxLifetime(3 * time.Minute) return db } // 댓글에 대한 좋아요 수를 반환하는 함수입니다. DB pool에 대한 접근은 r.db (*sql.DB) 로 합니다. func (r *TsboardCommentRepository) GetLikedCount(commentUid uint) uint { query := fmt.Sprintf("SELECT COUNT(*) FROM %s%s WHERE comment_uid = ? AND liked = ?", configs.Env.Prefix, models.TABLE_COMMENT_LIKE) var count uint r.db.QueryRow(query, commentUid, 1).Scan(&count) // r.db 가 *sql.DB 포인터를 가지고 있습니다. return count }물론 제가 뭔가 잘못한 걸 수도 있습니다. go-mysql-driver의 권장 설정을 제대로 따르긴 했지만, 아직 스스로를 고퍼라고 생각하진 않기 때문에 만약 제가 저지른 실수가 있다면 참회하는 마음으로 다시 글을 업데이트 할 생각입니다. (지금 이 글을 쓰면서 부디 제가 뭔가 잘못한 것이길 바라고 있습니다…!)Go 언어는 느리다, 가 아니라 빠르지는 않다모든 언어가 마찬가지지만, Go 언어도 빠르게 동작할 수 있는 부분이 분명히 있고, 기대했던 것보다는 느리게 동작하는 부분도 있습니다. CPU 집약적인 연산(예를 들면 JWT encode/decode)이나 병렬 처리해도 동시성 관리가 거의 필요없는 부분에서는 발군의 성능을 뽐낼 수 있지만, 실제 DB를 사용해야하고, DB가 주요 병목일 수 밖에 없는 백엔드에서는 기대했던 것만큼 성능이 나오질 않습니다.Node.js가 세상에 등장하고 Deno가 나오면서 점점 더 많은 사람들이 자바스크립트/타입스크립트 런타임에 의존하고 있습니다. 이 덕분에 Bun과 같은 고성능 런타임의 개발까지 이어졌다고 생각합니다. 정말 놀라운 결과이지만, Bun 런타임과 Elysia의 조합은 정말 인상적인 성능을 보여줍니다. TSBOARD 프로젝트를 처음 시작할 때 제가 선택한 이 스택을 보다 많은 개발자분들이 직접 써보시고, 실제 현업에서도 많이 활용해 보셨으면 좋겠습니다. 정말 좋거든요!그래서, Go 언어로 만든 백엔드는 포기하나요?지금까지 글을 읽어주신 분들 이라면 응당 제가 Go 언어에서 다시 Bun(Elysia) 조합으로 돌아 가겠구나, 하고 생각 하셨을 겁니다. 실제로 저도 진지하게 Go 재작성 프로젝트를 중단할까 고민도 했었습니다. 고성능 백엔드 개발에 쓸 만한 언어는 다양하게 있고, 저의 최애(?) 언어인 PHP도 건재하니 말이죠. (건재한 거 맞지 PHP…? 잘 지내니…?)그러나, 아래의 이유로 Go 언어로 백엔드 재작성을 마무리 짓고 진정한 Gopher로 거듭나고자 합니다!타입스크립트가 제공하는 타입 안정성은 부족합니다. 보다 다양한 원시 타입을 쓰면서도 타입스크립트에서 누렸던 type 정의와 interface의 활용이 가능한 Go 언어의 타입 시스템이 마음에 들었습니다.Go 언어에서 포인터는 비난의 대상이지만, 저는 오히려 반가웠습니다. 가끔 이 포인터의 존재가 그리웠어요!파이썬이나 자바스크립트 같은 코드는 바로 바로 고칠 수 있고 쉽게 배포도 가능하지만, 그 코드를 동작시키는 런타임을 반드시 필요로 합니다. 물론 저는 TSBOARD 프로젝트를 통해서 어느 정도 적응을 했습니다만, 가끔 npm install 가 불러오는 무지막지한 라이브러리들의 크기를 볼 때마다 내심 놀라곤 합니다.수십 KB의 내 코드를 동작 시키기 위해 수백 MB의 라이브러리들이 준비되어야 하고, 이 모든 걸 합쳐서 함께 바이너리로 만들어 배포하려고 보니 아주 간단한 기능 조차도 파일이 너무 커지게 됩니다. (런타임도 같이 넣으니까요.)저는 Go 언어가 제공하는 단일 바이너리 파일 배포가 정말 마음에 들었습니다. 더 이상 주절 주절 설명할 필요가 없으니까요!고루틴은 날카로운 병렬 검입니다. 잘못 쓰면 손가락이 날라가겠지만, 잘만 사용하면 하드웨어의 한계를 쥐어 짤 수 있습니다.본문에서는 언급하지 않았지만, 고루틴을 이용하여 파일 업로드를 구현하니 업로드 속도가 획기적으로 개선되었습니다. 동시에 진행해도 괜찮고, 모두 한 번에 마칠 필요가 없는 작업에서는 감히 고루틴보다 더 쉽고 강력한 답은 없으리라 생각합니다.아직 TSBOARD 백엔드에서 고루틴을 제대로 활용하질 못했습니다. 성능 개선의 여지는 충분하고, 제가 더 배우고 익힐수록 하드웨어 자원을 더 효율적으로 활용할 수 있으리라 생각합니다.사람마다 선호하는 언어가 다르고, 자신이 생각하는 정답이 다른 사람과 다를 수도 있습니다. 저는 다른 언어들 만큼 Go 언어도 좋아하게 되었고, 비록 기대했던 것만큼 비약적인 성능 향상은 없었지만 그럼에도 Go 언어의 여러 장점들이 마음에 들어서 좀 더 사용해 보려고 합니다. 그리고 부디 언젠가 성능 향상의 비급서를 찾을 그 날을 꿈꿔봅니다.이 긴 글을 읽어주신 분들께 감사드립니다. 혹시 기회가 된다면, 여러분들께서는 Go 언어에 대한 이 글의 비교 결과를 어떻게 생각하시는지 의견도 나눠보고 싶습니다!TSBOARD 프로젝트: https://github.com/sirini/tsboardTSBOARD GOAPI: https://github.com/sirini/goapi
시리시리니
읽어 보기
Go언어로 갑니다! (Goodbye, Bun!)
0
저는 10년 만에 웹 개발을 다시 시작하면서, 자바스크립트 생태계의 천지개벽에 적잖게 당황했고 또 놀랬습니다.React는 세상을 점령한 것처럼 보였고, 백엔드에서는 Node와 Deno의 등장으로 정말 어디서나 자바스크립트를 볼 수 있게 된 세상이 신기했습니다. 비동기 I/O가 주는 장점들을 십분 발휘 하면서도 다른 성능들과 개발 편의성도 동시에 급진적으로 개선되는 게 경이로웠고, 열광적으로 빠져들었던 기억이 납니다. 특히나 Node에서 Bun으로 런타임을 교체하며 동시에 타입스크립트로의 도전은 보다 큰 규모의 프로젝트를 무리없이 구성할 수 있겠다는 자신감까지 심어줬습니다. TSBOARD 개발은 전적으로 이 새로워진 자바스크립트 생태계 덕분입니다.그렇지만, 길다면 길고 짧다면 짧았던 저의 자바스크립트(혹은 타입스크립트) 백엔드 개발은 이제 곧 끝날 예정입니다. 저는 곧 Go언어로 백엔드를 완전히 재작성 할 예정이고, 다시 자바스크립트 생태계로 돌아오진 않을 겁니다. (토이 프로젝트나 시간이 정말 급박하다면 또 얘기가 다르겠지만요…! 😉)나는 왜 JS/TS 런타임으로부터 떠나는가?사실 지금의 TSBOARD를 만들 수 있게 해준 건 전적으로 타입스크립트와 JS/TS 런타임인 Bun 덕분입니다. 이 개발 스택을 선택한 건 지금도 후회하지 않고, 만약 처음으로 다시 돌아간다고 해도 저는 똑같은 선택을 할겁니다. 특히 Node의 부족한 성능을 정말 획기적으로 개선해준 Bun, 그리고 그런 Bun에 최적화된 웹 프레임워크를 제작해준 ElysiaJS팀에 감사한 마음을 가지고 있습니다.그럼에도, 여전히 마음 한구석에는 결국 싱글 스레드의 한계와 비동기 I/O 구조에만 지나치게 의존하는 런타임의 성능이 못내 아쉬웠습니다. 물론 트래픽이 엄청나게 적은 이곳 같은 경우에는 전혀 문제 될 것이 없고, 아마 동시 접속자수가 30여명이 넘어간다 하더라도 크게 무리가 되진 않을 겁니다. Bun이라면… 어쩌면 그 이상 해낼 지도 모르구요.그렇지만, 자바스크립트 런타임은 결국 자바스크립트를 처리하는 엔진의 구조나 성능에 크게 제약을 받게 됩니다. 구글 크롬의 V8 엔진이 아무리 괴물같은 최적화를 통해 미친 성능을 보여 준다고 하더라도, 결국은 나의 자바스크립트 코드를 인터프린팅 해줘야 합니다. Bun은 분명 Node보다 빠르고, Zig 언어를 이용해서 세부적으로 더 고성능의 동작이 가능하도록 API를 잘 다듬었지만, 어쨌든 JavaScriptCore에 의존합니다. 특정 케이스에서는 높은 성능을 보여줄 수 있지만, 전반적으로 컴파일 언어 대비 느릴 수 밖에 없습니다. 또한 아무리 비동기 I/O 방식이 백엔드로 쓰기에 효과적이라 해도 싱글 스레드로 동작하는 이상 성능 저하는 피할 수가 없습니다. (내 서버의 여러 CPU core들을 효과적으로 괴롭혀주지 못하는 것도 아쉽죠!)무엇보다, TSBOARD와 같은 도구를 실제 사용자에게 배포하는 과정이 간단하지 않습니다. 일단 전달 받는 쪽은 Bun이든 Node든 미리 설치해 두어야 합니다. 그리고 사용에 필요한 라이브러리들을 npm 등의 패키지 매니저를 통해 따로 내려 받아야 합니다. 또한 라이브러리들의 크기가 상당히 크고, 혹시나 버전이 꼬일 경우에는 이걸 처리하는 것만으로도 난감해집니다. 서버 환경에 따라서 라이브러리를 다르게 받아야 할 수도 있구요. 저의 경우 Bun 런타임이 한동안 가상 CPU에서는 제대로 동작하지 않는 버그가 있어서 이 배포 과정이 정말 힘들었습니다. (다행히 지금은 고쳐졌습니다!) 저조차도 특정 환경에서는 TSBOARD를 사용하지 못해 대체 솔루션을 찾아야 했을 정도니 그 스트레스가 이루 말할 수 없었죠. 사실 이 점이 저에게는 가장 크게 다가온 현실적인 문제이기도 했습니다. 내가 만든 프로젝트를 내가 쓰고 싶은 곳에 못썼던 시간이 너무 길었기에 대책을 세워야만 했거든요. 왜 Go언어인가?자바스크립트 런타임이 가지는 한계를 점점 명확히 인식하면서, 저는 대안을 고민했습니다. 가장 좋아 보였던 선택은 의외로 러스트(Rust) 언어 였습니다. 메모리 안정성부터 C++과 맞먹는 성능, 그리고 많은 개발자들이 사랑하는 언어라서 가장 먼저 고민을 했습니다. 그러나 웹 개발을 하면서 메모리 문제까지 고민하며 진행하기에는 제 내공도 부족하고, 회사에서 어차피 써야하는 C++만으로도 이미 충분히 괴로웠기 때문에 아쉽지만 제외했습니다. 다음으로 떠올린 대안들은 그누보드가 선택한 파이썬(Python)이었습니다. 하지만 파이썬 언어도 사실 만만치 않게 성능 관점에서 약점이 있다고 생각했고, 회사에서 업무용으로 써본 경험에 비춰보면 웹에서까지 쓰고 싶다는 생각은 들지 않았었습니다. 언어 자체가 강타입 언어도 아니고 배포 과정이 Node나 Bun에 비할 바는 아니겠지만 그래도 간단하지는 않은 것 같았습니다. (어쨌든 파이썬이나 필수 라이브러리들을 받긴 해야 하니까요)마지막으로 고려한 건 코틀린(Kotlin)과 스프링의 조합이었습니다. 정부 표준 프레임워크에 빛나는 자바 생태계에 마음이 끌리지 않았다면 솔직히 거짓말이고, 잠깐이나마 코틀린을 배워본 경험에 의하면 언어 자체가 자바 대비 선녀처럼 보였기 때문에 쓰고 싶었습니다. 그러나 아무리 스프링 프레임워크 설정이 쉬워졌다고 하더라도 여전히 저에겐 개발 환경 셋업도 어려웠습니다. Gradle 같은 빌드 도구들에도 솔직히 좋은 기억이 없어서 사실 가장 적합한 대안이라 생각했지만 제외했습니다.그리고 나서 문득, Go언어는 어떨까 싶어 이것 저것 기웃 거리면서 알아봤는데… 제가 원하는 것들이 대부분 포함되어 있었습니다! 어째서 이제서야 이 언어를 고려하게 되었나 하는 자책을 할 정도로 마음에 쏙 들었습니다.Go언어는 강타입의 컴파일 언어입니다. 타입 안정성이야 두말 할 필요가 없습니다.컴파일이 정말 빠릅니다. 인터프린터 언어에 비할 바는 아니라도 정말 빨라서 개발 생산성이 높습니다.배포 과정이 깔끔합니다. 크로스 컴파일도 잘되고, 생성된 바이너리 파일 하나만 있으면 바로 실행됩니다.GC를 지원합니다! 물론 매뉴얼로 메모리를 관리하는 것 대비 느려지는 시점이 간간히 있지만 그래도 감수할 만 합니다.언어 자체가 간결함을 지향해서 배우기가 쉽습니다. 덕분에 빠르게 적응할 수 있습니다.배포할 때 바이너리 파일 하나만 있으면 되고, 메모리 관리를 직접 하지 않아도 되는데다 배우기 쉽고 타입스크립트 언어와 약간 유사한 면도 있습니다. 덕분에 적응하는데도 그리 오래 걸리지 않아서 결과적으로 대 만족입니다. 이 Go언어 자체가 제가 가지고 있는 요구사항을 딱 맞춰서 개발한 것 같은 느낌도 들었습니다.물론 가장 강력한 장점이라 할 수 있는 고루틴(Goroutine)은 정말 백번 얘기해도 부족하지 않을 정도로 큰 장점입니다. 자바스크립트 런타임이 싱글 스레드의 제약에 묶여 있는 것이 내내 마음에 걸렸었기 때문에, 고루틴의 존재는 그 자체로 정말 반가웠습니다. 아무리 비동기 I/O 방식으로 동작한다고 해도 역시 여러 CPU 코어를 동시에 괴롭혀 줄 수 있다면 성능이 더 오를 수 있겠죠…! TSBOARD 백엔드는 언제 Go언어로 완전히 전환되나?현재 목표는 올해 12월 말까지 작업을 마무리하고, v1.0.0 배포 시점에 맞춰서 공표하는 것입니다. 아마 12월 전에는 마무리가 될 수 있을 것 같고, 전환한 이후에는 다시 Bun 런타임 기반의 코드로 돌아가진 않을 것 같습니다. 다만 제가 Go언어를 제대로 공부하고 난 후에 개발을 하는 게 아니라 배우면서 동시에 개발을 하는 상황인지라 테스트 및 성능 개선 부분에 좀 더 시간이 소요될 수는 있겠습니다. Go언어로의 전환이 완료되면 기존 TSBOARD의 server 폴더쪽 코드는 모두 제거될 예정이고, goapi (github.com/sirini/goapi) 의 OS별로 컴파일된 바이너리 파일만 추가되어서 배포될 겁니다. 물론 TSBOARD 사용자 분들 중에서 직접 백엔드를 고쳐서 쓰고 싶은 분들을 위해 goapi 코드 역시 Github에 계속 공개할 예정입니다. 만약 커스텀을 고려중이라면 걱정하지 않으셔도 된다고 말씀드리고 싶습니다.이만하면 되었다, 를 경계하며…TSBOARD를 만들면서 늘 경계하고자 했던 것 하나가, 바로 ‘이만하면 되지 않았나?’ 하는 생각입니다. TSBOARD 백엔드를 지탱해주고 있는 Bun, 그리고 ElysiaJS는 정말 기대 이상으로 잘해주고 있지만, 더 큰 기대를 품기에는 한계가 있습니다. 그 한계를 정확히 인식하고, 뛰어넘을 수 있도록 계속해서 노력해야 한다고 생각합니다. 그 것이 결국 TSBOARD를 사용하는 저나 다른 분들에게 더 큰 만족으로 돌아올테니까요.무사히 전환할 수 있도록 응원을 부탁드립니다!
시리시리니
읽어 보기
신혼여행을 다녀와서 : 천국은 멀리 있었다 (멕시코 칸쿤)
1
8월 31일 인생에서 가장 큰 이벤트라 할 수 있는 결혼식을 마치고, 9월 2일에 뉴욕으로 향했습니다.뉴욕에서의 5일도 정말 너무나 좋았었는데, 언젠가 한 번 이야기를 해볼 수 있으리라 생각하고, 오늘은 칸쿤에 대해서 짧게 남겨보고자 합니다.천국은 멀리 있다 : 18시간의 비행멕시코 칸쿤은 한 10년 전부터도 신혼여행의 성지로 불렸던 곳이라고 합니다.혹자는 아무리 칸쿤이 좋아봤자, 몰디브에 비할 바는 아니라고 하시기도 하는데, 글쎄요… 둘 다 가보진 못했지만 저는 칸쿤이야말로 감히 신혼여행의 성지라 할만하다고 주장하고 싶습니다. 가히 천국이라 칭해도 부족하지 않은데, 딱 2가지의 문제만 있었습니다. 바로 가는데 걸리는 시간과 돈입니다.칸쿤은 이 곳 대한민국에서 바로 간다고 하더라도 한 16시간 정도는 걸릴 것 같은데 (최근에 직항이 생겼다고 합니다), 뉴욕을 거쳐서 가게 되면 뉴욕까지 14시간, 다시 뉴욕에서 칸쿤까지 4시간 더 걸려서 최소 18시간이 소요됩니다. 하루가 24시간이니까, 사실 수속하고 이것저것 하다보면 하루를 그냥 비행기에서 보내는 셈입니다. 정말 멀어도 너무 멀다 싶긴 한데, 막상 칸쿤에 도착하고나서 리조트에 짐을 풀고 있노라면 멕시코 만과 카리브 해의 중간에서 맛보는 바다의 풍경이 일품이었습니다.저는 이번 신혼여행에서 처음으로 10시간이 넘는 장거리 노선을 타보았습니다. 한 6~7년 전에 중국에서 잠깐 살때도 중국 내에서 이동하는데 4시간 정도 걸렸던 게 가장 긴 노선이었는데, 이제서야 미국과 칸쿤을 가게 되면서 장거리를 제대로 경험해 본 셈입니다. 혹자는 그래도 신혼여행이니까 비즈니스 정도는 타지 않았을까 지레 짐작하셨을 수도 있겠지만, 이코노미를 타고서 왕복으로 다녀왔기 때문에 조금 힘들긴 했습니다. 중간 중간에 일어나서 스트레칭도 하고 별 걸 다했는데, 그나마 제가 미리 출발하기 전에 네이버 시리즈나 카카오 페이지에서 볼만한 작품을 완결까지 모두 구매해놓고 출발해서 지루하진 않았던 것 같습니다. 만약 다음에도 장거리 노선을 타야 할 일이 생긴다면 똑같이 준비해서 심심하지 않게 할 생각입니다.올 인클루시브 매직 : 그래도 팁은 준비해 두세요칸쿤 리조트들은 대부분 올 인클루시브(All Inclusive)입니다. 즉 호텔 리조트 비용 안에 각종 부대비용들(레스토랑, 카페, 스낵, 아이스크림 등)이 모두 포함되어 있습니다. 따라서 현장에서는 따로 돈을 지불하실 게 사실 거의 없다고 보셔도 됩니다. 여기서 “거의” 없다고 표현한 건, 그래도 리조트마다 추가적인 비용을 지불해야만 이용할 수 있는 게 조금씩은 있기 때문입니다. 저희는 하얏트 지바 칸쿤에서 한 4일 정도 머물렀고, 이어서 스칼렛 아르떼로 이동하여 한 3일 정도 머물렀습니다. 둘 다 모두 훌륭한 곳으로 서로의 장단점이 있는데, 가격 차이가 한 2배 가까이 나는 만큼 스칼렛 아르떼의 시설이나 액티비티 등이 훨씬 가치 있었다고 말씀드릴 수 있겠습니다. 만약 다시 골라야 한다면 여전히 고민은 되겠지만, 아마 좀 무리를 해서라도 스칼렛 아르떼를 선택하지 않을까 싶습니다. 하긴 한국에서도 1박에 100만원이 넘는 곳에 숙박을 한다고 하면 그정도 만족감은 당연히 느껴야 하는 거겠죠? ㅎㅎ하얏트 지바와 스칼렛 아르떼 모두 훌륭한 서비스를 보여줍니다만, 서비스의 질 자체는 하얏트 지바가 좀 더 좋았습니다. 직원들의 친절함이야 물론 말할 것도 없고, 서비스들도 나쁘지 않았습니다. 스칼렛 아르떼 역시 마찬가지로 친절하고 좋았지만 브랜드 호텔이 보여주는 그런 수준은 아니었던 것 같습니다. 반면 시설 같은 경우에는 지바가 좀 더 오래된 느낌도 있고, 숙박 시설 내부의 컨디션도 스칼렛 아르떼 대비 조금 떨어지는 건 어쩔 수 없었던 것 같습니다. 올 인클루시브는 무언가를 먹고 마시는데 있어 아무것도 신경쓰지 않게 해주니까 정말 좋았습니다. 다음에도 휴양 개념의 여행을 가게 된다면 올 인클루시브를 먼저 살펴보게 될 듯 합니다. 아, 그래도 혹시 모르니 미국 달러로 된 팁은 챙겨가시는 걸 추천드립니다. 여행사에서 제시하는 수준의 팁 까지는 줄 필요가 없어 보였습니다만(계속 관찰해봐도 팁을 주는 외국인들은 한 50% 정도입니다), 방 청소를 해주시는 분께 남기는 2달러 정도의 팁이나, 레스토랑에서 저희 테이블을 담당해준 서버에게 전해주는 2달러 정도의 팁은 괜찮아 보였습니다. 팁을 안준다고 해서 서비스가 형편없어 진다거나 하진 않았고, 팁을 받는 종업원들도 팁이 필수는 아니라고 이야기 해줬습니다. 그럼에도 무언가 메뉴를 전달 받거나 음료수를 주문해서 받았을 때 서로 기분 좋게 최소한 1달러씩 주는 건 나쁘지 않아 보였습니다. 개인적으로는 팁을 주는 문화권에 여행 간 것이 이번이 처음이어서 처음에는 조금 어색했는데, 그래도 와이프 따라서 몇 번 주다보니까 익숙해진 느낌입니다. 그럼에도 한국에는 팁 문화가 들어오지 않았으면 하는 생각도 들었습니다. ㅎㅎ폭력적인 적도 태양 : 자외선 차단은 필수칸쿤의 하루는 태양이 어느 정도 떠올랐는가에 따라서 갈립니다. 9월 초 칸쿤은 오전 11시부터 오후 3시까지는 야외에서 생활하는 것이 굉장히 힘들 정도로 태양이 뜨거웠습니다. 저는 적도 태양의 폭력적인 자외선이 얼마나 대단한지 미처 알지 못한 채로 딱 하루 동안 하루 종일 야외 수영장에서 튜브를 잡고 헤엄치며 놀다가 돌아다니다가 했었는데, 그 하루만에 노출된 팔이 모두 시커멓게 변해버리면서 따갑고 후끈거리게 되었습니다. 레쉬가드를 입었어야 했는데 그날 하루 안입었다고 이렇게 타버리나 싶기도 했고 여러모로 놀랬습니다. 리조트 직원분들은 애초에 전신을 꽁꽁 싸매고 근무하고 계셨었는데, 처음에는 날도 더운데 왜 저렇게 있지? 했지만 적도 태양의 폭력적인 뜨거움 앞에 고개를 끄덕일 수 밖에 없었습니다. 혹시 칸쿤으로 여행을 가신다면 레쉬가드 긴팔로 꼭 챙기시고, 자외선 차단을 위해서 썬크림은 자주 바르시기 바랍니다. 선글라스도 무조건 챙기셔야 합니다. 한낮의 태양빛도 무시무시한데, 물살에 반사되는 햇볕들도 눈을 때립니다. 한국 신혼부부들의 정모 장소 : 한국인듯 한국 아닌 한국 같은 칸쿤우리나라의 혼인율과 출산율 감소는 이미 세계적으로도 잘 알려져 있는 심각한 문제입니다. 뉴스에서도 학계에서도 우리나라가 이대로만 가면 곧 소멸할 거라고 예측하고 있고, 실제로도 회사마다 20대 직원 비율이 현저히 낮아지는 등 문제가 속속 발견되고 있습니다. 그럼에도 칸쿤을 가보면, 그 귀한 신혼부부들을 심심치 않게 만나 보실 수 있습니다. 농담이 아니라 정말 많은 한국인 신혼부부들이 칸쿤 리조트에서 휴양을 만끽하고 있습니다. 그냥 리조트 어디를 걸어 가더라도, 수영장 어디를 가더라도 한국인 신혼부부들을 만나보실 수 있습니다. 정말 국민 신혼여행지라고 보셔도 됩니다.처음에 뉴욕을 거쳐 멕시코 칸쿤으로 갈 때만 하더라도, 저에게 있어 멕시코라는 나라를 표현하는 단어들은 마약, 카르텔, 나르코스와 같은 다소 무섭고 부정적인 것이었습니다. 그러나 실제로 만나 본 칸쿤은 정말 지상낙원이라는 표현이 부족할 정도로 멋진 곳이었고, 리조트 시설이나 직원들의 친절함도 좋았습니다. 그리고 무엇보다, 젊은 한국인들이 정말 많았습니다! 뭔가 궁금하거나 모르는 게 생기면 근처에 지나가는 한국인 신혼부부 관광객에게 한국말로 그냥 물어봐도 될 정도입니다. 약간 외국이라는 느낌이 조금 덜해지는 아쉬움은 있지만, 반대로 이렇게나 많은 한국인 관광객들에게 선택받은 만큼 안전하겠구나 하는 생각도 들어서 조금 안심이 되었습니다.언제 또 다시 가볼까… 또 가고 싶은 칸쿤회사 동료분들 중에 한 분은 칸쿤이 너무 좋아서 결혼 후에 아이와 함께 다시 칸쿤을 찾았었다고 말씀해 주셨었는데, 그 마음을 이제는 좀 알 것 같습니다. 칸쿤이라는 곳이 주는 휴양의 느낌, 그리고 아름다운 바다의 모습과 여유롭게 휴양을 즐기는 사람들의 즐거움이 오래도록 기억에 남습니다. 만약 기회가 된다면 또 한 번 가보고 싶고, 좀 길게 휴양지를 즐겨보고 싶다는 생각이 듭니다. 전세계 어디서든 노트북 하나만 있으면 언제든지 일을 할 수 있다고 하는데, 칸쿤 리조트에서 카리브 해를 바라보며 TSBOARD 개발하면 어떨까 하는 상상도 해보았습니다. ㅎㅎ
시리시리니
읽어 보기
만약 TSBOARD 런타임을 더 고성능으로 만들어본다면?
0
요즘 문득 드는 (쓸데없는) 고민이 하나 있는데, 바로 고성능 백엔드 입니다.물론 지금 신세지고 있는 Bun 런타임의 성능이 낮다거나 한 건 아닙니다. 지금 보여주는 퍼포먼스는 Node.js 와 비교하기에는 미안할 정도로 우수하고, 지금 이 순간에도 계속해서 업데이트 되면서 호환성과 속도를 계속 개선해 나가고 있습니다. 하지만, 특정 규모를 넘어서는 시점에서는 Bun이 아닌 다른 백엔드나 혹은 다른 구조가 요구될 수도 있습니다.즉 미래 어느 시점에 백엔드를 좀 더 고사양으로 교체하거나, 혹은 고사양 백엔드 옵션을 제공할 필요가 생길 수도 있습니다. 즉 일반적인 상황에서는 TSBOARD가 제공하는 Bun 런타임 기반의 백엔드를 그대로 쓰고, 좀 더 고성능의 백엔드가 요구될 때는 별도의 프로젝트에서 제공되는 고성능 백엔드를 실행시켜서 응답 속도를 더 높이고 더 많은 요청을 처리하는 것입니다. 사실 이 고민은 어떻게 보면 저에게는 굉장히 쓸모 없으면서도 쓸모가 있습니다. TSBOARD 공홈이나 제가 따로 운영하는 사이트들은 그렇게 많은 트래픽을 감당할 필요가 없습니다. 즉 지금 사용하고 있는 Bun 런타임이 아니라 사실 Node.js 런타임이라 하더라도 크게 문제 되지는 않을 것입니다. 하지만 반대로 고성능 백엔드를 TSBOARD가 옵션이든 기본이든 제공할 수 있다면, TSBOARD 도입을 고려하는 분들에게 선택을 좀 더 쉽게 만들어드릴 수 있을 것입니다. 물론 고성능 백엔드를 구성할 수 있다면 저 역시도 배울 점이 많을테니 공부가 되겠죠.추가적으로, Bun 런타임의 태생적 한계인지는 모르겠으나 가상 CPU에서는 제대로 동작하지 않는 문제를 고성능 백엔드 바이너리를 통해서 해결할 수 도 있습니다. Bun을 쓰지 못하더라도 다른 옵션이 있는 셈이니 사용자에게는 여러모로 이득이긴 합니다. (사실 저도 이 문제가 마음에 계속 걸려서 백엔드를 어떻게 할까 고민하기 시작했습니다)고성능 백엔드, 한다면 어떤 언어로?저에게는 고성능 하면 떠오르는 불멸의 언어 하나가 있습니다. 바로 (Modern) C++ 입니다. 물론 Rust, Zig 등의 언어도 있고 실제로 Bun 런타임의 경우 Zig 언어로 개발되었으니 고려해봄직 합니다. 그러나 여러 대안이 존재함에도, 백악관에서 쓰지 말라고 함에도 불구하고 고성능이 요구되는 프로젝트에서 C++을 빼놓고 생각하긴 어렵습니다. Rust 언어는 써볼려고 잠깐 학습하긴 했습니다만, 뭔가 손이 잘 가지 않습니다. 선생님같은 컴파일러 덕분에 무엇이 문제인지 친절히 배울 수 있다는 점은 좋았습니다만, 이걸로 당장 개발을 시작하기에는 스트레스가 더 많아질 것 같아서 아직은 엄두가 안납니다.여러 고민들을 해보다가, 문득 Go 언어로 하면 어떨까? 하는 생각이 미쳐서 여러 사례들을 봤는데… 딱 제가 생각하는 고성능 백엔드에 적합한 개발 언어라는 생각이 들었습니다. 똑똑한 GC 덕분에 메모리 걱정을 좀 내려놓아도 되고, 문법도 크게 어렵지 않은데 컴파일도 빠르고 실행도 그만하면 빠르다는 생각이 들었습니다. 타입스크립트로 작성한 백엔드 보다는 개발 속도가 좀 늦어지겠지만, C++로 작성하는 것 보다는 훨씬 빠르게 만들 수 있지 않을까? 하는 막연한 확신(?!)도 들구요. ㅎㅎ아직 TSBOARD가 v1.0.0 달성도 하지 못한 상태에서 백엔드를 하나 더 만드는 게 가당치도 않은 소리입니다만, 언젠가 백엔드를 필요에 따라서 교체해서 쓸 수 있는 이 아이디어를 구현할 수 있는 날이 왔으면 좋겠습니다. 이참에 저도 Go 언어와 친해져서 이것 저것 재미난 것들 만들어보고 싶네요.
시리시리니
읽어 보기
살면서 언젠가 한 번은 C++를 써야 할 때가 온다
0
저는 코딩을 PHP부터 시작했고, 스크립트 언어 위주로 사용하다가 시간이 조금 지나서 이제는 화석이 되어버린 MFC를 써야하는 시점에 C++ 언어를 제대로 접하게 되었습니다. 학부 시절에 로우 레벨 언어로 사용했던 C언어와 간혹 같이 붙여서 C/C++ 로 표현하기도 했었지만, C++의 뜨거운 맛을 맛본 뒤로는 C언어와 동일 선상에서 부르는 건 그만두게 되었지요.C++언어는 정말 경이로운 언어입니다. 만들어질 당시 컴퓨팅 파워는 지금의 라즈베리파이보다 못한 수준이었을테고, 그럼에도 최적화된 성능을 이끌어내기 위해서 컴파일러나 언어 사용자나 많은 고생을 해야만 했을 겁니다. C언어 수준의 속도를 보장하면서도 여러 패러다임들을 받아들이기 위해 마개조스러운 변화가 반영되었고, 그럼에도 예전 코드가 최신 컴파일러에서 제대로 동작하도록 하위 호환성에도 미친듯한 신경을 썼습니다. 과거의 유산을 포기하지 않으면서 여전히 미래로 도전하는 이 언어는 감히 평해보자면, SW업계에 공기와도 같은 존재로서 어디서나 만날 수 있는 언어라 말할 수 있겠습니다.C++언어의 창시자와 다른 구루들이 남긴 말을 살펴보면, 이 언어의 진가를 알 수 있습니다.50년간 연구를 했다. 결국 C++인가? (Richard A. O’Keefe, Functional Programming 연구에 힘쓰는 컴퓨터 과학자)C,C++을 쓰는 건 안전가드를 제거한 전기톱을 쓰는 것과 같다. (Bob Gray)C++ 에서는 스스로 발을 쏘는 행위는 거의 일어나지 않는다. 하지만 그런 일이 일어난다면 다리 전체가 날아가 버릴 거다. (Bjarne Stroustrup, C++언어의 창시자)C++ : 여기선 친구들이 당신의 Private Members에 접근할 수 있다. 코딩 농담임. (Gavin Russell Baker)(출처 : https://subokim.wordpress.com/2015/03/12/101-great-computer-programming-quotes/)제 생애 가장 프로그래밍이 고통스러웠던 순간을 떠올려보면, C++언어를 사용할 때라고 단언할 수 있습니다. 비록 그 때는 모던 C++ 시대가 아니었고, 제가 주로 사용했던 영역은 MFC였습니다만, 그럼에도 이 C++언어는 저로 하여금 스스로 다리 전체를 날려버리는 끔찍한 경험을 몇번이나 하게 만들었습니다. 포인터를 날려버리는 건 귀여운 애교 수준이었고, 가끔은 캐스팅을 잘못해서, 어쩔 땐 참조를 잘못써서 문제가 생기는 게 흔하던 시기였습니다. 저의 실력이 미천했던 것도 물론입니다만, 당시 제 느낌은 헬멧도 쓰지 않은채로 시속 100km로 달리는 오토바이 위에서 눈을 감고 서 있는 그런 느낌이었습니다. 운이 좋으면 오토바이가 멈출 때까지 (프로그램이 종료할 때까지) 아무런 일도 일어나지 않지만, 운이 나쁘면 저는 오토바이가 의도치 않게 멈춰 저는 어디론가 날아가 버릴 수도 있겠죠. ㅎㅎ;;다른 언어도 마찬가지겠지만, C++언어는 모든 부분을 다 배워서 써먹는 게 불가능합니다. 이 언어만 몇십년동안 사용했던 개발자들도 하는 얘기니 믿을 수 있겠죠. 프로그래밍 언어의 역사가 이 언어 속에 녹아져 있고, 그걸 모두 배워서 써먹는 건 가능하지 않습니다. 그저 필요한 부분만 확실히 익혀서 써먹는 정도가 가능할 뿐이죠. 마치 학창시절부터 배워 온 영어가 아직 입 안 어딘가에 맴돌기만 하는 것과 같습니다.가능하면 MFC를 쓸 때 이후로 다시는 C++언어와 만나고 싶진 않았습니다. 지금 TSBOARD 프로젝트처럼 이왕이면 타입스크립트 언어나 좀 더 네이티브로 나아간다면 Go 언어 정도를 배워서 써먹어야겠다 생각했는데… 어쩌다 보니 먹고 살기 위해서 다시 C++언어를 만날 준비를 하고 있습니다. 무서운 선생님을 다시 만나는 기분이라 약간 두려운 마음이 크네요. 부디 예전과 다른, 조금쯤은 더 친절해진 C++이 저를 맞이해 주기를 바라며 다시 열공중입니다. 프로그래밍을 하시는 분들이라면, 누구나 한 번쯤은 C++언어를 만나게 되는 순간이 있을 겁니다. 그 때 부디 유쾌한 재회가 될 수 있기를 기원합니다. 저도 이제는 다리 전체를 날려버리는 멍청한 짓은 이제 그만둘 수 있기를 바래봅니다.
시리시리니
읽어 보기