2025년 3~6월 회고
📁 들어가며
이번 학기는 지나고 나서야 뭔가 남은 게 보이는 학기였다. 그 전에는 성장이라는 키워드가 더 어울렸다면, 이번 학기는 ‘몰입’과 ‘실험’이었다. 다양한 시도들을 했고, 기술의 발전을 받아들이며 같은 시간 안에 더 많은 것을 해내기 위해 발버둥쳤다. 특히 Cursor와 MCP 같은 새로운 툴이 널리 알려지면서 어떻게 하면 내가 더 많은 기능을 구현할 수 있을지, 구현하는 데서 그치지 않고 처음 보는 사람들에게도 쉽게 설명할 수 있을 정도로 이해도를 높일 수 있을까에 대해 많이 고민했던 학기였다.
그 고민의 기반이 되어준 것이 바로 전공 수업들이었다. 기본기를 제대로 갖추지 않으면, 아무리 빠르게 만들 수 있어도 그것을 설명하거나 확장하기 어려울 수 있다는 생각이 강해졌고, 그래서 수업 하나하나를 더 집중해서 듣고 정리해야겠다는 다짐을 하게 되었다. 시험을 위한 공부가 아니라 다른 사람들에게 설명이 가능한 수준까지 이해를 하는 과정이 필요하다는 걸 크게 느꼈다. 개발과 동시에 학기 중에 열심히 과제로 삼고 지키려 했던 것이다.
특히 나 자신에게 질문을 많이 던지게 되는 시기였다. 단순히 만들기만 하면 끝인 줄 알았는데, 유지하고 설명하고, 다시 개선해야 하는 흐름이 중요하다는 걸 절감했다. 더 이상 “돌아가기만 하면 돼”라는 말은 통하지 않았다. 기능을 하나 넣으면 버그가 따라오고, 사용자의 피드백이 실시간으로 영향을 미쳤다. 생산성과 안정성 사이에서 균형을 잡는 일, 내가 만든 코드의 이유를 설명할 수 있는 상태에 도달하는 일이 모두가 너무나 중요하다는 걸 느꼈다.
아쉬운 점은 학기가 끝난 것 말고 온전히 완료된 것이 거의 없었다. 오히려 뭔가가 더 커졌고, 할 일은 늘어났다. 마감은 더욱 급했고, 문서화는 밀렸고, 그 안에서 불균형은 반복되었다. 수업은 기말고사를 치기 때문에 끝이 났지만 프로젝트는 끝나지 않았다.
📁 개강
컴퓨터망
총 3개의 네트워크 수업 중 마지막 수업이었다. 이전 두 수업은 많은 내용을 다루고 있음에도 내가 그때 당시에는 제대로 따라가지 못했고, 그래서 성적도 만족스럽지 못했다. 이해가 부족했던 것에 대한 아쉬움이 컸고, 그 미완의 감정을 그대로 남겨둘 수 없어 이번 학기에 다시 도전하게 되었다. 전공자로서 네트워크는 필수적인 영역이라는 생각이 강했기 때문에, 이번에야말로 제대로 마무리해보자는 마음이었다.
사실 이전의 계절학기 수업은 애초에 3주라는 짧은 시간 안에 방대한 내용을 다뤄야 했기 때문에, 깊이를 기대하기 어려운 구조였다. 강의 시간도 제한적이고, 수업의 밀도보다 속도 위주로 나가야 했던 환경 속에서 깊이 있는 이해가 생기기 어려웠다. 교수님의 설명도 짧은 시간 안에 핵심만 전달하려다 보니, 질문할 기회도 거의 없었고 수업 이후의 피드백이나 보충도 어려웠다. 그래서 이 정규학기 수업은 그런 구조적 한계를 보완할 수 있을 거라 기대했다.
기대대로, 정규학기 수업은 책 한 권을 교수님의 열정적인 설명과 함께 차근차근 따라갈 수 있었고, 이번에는 빠지지 않고 복습하려고 노력도 많이 했다. 그러던 중 등장한 개념 중 하나가 바로 유한 상태 머신(Finite State Machine)이었는데, 이건 내가 오토마타 수업을 듣지 않아서 생소하게 느껴졌고, 처음엔 이해가 정말 어려웠다.
작동 방식이 어떻게 패킷 흐름 제어나 전송 계층의 논리와 연결되는지 파악하는 데 오래 걸렸다. 처음에는 추상적인 그림으로만 보였던 구조가 수업을 들으며 점차 프로토콜 흐름 속의 논리적 장치라는 점이 이해되었다.
블로그 정리도 계획은 세웠지만 아직 실현하지 못했고, 그 점이 가장 큰 후회로 남는다. 시험 기간에는 나름 철저히 준비했지만 지금은 많이 잊어버린 상태다. 정리는 결국 시험 직전의 공부가 아니라, 평소에 어떻게 개념을 내 것으로 만들고 설명할 수 있는 상태로 가져가느냐의 문제라는 걸 실감했다.
특히 취업 준비를 병행하면서 모의면접에서 네트워크 관련 질문을 받은 경험이 있었는데, 거기서 이 과목의 실전적 가치가 얼마나 큰지 절실히 느꼈다. 시니어 개발자들이 공통적으로 강조했던 것도 결국 '기본기'였고, 이 수업을 통해 내가 어떤 수준까지 도달했는지를 점검할 수 있었다. 그래서 더더욱 이 내용을 다시 구조화해서 정리해보고 싶다. 지금은 정리가 덜 되어 있어 즉답이 어려운 상태지만, 블로그와 함께 지식 베이스를 만들어두는 것이 다음 학기의 목표 중 하나다.
컴파일러
기초가 부족했던 분야. 원래도 꼭 들어보고 싶던 수업이었고, 부스트캠프 챌린지 과정에서의 경험이 큰 계기가 되었다. 당시 컴파일러 관련 과제가 나왔는데, HTML과 JavaScript가 실행되는 게 아니라 내부적으로 복잡한 파싱과 구조화 과정을 거친다는 사실을 처음으로 알게 되었다.
그전까진 그냥 코드가 화면에 뿌려지면 끝이라고 생각했지만, 그 과정엔 분명 무언가 '언어 처리'에 가까운 일이 벌어지고 있었고, 그걸 설명하지 못한다는 사실이 꽤나 찝찝하게 다가왔다. 특히 멤버십 과정에서 React를 배우며 JSX가 DOM으로 변환되는 과정을 보면서, 이런 변환이 결국 컴파일러 개념과 깊이 연관되어 있다는 걸 느꼈다. 그 경험 이후로 '내가 매일 다루는 이 기술의 본질은 뭘까?'라는 의문이 생겼고, 결국 그 회의감이 수강 신청으로 이어졌다.
당시 프로젝트에서 DOM Parser, Tokenizer, Lexer, Parser 같은 개념들이 등장했는데, 용어도 생소했고 이런 과정들이 어떻게 작동하는지 설명할 수 없었다. 예를 들어 브라우저가 <div>Hello</div> 같은 HTML 문자열을 받았을 때, 이걸 어떤 과정을 거쳐 화면에 그리는지, 또 React에서 <div>{message}</div> 같은 JSX 코드가 어떻게 실제 DOM으로 변환되는지 그 중간 단계들을 말로 풀어낼 수 없었다.
수업을 들으면서 브라우저가 문자열을 토큰 단위로 쪼개고(<div>, Hello, </div>), 이 토큰들을 문법에 맞춰 트리 구조로 재구성한 다음, 그 트리를 메모리에 DOM 객체로 만든다는 걸 알게 되었다. JSX 역시 마찬가지로 Babel 같은 도구가 JSX 문법을 JavaScript 함수 호출로 변환하고, 그것이 다시 DOM 조작으로 이어지는 과정을 거친다는 점에서, 결국 모든 웹 기술이 이런 '언어 처리' 단계를 거친다는 걸 이해하게 되었다.
수업에서는 Syntax Analysis에서의 LL Parsing, Semantic Analysis에서의 Type Checking 같은 컴파일러의 이론적 동작 과정을 깊게 다뤘지만, 정작 Babel이나 TypeScript 컴파일러 같은 실제 웹 개발 도구들이 이런 이론을 어떻게 구현하고 있는지는 여전히 궁금한 상태로 남았다.
예상대로 어려웠고, 영어 강의였지만 교수님 덕분에 이해는 어느 정도 가능했다. 교수님은 열정이 넘치셔서 컴파일러가 수행하는 거의 모든 과정을 세세하게 설명해주셨고, 내가 부스트캠프에서 마주쳤던 의문들이 하나하나 풀리는 경험을 할 수 있었다. 웹에서 필요한 것 이상의 지식을 얻을 수 있었다.
교수님 강의가 YouTube에 올라와 있어 수업 후에도 공부할 수 있는건 되게 좋았다. 암기보다도 이해가 중요한 과목이라 학습 속도가 더뎠고, 개념 자체가 생소해서 체화하는 데 시간이 많이 걸렸다. 여전히 자신 있진 않지만, 그만큼 꾸준히 다시 돌아봐야 할 과목이라는 생각이 든다. 시험을 위한 수업이 아니라, 나중에 나의 기술 정체성을 단단하게 다질 때 다시 꺼내보고 싶은 강의였다.
고급웹프로그래밍
프론트엔드 수업을 기대하고 들었지만, 실제 구성은 대부분 백엔드 중심이었고, 프론트엔드 관련 내용은 1~2주 분량에 그쳐 아쉬움이 컸다. 프론트엔드 수업 역시 최신 흐름과는 다소 거리가 있었고, React 프로젝트를 CRA(Create React App) 기반으로 시작하는 등, 수업 자료가 현재의 개발 흐름과 괴리되어 있다는 인상을 받았다.
GPT를 중심으로 수업을 진행하신 부분은… 처음에는 뭔가 흥미로웠지만 학기가 갈 수록 금방 한계를 느끼게 되었다. AI가 제안해주는 사항들을 그대로 반영한 실습들이 반복적인 복붙 실행으로 진행되는 순간이 많았고, 가뜩이나 학습자의 수준이 그렇게 높지 않았는데 배경 지식을 고려한 맥락 설명이 많이 부족했다. 수업이 기술에 대한 설명이나 원리보다, 출력된 코드 결과를 따라가는 데 집중되는 경향이 있었다.
그동안 다른 전공 수업들에서 교수님들이 보여주셨던 수업 자료의 밀도와 설명의 정성, 그리고 흐름에 맞춘 맥락적 구성과 비교했을 때, 이번 수업은 상대적으로 정리와 전달 면에서 부족하다고 느꼈다. 동아리에서 직접 수업을 기획하고 자료를 만들며 진행했던 경험과 비교해봐도, 학습 콘텐츠 구성에 있어 더 많은 고민이 필요해 보였다.
학습 측면에서 특정한 무언가를 얻었다고 말하기는 어려운 수업이었다. GPT를 활용한 수업 모델에 대한 실험적 시도로서는 의미가 있었지만, 도구를 넘어서는 교육적 설계의 중요성을 다시금 느끼게 해준 수업이었다.
기업가정신과벤처창업
창업에 대해 진지하게 생각하게 된 수업. 전공 수업은 아니지만, 창업가 정신과 실제 창업 준비 과정(서류, 발표 등)을 경험하면서 '취업 외의 경로'를 체감했다. 창업을 당장 하지 않더라도, 준비는 되어 있어야겠다는 인식이 생겼다.
이 수업에서는 예비창업패키지 제출용 사업계획서를 팀 프로젝트 형태로 준비했는데, 어떤 아이템으로 사업을 구성할지 팀원들과 함께 결정하고 그 과정을 발표하는 수업 흐름이 기억에 남는다. 내가 무언가 중심적으로 아이디어를 제안한 것은 아니었지만, 다른 학생들의 아이디어를 함께 구상하고 발전시켜보는 과정에서 ‘창업’이라는 행위를 가까이서 체감할 수 있었던 것 같다. 실제로 어떤 내용을 사업 아이템으로 다루고, 그것을 어떻게 서류로 정리하고 발표로 풀어내는지 전체적인 맥락을 실습처럼 겪을 수 있었다.
생활수영
월요일 오전 9시 수업. 수업 자체는 단순한 수영 강습이었지만, 나의 루틴을 만드는 데 큰 역할을 했다. 하루를 알차게 시작한다는 감각은 생각보다 강력했다. 작년에 수영장문으로 이사를 온 뒤로, 근처에 수영장이 있었지만 한 번도 이용해본 적이 없었다. 학교를 다니면서 (그것도 수영장문에 살면서!) 수영장을 한 번도 못 가면 아쉬울 것 같았다. 그래서 이 수업을 듣는 것이 그런 의미에서 정말 좋은 선택이었다.
수영 실력이 절대적으로 크게 늘었다고 말하긴 어렵겠지만, 나에게는 0에서 1로 가는 전환점이었다. 수영을 전혀 못 하던 상태에서 이제는 물속에서 어느 정도 앞으로 나아갈 수 있다는 감각이 생겼고, 물에 대한 두려움이 줄었다. 그런 점에서 실력의 '크기'보다 '변화의 질'이 더 중요하게 느껴졌다. 나 스스로도 꽤 뿌듯했고, 정말 잘한 선택이었다고 생각한다.
피곤했지만 덕분에 일주일의 리듬이 정리되었고, “몸을 움직이며 시작하는 하루”가 주는 힘을 경험했다. 수영으로 하루를 시작한 월요일은 유난히 길고 밀도 있는 하루로 느껴졌고, 그것만으로도 큰 의미가 있었다.
기말고사로 수영을 25m 완주하는 것이었는데, 아쉽게도 호흡 이슈로 한 번 발을 바닥에 대어버렸다.. 그래서 감점을 당해 만점을 받지는 못 했다.
구름톤 유니브
전국 연합 동아리로, 웹 지식을 학습하고 하반기 해커톤에 참가해서 다른 학교 사람들과 팀을 구성해 실력을 검증하고 향상시키는 것이 목표였다. 회장을 맡고 있던 친구의 소개로 운영진으로 참여하게 되었고, 스터디를 지원하고 전체적인 활동이 잘 진행될 수 있도록 돕는 역할을 맡았다.
스터디는 각자 배우고 싶은 점들을 이야기해보고, 2주에 한 번씩 피드백하는 식으로 진행했다. 부스트캠프를 통해 스터디의 중요성과 장점을 잘 알고 있었기 때문에, 스터디가 엎어지지 않게 하기 위해 노력했다. 캠을 켜보자고 제안하는 등 몰입감을 높이려고 시도했지만 잘 지켜지지 않았다.
스터디 전체적으로 강의를 듣는 것에서 끝나게 되어 아쉬움이 많았다. 강의를 듣는 것에서 그치지 않고 무언가를 만들어보면 좋겠다는 생각이 있었지만 시간도 많이 없기도 했고, 학생의 본분은 어쨌든 학교에서 공부를 해서 좋은 성적을 받는 것이라고 생각했기 때문에 더 간섭하고 싶지 않았다.
각자가 처한 다양한 상황 안에서 온라인으로만 진행해 몰입감이 떨어졌던 것 같다. 원하는 만큼 잘 진행되지는 않았었다. 그래도 내가 할 수 있는 최선은 다한 것 같다.
추후 일정은 무박 2일 해커톤, 데모데이가 있다.
사진에는 없지만, 경상권 대학교 연합 해커톤도 예정되어 있다. 일정만 괜찮다면 스태프로 참여하게 될 것 같다.
전국 연합 동아리기 때문에 해커톤은 스태프가 아니라 개발을 직접하는 참여자로 나가고 싶다. 하지만 이 기간 동안 많은 과업들이 예정되어 있어 해낼 수 있을지는 잘 모르겠다. 지금까지 많은 해커톤을 해왔지만, 무작위로 팀을 짜주는 해커톤에서만 상을 타는 이상한 징크스가 있다. 그래서 이번에도 나가게 된다면.. 수상을 한다기보다 좋은 성과가 있지 않을까 하는 기대가 있다.
야구 직관 소모임
원래 야구를 너무 못 해서 안 보다가 작년부터 야구를 보기 시작했는데, 생각보다 재미있었다. 작년 성적이 아쉬웠기도 했고, 작년 성적이 아쉽기도 했고, 삼성 라이온즈가 2등을 해서 한국시리즈 기간에 학교 근처 가게들에서 다 같이 응원하는 것들이 정말 재밌어 보였다. 그래서 올해는 조금 더 잘해줬으면 좋겠다는 생각을 했었다.
소모임에 들어가게 된 계기는 이전부터 알던 편입생 친구가 운영진을 하고 있었기 때문이다. 그 친구가 소개해줘서 들어오게 되었다. 다른 사람들 얘기를 들어보니 몇 분들은 알음알음 들어온 것 같고, 조금 지내다보니 편입생들이 주가 되어서 이 소모임이 운영되고 있었다. 그래서 신기했다.
심지어 편입한 지도 얼마 되지 않은 친구들인데, 짧은 시간 안에 이 정도 규모의 집단을 이끌어나가고 있다니 새삼 지난 2년 동안 너무 전공 관련 활동만 한 게 아닌가 싶어 약간 후회가 되었다. 자발적으로 소모임을 만들어서 하는 게 정말 멋있었다.
아래 사진을 찍을 때가 4월에 대구삼성라이온즈파크(이하 라팍)로 가서 처음으로 직관을 갔던 때다. 이 때까지만 해도 항상 하던 하위권 팀이었어서 ‘그럼 그렇지’ 라는 생각으로 경기가 끝나지도 않은 8회 말에 집으로 돌아갔다. 하지만 이 다음날 같은 장소에서 말도 안되는 경기가 나오게 되어.. 이걸 직접 봤으면 더 좋았겠지만 이 날 이후로 성적이 점점 좋아졌다.
앞으로 학교를 다닐 날도 많이 남지 않았는데, 졸업 전에는 학교에서만 할 수 있는 활동들을 해보고 싶었다. 늦었지만 지금이라도 그런 경험들을 해보고 싶어서 소모임을 선택하게 되었다.
적극적으로 찾아보지 않았던 지난 1년이 후회가 되었다. 친구들은 나보다 학년도 아래고 편입 기간도 늦었는데도 이런 걸 만들어서 하는 게 정말 멋있었다. 이 소모임에서 편입생 친구들을 많이 만났다. 물론 다 편입생은 아니지만 그런 거 신경 안 쓰고 재미있게 놀 수 있었다. 덕분에 새로운 사람들을 많이 만나게 되었다.
📁 과업
쪽문네컷
2024년 9월, 추석 즈음 외주 형태로 시작된 프로젝트. 처음에는 사내 테스트용으로 기획되었지만, 3월부터 새 학기에 맞춰 결제 시스템을 붙여 오프라인 사진관 상용 서비스로 확장되었다. 학교 근처에 매장을 오픈해 고객을 받다가, 중간고사 이후에는 대구힙합페스티벌 같은 곳에 직접 나가 대여 서비스로 확장하게 되었다.
동작을 우선으로 빠르게 개발했기 때문에, 기능이 점차 추가되면서 예상치 못한 문제들이 발생했다. 결제 흐름 이슈, 모바일 레이아웃 문제, 반응형 처리 미흡 등 실사용 환경에서 다양한 개선점들이 드러났고, 사용자 피드백을 통해 실제 서비스 운영의 복잡함을 체감하게 되었다.
그럼에도 불구하고 코드를 정비하고 문제를 하나씩 해결해가며, 코드 설계와 유지보수에 대해 진지하게 고민하게 되었다. 단순히 돌아가는 것 이상의 기준—구조의 명확성, 설계 의도, 설명 가능성—이 중요하다는 사실을 실감했다. 빠르게 구현하는 것이 전부가 아니라, 이해와 설명이 가능한 코드여야 이후 확장과 유지보수가 가능하다는 교훈을 얻었다.
특히 몇 개월 전에 급하게 짠 코드를 다시 봤을 때, 당시에는 분명한 이유가 있었을 텐데 왜 그렇게 구현했는지 기억이 나지 않는 경우가 많았다. 코드 자체보다도 '왜 이 방법을 선택했는지', '다른 대안들은 왜 배제했는지', '어떤 상황을 고려해서 이렇게 설계했는지' 같은 내 생각과 판단 과정이 사라져버린 게 더 큰 문제였다.
문서화는 이전부터 중요하다고 생각했지만, 이런 경험을 반복하면서 더 중요하다 느끼게 되었다. 기능을 만든 이유, 고려했던 선택지, 예상했던 예외 상황 등 내 사고 과정을 꾸준히 기록하는 습관이 제대로 자리잡지 못했던 것 같다. 구현에만 시간을 쓰는 것도 좋지만, 아예 주말에 정리 시간을 따로 정해서라도 주기적으로 해야겠다는 생각도 든다. 그래서 다음부터는 기능을 완성하는 것 뿐만 아니라 이유와 맥락까지 함께 남기는 것을 더 철저히 습관화 해보려 한다.
쪽문네컷 프로젝트 이후에는 클래센도와 회사 홈페이지 개편 작업 등, 여러 실서비스의 유지보수와 기능 개선 작업을 이어서 맡게 되었다. 클래센도에서는 기존 코드에 기능을 확장하거나 UI/UX를 개선하는 작업들이 중심이었고, 회사 홈페이지는 3~4차례에 걸쳐 개편 작업을 반복하며 구조를 다시 설계하고, 콘텐츠 전달 방식을 개선하는 과정을 경험했다.
이런 프로젝트들은 구현을 넘어 실제 사용자가 있는 서비스를 안정적으로 유지하는 일에 더 가까웠다. 쪽문네컷의 경우 1000명 정도의 사용자가 실시간으로 피드백을 주는 상황에서, 당장 필요한 기능을 빠르게 추가하는 데만 집중하다 보니 급하게 짠 코드들이 쌓여갔다. 특히 반복적으로 고치는 작업 속에서 '완벽한 코드를 짜는 것'보다는 '오류가 생겼을 때 얼마나 빠르게 복구할 수 있는가', '코드를 보고 신속하게 상황을 이해하고 정리해낼 수 있는가'가 더 중요하다는 생각이 점점 선명해졌다.
아직 많이 부족하고, 시행착오도 계속 겪고 있지만, 그 경험들이 쌓이면서 점차 “코드만 잘 짠다고 끝나는 일은 아니다”라는 실감이 깊어졌다. 개발은 결국 오랜 시간 동안 유지될 시스템을 설계하는 일이기도 하다는 걸 점점 몸으로 배우고 있다.
Classendo
쪽문네컷 이전부터 지속적으로 진행되어온 프로젝트. 초등학교 선생님들의 학생 평가 업무를 간소화해주는 서비스로, 매일 쌓이는 서류작업과 행정 업무로 인해 본질적인 교육 활동에 집중하기 어려운 현실을 개선하고자 개발되었다.
과정 중심 학생 평가가 선생님들에게는 업무 부담으로 다가오는 상황에서 클릭 몇 번으로 학생들의 성취기준 평가 등급을 입력할 수 있고 일괄 적용을 통해 한 번에 평가 등급을 업데이트할 수 있다. 평가가 완료되면 NEIS에 자동으로 업로드되어 업무 효율성을 크게 높일 수 있는 구조다. 한 번에 여러 과목을 가르치는 담임 선생님이나 한 과목을 여러 반에서 가르치는 교과 선생님 모두 사용할 수 있도록 설계되었다.
실제 교육 현장에서 사용되는 서비스이다 보니 교육과정 변화에 따른 지속적인 업데이트가 필요했다. 특히 올해 상반기에 2022 개정 교육과정이 초등학교 3~4학년을 대상으로 변경되면서 관련 과목들을 조정하는 작업을 진행했다. 기술적으로는 크게 복잡하지 않았지만, 이미 사용자가 있는 서비스를 건드리는 일이라 신중하게 접근해야 했다.
internal-tools
서비스들을 운영하면서 필요하게 된 내부 관리 도구들을 모아놓은 프로젝트. 특히 쪽문네컷이 렌탈 서비스로 피벗팅하면서 관리 기능의 필요성이 커졌다.
이전에는 개발자가 일일이 값을 직접 DB에 넣는 식으로 진행했다. 사실 이런 기능에 대한 요소가 없었고, 시제품이기도 해서 관리 기능 개발 소요가 측정되지 않기도 했다. 그래서 DB에 직접 넣는 게 아니라 서비스 형태로 넣어주면 좋겠다는 생각이 들었다.
이렇게 하면 새로운 값을 넣어야 할 상황이 왔을 때 꼭 개발자가 아니더라도 넣을 수 있겠다고 생각했다. 프로젝트와 팀 특성 상 기업들의 요청 사항들이 종종 있어왔고, 결과적으로 개발자의 일을 줄일 수 있을 것이라 판단했다. 특히 모바일에서도 사용 가능하도록 설계해 현장에서 바로바로 고객사로부터 받은 사진을 소통 채널로 받아서 업로드할 수 있을 정도로 접근성을 높이려고 했다.
그런 것 말고도 운영하면서 편의사항이 생길만한 요소들을 더 생각해보면서 정말 도움이 될 수 있는 것들을 넣으려고 했다. 예를 들어 i18n을 적용하게 되면 JSON 파일이 정말 길어지게 되는데, 개발하다보면 누락되는 것들도 생길 수 있다. 어떤 것들은 영어만 번역되거나, 한글만 번역되는 상황도 있었다.
이런 식으로 개발자가 아니라 번역에 일가견이 있으신 다른 분이 봐야 할 상황이 생기기도 한다. 도와주시는 분이 방대한 JSON 파일을 보게 된다면 보자마자 의욕이 떨어질 것이다.
그래서 이걸 보기 좋게 시각화해서 웹으로 보여주게 되면 작업하는 사람의 입장에서도 편할 것이라 생각했다. 개발자도 따로 이걸 텍스트로 바꿔서 변환하고, JSON으로 변환해주는 작업을 하지 않아도 된다. 또 서비스로 이걸 보여주게 된다면 작업 현황을 퍼센트로 표시해서 동기부여를 불러일으켜 생산성을 높일 수도 있을 것이다.
위와 같은 일련의 사건들로 인해 필요성을 느껴 개발을 시작하고 있다. 아직은 제작 중이다.
Denamu
작년 네이버 부스트캠프에서 시작한 6주짜리 프로젝트. 짧은 시간 안에 MVP를 만들어야 했기 때문에 완성도보다는 속도에 중점을 둔 개발이 많았고, 프로젝트가 끝난 후에도 '이걸 좀 더 다듬고 사용자에게 실제로 제공해보면 어떨까?'라는 고민이 계속 남았다. 그렇게 팀원들과 함께 프로젝트를 이어가고 싶었지만, 취업 준비, 복학, 병행 중인 다른 프로젝트들 등 각자의 사정들로 인해 자연스럽게 우선순위에서 밀리게 되었다.
그럼에도 불구하고 포기할 수 없었던 이유는 여전히 이 서비스를 통해 사용자 피드백을 받아보고 싶다는 갈증이 컸기 때문이다. 쪽문네컷이 '너무 빠른 생산성'에 초점을 맞추다가 유지보수가 어려워졌다면, Denamu는 '사용자 경험을 제대로 확인해보지 못했다'는 점에서 계속 미련이 남는 프로젝트였다. 오히려 그 미완성 상태가 동기부여가 되기도 했다.
한편으로는 팀워크를 흐리지 않기 위해 중간에 그만두는 것이 맞을까 고민도 많았지만, "내가 발목을 잡고 있지는 않을까?"라는 죄책감보다는 서로의 상황을 이해하고 맞춰가는 게 더 건강한 방식이라 느끼며, 조금씩이라도 프로젝트를 이어가고자 했다. 지금도 사용자를 받아보고 싶은 욕심은 남아 있고, 이를 위해 새로운 구조나 기술(MCP 등)을 도입해 빠르게 개선하려는 움직임도 있다. 다만 실질적인 사용자 제공까지 시간이 더 필요한 이유는 기술적 기반보다는 팀원들의 현실적인 사정 때문이다. 개발을 함께 하던 5명의 팀원 중 일부는 취업 준비 등으로 인해 프로젝트에서 이탈하거나, 남아 있는 팀원들조차 개인 사정으로 프로젝트에 충분한 집중을 하지 못하고 있다. 그 결과, 프로젝트는 점점 각자의 우선순위에서 밀리게 되었고, 현재는 정체된 상태에 가깝다.
나는 이 프로젝트를 처음 설계할 때 지속적으로 개발 가능한 구조를 만들고 싶어서 마일스톤을 정하고, 역할을 나누고, 가능한 한 명확하게 방향을 제시하려고 노력했지만, 실질적으로 동기부여가 될 만한 요소들을 팀 내부에서 적극적으로 끌어내지 못한 것 같다는 아쉬움이 남는다. 그래서 지금의 정체가 단순히 외적 상황 때문만은 아니라는 생각도 든다. 그럼에도 불구하고 여전히 이 서비스에 대한 애정은 남아 있고, 언젠가 이 경험이 더 큰 무언가로 이어질 수 있지 않을까 기대하고 있다.
blog
블로그를 또 만들고 있다..
이전부터 Notion을 CMS로 두고 블로그를 만들고 싶었다. 지금까지 정리해둔 글들이 다 Notion에 있어서 옮기기가 사실 편한 일은 아니었다. 그리고 편집하기 되게 편하고, 이걸 연계해서 여기다가 글을 적어놓고 다른 사람들에게 보여주면 금방 발행할 수 있겠다 생각했다.
나만 이런 생각을 했던게 아니었던지 지금까지 oopy 같은 서비스들도 나오고 그랬었다. 그래서 23년도에 만드려는 시도를 했었는데 잘 안되었다. 글이 너무 느리게 로드되었고, 설상가상으로 markdown 중 일부 컴포넌트들이 깨져서 보였다. 그래서 원하는대로 글이 보여지지 않았다.
그래서 한동안 tistory에서 글을 계속 쓰다가, 작년에 부스트캠프를 하면서 다양한 사람들의 각자 만든 블로그를 보고 다시 의욕이 생기게 되었다. Notion의 편의성을 무시할 수는 없기에 다시 시도하기로 했다.
글이 로드될 때 되게 느린건 원래는 Notion API로 글을 그 서버에서 직접 끌어다가 써서 오래 걸렸다. 이번에 구현하면서 생각한거는 특정 시간마다 한 번씩 Notion에서 글을 가져와, markdown 형식으로 직접 갖고 있다가 그걸 보여주는 식으로 구현하기로 생각했다. 그렇게 되면 로드될 때 시간이 많이 들지는 않으니 예상대로 처음 딱 글을 접근했을 때 막 몇 초씩 기다리지 않아도 됐다.
하지만 이 방식도 만만치 않았다. 기존에는 실시간과 가깝게 1시간마다 Notion에서 글의 정보를 가지고 오면서 구현했었는데, Github actions 무료 요금에 제한이 걸려 이런 방식으로는 지속할 수 없겠다 싶었다. 하루 주기로 늘리니 Notion에서 글을 수정해도 다음 날에 일괄적으로 업데이트되었다. 캐싱 전략도 고민이 많았다. 권한 문제로 인해 이미지를 Notion 링크 그대로 보여줄 수 없다. 이런 것 때문에 사진을 어디에 가지고 있어야 할지도 고민을 많이 했다.
아직도 제작 중이긴 한데, 블로그 미완성을 이유로 글을 못 적는게 지속되어 미완성 상태더라도 계속 글은 배포해보려 노력 중이다.
YouViCo
기존 프로젝트에서 Nuxt를 사용하게 되었다. Vue 기반의 풀스택 프레임워크로, React의 Next.js와 비슷한 역할을 한다.
그래서 최근에 Vue 코드를 보고 있는데, 확실히 React에 비해 내재되어 있는 설계 사상이 많이 다르다.
v-model의 양방향 바인딩
양방향 바인딩(Two-way data binding)은 데이터와 UI가 서로 동기화되는 방식이다. 사용자가 입력 필드에 무언가를 타이핑하면 자동으로 데이터가 업데이트되고, 반대로 데이터가 변경되면 UI도 자동으로 업데이트된다. 마치 두 개가 실시간으로 서로를 반영하는 것처럼 동작한다.
React는 단방향 데이터 흐름을 고수한다. 데이터는 항상 한 방향(State → UI)으로만 흐르고, UI에서 발생한 이벤트는 명시적인 핸들러를 통해서만 State를 변경할 수 있다. 이런 설계는 데이터 변경이 언제, 어디서, 왜 일어났는지 추적하기 쉽게 만든다. 예를 들어 입력값 검증이나 포맷팅이 필요한 경우, onChange 핸들러 안에서 이를 처리할 수 있어 유연성이 높다.
그래서 이런 동작을 위해 명시적으로 코드를 작성해야 했다.
function LoginForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
return (
<form>
<input
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="이메일"
/>
<input
value={password}
onChange={(e) => setPassword(e.target.value)}
type="password"
placeholder="비밀번호"
/>
</form>
);
}
Vue에서는 v-model이 이 모든 과정을 자동으로 처리한다.
<template>
<form>
<input v-model="email" placeholder="이메일" />
<input v-model="password" type="password" placeholder="비밀번호" />
</form>
</template>
<script setup>
import { ref } from 'vue'
const email = ref('')
const password = ref('')
</script>
코드량 차이가 확연하다. React에서는 value와 onChange를 각각 설정해야 하지만, Vue는 v-model 하나로 끝난다. 내부적으로 Vue가 입력 이벤트를 감지하고 데이터를 업데이트하는 작업을 대신 해주기 때문이다.
처음엔 자동으로 되어서 편했지만, Vue의 양방향 바인딩에도 단점이 있었다.
복잡한 폼에서 데이터 흐름을 추적하기 어려웠다. 여러 컴포넌트에서 같은 데이터를 수정할 수 있을 때, 어디서 값이 변경되었는지 찾기가 까다로웠다.
<input
value={email}
onChange={(e) => {
debugger; // breakpoint로 호출 스택 추적 가능
setEmail(e.target.value);
}}
/>
<input v-model="email" />
<!-- 값이 바뀌는 순간을 직접 감지하려면 watch를 추가로 써야 함 -->
입력값을 가공하거나 검증하려면 추가 작업이 필요했다. React에서는 onChange 안에서 바로 처리할 수 있는데, Vue에서는 별도의 computed나 watch를 만들어야 했다.
<input
value={phone}
onChange={(e) => {
const cleaned = e.target.value.replace(/\\D/g, '');
const formatted = cleaned.replace(/(\\d{3})(\\d{4})(\\d{4})/, '$1-$2-$3');
setPhone(formatted);
}}
/>
<template>
<input v-model="phone" />
</template>
<script setup>
const phone = ref('')
// 로직이 template과 떨어져 있음
watch(phone, (newValue) => {
const cleaned = newValue.replace(/\\D/g, '');
phone.value = cleaned.replace(/(\\d{3})(\\d{4})(\\d{4})/, '$1-$2-$3');
})
</script>
더 큰 문제는 프로젝트가 커질수록 이런 분리가 심해진다는 것이었다. 폼 검증, 데이터 변환, API 호출 등 여러 로직이 template, computed, watch, methods에 흩어져 있어서 하나의 기능이 어떻게 동작하는지 파악하려면 코드 위 아래를 오가며 확인해야 했다.
computed 속성의 캐싱
Vue의 computed는 React의 useMemo와 비슷하면서도 다르다. 둘 다 계산 결과를 캐싱하지만, Vue는 의존성을 자동으로 추적한다.
const totalPrice = useMemo(() => {
return items.reduce((sum, item) => sum + item.price * item.quantity, 0);
}, [items]); // 의존성 배열 필수
<script setup>
const items = ref([...])
const totalPrice = computed(() => {
return items.value.reduce((sum, item) => sum + item.price * item.quantity, 0);
})
// items가 바뀔 때만 재계산, 의존성 배열 불필요
</script>
Vue의 자동 의존성 추적이 생각보다 편리했다. React에서 자주 겪었던 의존성 배열 누락 버그가 Vue에서는 원천적으로 불가능했다.
const totalPrice = useMemo(() => {
return products.reduce((sum, product) => {
return sum + product.price * (1 - discount);
}, 0);
}, [products]);
위 코드는 discount가 변경되어도 totalPrice가 재계산되지 않는다. 이런 버그는 런타임에서야 발견되는 경우가 많다.
Vue는 Proxy를 사용해 이 문제를 근본적으로 해결한다. computed가 실행될 때 Vue가 자동으로 의존성을 추적하는 과정은 이렇다.
- computed 함수가 실행되면 Vue가 "의존성 수집 모드" 시작
- 함수 내에서
products.value,discount.value등에 접근 - Proxy가 이 접근을 감지하고 "이 computed는 products와 discount에 의존한다"고 기록
- 이후 products나 discount가 변경되면 자동으로 재계산
개발자는 그냥 computed 안에서 필요한 데이터를 사용하면 된다. 의존성 배열을 관리할 필요가 없어서 실수할 여지가 사라진다.
그렇지만 이 자동화에도 단점이 있었다. computed 안에서 실수로 다른 반응형 데이터를 참조하면 의도치 않게 의존성이 생겨버렸다.
<script setup>
const userSettings = ref({ theme: 'dark' })
const products = ref([...])
const totalPrice = computed(() => {
// 디버깅용 console.log인데..
console.log('현재 테마:', userSettings.value.theme);
return products.value.reduce((sum, p) => sum + p.price, 0);
})
// userSettings.theme가 바뀔 때마다 totalPrice도 재계산됨
</script>
디버깅이나 로깅을 위해 임시로 넣은 코드가 의존성이 되어버리는 경우가 있었다. React처럼 의존성을 명시적으로 관리하는 게 오히려 예측 가능할 때도 있었다.
watch와 watchEffect
Vue의 watch와 watchEffect는 React의 useEffect와 비슷하지만 더 세분화되어 있다. React는 useEffect 하나로 모든 부수 효과를 처리하는데, Vue는 용도에 따라 나누어 제공한다.
useEffect(() => {
console.log('user가 변경됨:', user);
}, [user]);
<script setup>
watch(user, (newUser, oldUser) => {
console.log('변경 전:', oldUser);
console.log('변경 후:', newUser);
})
watchEffect(() => {
// user나 settings 중 하나라도 변경되면 실행
console.log(user.value.name, settings.value.theme);
})
</script>
watch는 이전 값과 새 값을 비교할 수 있어서 유용했다. React에서는 이전 값을 보려면 useRef로 따로 저장하는 작업이 필요하다.
const prevValueRef = useRef();
useEffect(() => {
console.log('변경:', prevValueRef.current, '→', value);
prevValueRef.current = value; // 다음 렌더링을 위해 저장
}, [value]);
watch(value, (newVal, oldVal) => {
console.log('변경:', oldVal, '→', newVal);
// 바로 사용 가능
})
페이지 변경이나 폼 수정 같은 상황에서 "무엇이 어떻게 바뀌었는지" 바로 알 수 있어서 편했다.
Pinia 상태관리
Pinia는 Vue의 공식 상태 관리 라이브러리로, React의 Redux나 Zustand와 같은 역할을 한다.
이전 버전인 Vuex는 Redux와 비슷한 구조였는데, 오히려 더 복잡했다. Redux는 action → reducer 2단계인데, Vuex는 action → mutation → state 3단계였다. 상태를 변경하려면 mutation을 commit하고, 비동기 작업은 action을 dispatch해야 하는 등 보일러플레이트가 많았다.
// Vuex
// store.dispatch('fetchUser') → action → commit('SET_USER') → mutation → state 변경
// Pinia
// store.fetchUser() → 바로 state 변경
Pinia는 이런 복잡함을 제거하고 action 하나로 모든 걸 처리할 수 있게 만들었다. React의 Zustand처럼 직관적이면서도 TypeScript 지원이 잘 되어있어서 사용하기 편했다.
export const useUserStore = defineStore('user', {
state: () => ({
user: null,
isLoggedIn: false
}),
getters: {
userName: (state) => state.user?.name || 'Guest'
},
actions: {
async login(credentials) {
const user = await api.login(credentials);
this.user = user;
this.isLoggedIn = true;
}
}
})
const useUserStore = create((set, get) => ({
user: null,
isLoggedIn: false,
userName: () => get().user?.name || 'Guest',
login: async (credentials) => {
const user = await api.login(credentials);
set({ user, isLoggedIn: true });
}
}))
state, getters, actions로 역할이 나뉘어 있어서 이해하기 쉬웠다.
Nuxt의 파일 기반 라우팅
Nuxt의 라우팅 시스템은 Next.js와 비슷하지만 세부적인 차이가 있었다. 둘 다 파일 시스템 기반 라우팅을 제공하지만, 구조와 사용법이 조금씩 달랐다.
// Nuxt
pages/
├── index.vue // '/'
├── users/
│ ├── index.vue // '/users'
│ └── [id].vue // '/users/:id'
└── posts/
└── [...slug].vue // '/posts/*' (catch-all)
// Next.js
app/
├── page.tsx // '/'
├── users/
│ ├── page.tsx // '/users'
│ └── [id]/
│ └── page.tsx // '/users/:id'
└── posts/
└── [...slug]/
└── page.tsx // '/posts/*' (catch-all)
Nuxt는 파일명으로 라우팅을 정의하는 반면, Next.js의 App Router는 폴더 구조와 page.tsx 파일을 사용한다.
특히 Nuxt의 <NuxtLink>와 navigateTo() 같은 네비게이션 API가 React Router나 Next.js의 Link와 미묘하게 달라서 적응이 필요했다. 프리페칭이나 트랜지션 처리 방식도 달라서, 기존 React 경험을 그대로 적용하기 어려웠다.
결론적으로 Vue/Nuxt 생태계는 React와 많은 면에서 비슷하면서도 철학적으로 다른 접근을 취하고 있었다.
Vue는 "Progressive Framework"라는 철학답게 개발자가 점진적으로 학습하고 적용할 수 있도록 설계되어 있었다. 템플릿 문법은 HTML에 가까워서 디자이너나 퍼블리셔도 이해하기 쉬웠고, 필요한 기능들이 프레임워크에 내장되어 있어서 별도의 라이브러리 선택 고민이 적었다.
React의 "It's just JavaScript" 철학과는 정반대였다. React는 모든 것을 JavaScript로 해결하려 하고, 개발자에게 완전한 제어권을 주는 대신 모든 선택의 책임도 개발자에게 있었다. 반면 Vue는 "이미 최선의 방법을 정해놨으니 그대로 따라오면 돼"라는 느낌이었다.
처음엔 Vue를 별로 좋아하지 않았다. "왜 개발자에게 제약을 걸지?"라는 생각이 강했다. React에 익숙해져 있던 나로서는 프레임워크가 정해놓은 방식을 따라야 한다는 게 답답했다. 내가 원하는 대로 구현할 자유가 없다는 느낌이었다.
하지만 시간이 지나면서 오히려 "이런 프레임워크가 왜 이렇게 구성되었을까?"라는 생각을 해보게 되었다. Vue가 개발자의 자유도를 제한하는 대신 얻는 것들이 뭔지 관찰해보니, 팀 협업에서의 일관성, 신입 개발자도 쉽게 따라올 수 있는 학습 곡선, 실수할 여지를 줄여주는 안전장치 같은 것들이었다.
React의 자유도가 주는 유연함도 좋지만, Vue의 제약이 주는 안정감도 나름의 가치가 있다는 걸 깨달았다. 결국 어떤 상황에서 어떤 도구를 쓸지는 프로젝트와 팀의 성격에 따라 달라지는 문제였다.
📁 OKR
OKR은 'Objectives and Key Results'의 약자로, 명확한 목표(Objectives)와 그 목표를 달성하기 위한 핵심 결과(Key Results)를 설정하고, 주기적으로 측정하고 반성하는 일하는 방식이다. 처음에는 이 개념이 다소 생소했지만, 프로젝트의 목적성과 실행 계획을 체계화하는 데 매우 효과적이라는 것을 느꼈다.
이전에는 프로젝트마다 뚜렷한 목표 없이, 떠오르는 대로 작업을 하고 우선순위를 명확히 하지 못한 채 흘려보낸 경우가 많았다. 하지만 OKR을 도입하면서 스프린트 단위로 '지금 내가 해야 하는 일'이 구체화되었고, 장기적인 방향 속에서 당장의 업무가 어떤 의미를 갖는지를 자각하게 되었다. 단순히 열심히 한다는 느낌이 아니라, '왜 이걸 하는가'에 대한 명확한 이유와 구조가 생겼다.
또한, 작업을 단위별로 쪼개고 문서화하는 습관이 함께 생기면서 프로젝트에 대한 애정도 자연스럽게 깊어졌다. 정리의 틀을 만들어 놓고, 기록하고, 되짚는 과정을 반복하다 보니 문서화는 단순히 결과만을 남기는 것이 아니라 감정과 맥락까지 함께 담아내는 기록으로 변했다. 나중에 버그를 수정하거나 회고를 작성할 때 그런 기록들이 다시 돌아볼 수 있어 체감될 정도로 좋았고, 그 과정 속에서 내가 프로젝트를 바라보는 시선도 바뀌었다. 이전에는 '일단 만들어서 돌아가면 성공'이라는 단순한 기준을 가지고 있었지만, 점점 '그게 왜 그렇게 작동하는지', '누구에게 어떻게 설명할 수 있을지', '앞으로도 안정적으로 유지할 수 있는 구조인지'에 대한 고민이 더 중요해졌다. 기능 하나를 넣는 것도, 그것이 전체 흐름에 어떤 영향을 주는지를 설계단계부터 고려하게 되었고, 프로젝트를 단순한 결과물이 아닌 하나의 살아 있는 시스템으로 대하기 시작한 것 같다. 결국 이 모든 것이 정리를 넘어서 더 나은 방향으로 나아가기 위한 관찰의 능력을 기르게 되었다.
하지만 시간이 지나면서 OKR을 설정하고 실행하는 흐름이 점차 무너진 것도 사실이다. 시험 기간이나 개인 일정이 겹치면서 스프린트 단위의 리듬이 끊기게 되었고, 그로 인해 OKR을 쓰는 일 자체가 점점 어려워졌다. 어떤 스프린트는 아예 기록하지 않게 되고, 그렇게 한두 번 건너뛰다 보니 결국 전체 OKR 루틴 자체가 흐려지게 되었다. 프로젝트 관리자(PM) 역할을 하던 사람도 다른 업무에 과중되면서 OKR을 챙기기 어려워졌고, 그렇게 팀 전체에서 OKR이라는 틀이 점차 기억 속에서 사라지게 되었다.
작업 단위를 작게 쪼개서 관리하지 않으면, 사소한 것 하나도 놓치게 되기 마련이고, 이게 쌓이면 중요한 것까지 흐려진다. 예전엔 누군가 챙겨주지 않으면 나도 같이 안 하게 되는 경향이 있었던 것 같다. 하지만 지금은 그런 수동적인 태도에서 벗어나야겠다는 생각이 든다. '왜 지금 OKR을 하지 않고 있지?'라는 질문을 내가 스스로 던지고, 팀이 놓치고 있는 부분이 있다면 먼저 시도해보는 자세가 필요하다. 시도하고 실패하면 그때 다시 조정하면 되지, 처음부터 안 하기로 결정해버리는 건 너무 이르다.
그래서 이 회고를 작성하면서 가장 강하게 느끼는 점은, 다음 스프린트에서는 누가 시키지 않아도 스스로 계획하고, 기록하고, 점검할 수 있도록 나 자신이 주도적으로 이끌어야겠다는 다짐이다. 이건 단순한 작업 루틴이 아니라, 내가 어떻게 일하고자 하는지를 보여주는 태도의 문제이기 때문이다. 문서화와 OKR은 결국 나 자신이 애정을 가지고 프로젝트를 지속하려는 의지의 표현이라는 걸, 이번 학기를 통해 조금씩 배워가는 중이다.
📁 상담
이번 학기는 심리적으로 위축되고 많이 지쳐 있었던 시기였다. 특히 취업 준비와 인간관계에서 내가 보여주고 싶었던 최선의 모습을 나름대로 다 해봤음에도, 그 결과가 따라주지 않는 상황이 반복되면서 스스로를 더 지치게 만들었던 것 같다. 하필 시험기간 때 이런 생각이 심하게 들어 기존 루틴에 영향을 주었고, 식욕도 많이 떨어져 밥도 잘 안 먹게 되었다. 뭔가 먹는 행위 자체에 대한 동기나 에너지가 이전보다 덜 했다.
자신감은 작년 말과 비교했을 때 많이 줄어들었다. 내적으로나 외적으로나 무너지고 있다는 느낌이 강하게 들었던 기간이었다. 그래서 결국 학교 상담센터에 찾아가 상담을 받게 되어 지금은 많이 좋아지고 있다.
처음에는 '버텨야 한다'는 생각이 강했지만, 점차 ‘내 삶을 살아야 한다’는 방향으로 사고가 전환되었다. 프로젝트로 함께 무언가를 해나갈 수 있는 기회가 생기면서, 적어도 지금 당장의 가장 큰 불안 요소는 하나 해결된 셈이었다. 하지만 한편으로는 '이제는 정말 이걸 안정적으로 지켜내야 한다'는 새로운 부담도 함께 생겼다. 특히 서비스가 살아 있는 상태로 운영되면서, 언제 어디서든 문제가 발생할 수 있다는 압박감은 생각보다 컸다. 오히려 그런 감정이 쌓이면서 마음 한켠의 여유를 무너뜨리는 데 작게나마 기여했던 것 같기도 하다.
취업이나 인간관계 모두 중심에 있어야 하는 건 '나 자신의 삶'이라는 점이었다. 나를 우선에 두지 않으면 오히려 더 흔들리고 기대가 무너지며 실망하게 되는 일이 반복되었다. 그래서 지금은 인간관계에서도 기대보다는 관찰과 거리 두기를 택하게 되었고, 내 감정에 스스로 책임지는 법을 조금씩 배워가는 중이다.
상담을 받으면서 체화시키면 좋겠다고 생각이 드는 몇 가지를 정리해보았다. 상담을 받으면서 어디에다가 적어뒀으면 되게 좋았을 것 같은데, 이해하고 그 느낌을 체화하는 것에 집중을 한 나머지 기록을 제대로 하지 못 했다. 그래도 상담을 받으면서 다 좋았지만 기억에 남는 것들을 위주로 작성을 해보려 한다.
모든 것을 다 얻을 수는 없다
이전부터 학업과 병행하면서 프리랜서로 일을 하고 있었는데, 거기에다가 취업 준비를 같이 하고 있었던 순간이 있었다. 취업 준비를 하지 않아도 졸업 후에 바로 취업을 해야겠다는 생각이 있었고, 졸업을 하고 바로 하지 않더라도 빠른 시일 내에 취업을 해야겠다는 생각을 크게 가지고 있었던 것 같다.
왜 빨리 해야 하는지에 대해서는 주변에 많은 사람들이 누구나 가고 싶어하는 회사에 인턴이나 정규직으로 들어가는 것들을 많이 봐와서 그런 것 같다. 어쨌든 학업, 프리랜서 업무, 취업 준비라는 세 가지의 큰 태스크들을 한꺼번에 다 가져가려고 했던 것 같다.
다른 사람들에 비해 학생 신분이지만 이미 회사와 일을 하고 있고, 어떻게 보면 취업 준비를 지금 당장 하지 않아도 경험을 쌓고 있는 일이기 때문에 모든 걸 다 할 수 없다면 내려놓을 줄도 알아야 한다는 걸 깨달았다. 그렇다고 취업 준비를 포기하는 건 아니긴 한데, 지금 당장은 준비를 하지 않는 게 맞다는 판단을 했다. 일단 학교를 다니고 있고 학기 중에는 학생의 본분을 다해야 했기 때문에 학업을 포기하면서까지 취업 준비를 할 수는 없었다.
과도한 책임감은 오히려 역효과를 불러온다
프리랜서 일 때문에 조금 과도한 책임감이 들었던 부분이 있었다. 생각보다 나한테 주어진 일이 많았는데, 초기에는 1의 업무를 한다면 조금 지나면 10개의 일, 100개의 일.. 점점 기존 능력을 벗어나는 일들도 많이 하게 되었다.
사실 일을 하면서 다 해봤던 걸 할 수는 없을 것이다. 성장도 그 동안 안 해본 것들을 도전하면서 늘어가는 것이라 생각한다. 문제는 이렇게 안 해본 걸 많이, 그것도 짧은 시간 안에 하게 되면서 미지의 구간을 탐구해가는 재미보다는 부담으로 조금 더 다가왔던 것 같다. 새로운 걸 배우는 즐거움보다는 압박감이 더 커진 느낌이었다.
뭔가 모든 걸 완벽하게 해내야 한다는 생각에 사로잡혀 있었던 것 같다. 하지만 그런 마음가짐이 오히려 일 자체를 더 힘들게 만들고, 결국은 번아웃으로 이어졌던 것 같다.
지금은 완벽주의를 내려놓으려고 노력하고 있다. 우선순위를 확실하게 정해놓고, 정해진 시간 안에서만 일을 하려고 한다. 물론 긴급한 상황이 생기면 근무 시간 외에도 일하긴 하지만, 그런 게 아니라면 정해진 시간 안에서 최고의 퍼포먼스를 내려고 한다. 오히려 그게 일을 늘어지게 하지 않는 데도 도움이 되는 것 같다.
가벼운 이야기들을 할 수 있는 친구들을 만들자
지금까지 내 주변 사람들을 보면 대부분 개발하는 사람들이고, 컴퓨터와 관련되지 않은 사람들은 별로 만나지 않았다. 그러다 보니 개발이나 기술 얘기가 아닌 일반적인 대화를 할 때 어색했다. 무슨 말을 해야 할지 잘 떠오르지 않았다. 현재는 카카오톡 오픈채팅방(이하 옵챗방)이 일반 채팅방과 분리되어 있지만, 그렇지 않을 때에는 개발 관련 옵챗방이 항상 맨 위에 도배되어 있었다. 그 정도로 개발 소식이 나에게는 중요했고, 그렇지 않은 것들은 항상 차순위였다.
이런 상황이 계속되면서 대화의 폭이 좁아지고 있다는 느낌이 들었다. 개발 소재 이야깃거리는 익숙해서 잘 할 수 있지만, 오히려 가볍고 재미있는 일상 대화는 잘 안 되는 것 같았다.
상담선생님께 이런 고민을 얘기했더니, 스몰토크를 할 수 있는 사람들을 많이 만나보라고 하셨다. 영양가 없어 보이는 가벼운 대화들도 사람과의 관계를 만들어가는 데 중요하다는 얘기였다. 다행히도 기존에 중앙동아리를 하고 있어 이런 환경에서 다양한 사람들과 만나면서 말을 많이 하게 된 것 같다. 아직 얼마 안 되긴 해서 더 다양한 경험을 가진 사람들과 이야기해봐야겠지만, 이전보다 확실히 폭넓게 이야기를 나눌 수 있게 되어 좋았다.
예전에는 이런 시간들을 의미 없다고 생각했는데, 이런 것들도 나를 성장시키는 과정인 것 같다.
인생은 계획대로 되지 않는다
내가 계획한 것은 무조건 그대로 되어야 한다는 생각이 강했다. 조금만 어긋나더라도 납득이 안 되고 스트레스를 받았다. 모든 걸 통제하고 예측 가능하게 만들려고 했는데, 그게 오히려 더 힘들게 만들고 있었다.
학업 계획부터 시작해서 원래는 이번 학기에 부스트캠프가 끝난 걸 정리하는 식으로 공부에 집중하려고 했었다. 그런데 같이 서비스를 만들자고 제안해주신 분이 있어서 계속 개발을 하게 되었고, 공부 정리는 많이 못 했다. 프로젝트 일정 같은 경우에도 원래 계획이 있었는데, 급하게 처리해야 할 일들이 게릴라성으로 생기면서 새로운 프로젝트들로 인해 기존 일정도 계속 어긋나게 되었다. 물론 이렇게 만들어진 프로젝트들이 무산되는 경우도 종종 있었다. 그런 이슈들이 한두 개가 아니라 여러 개가 오다 보니까 집중하지 못 했다.
인간관계에서도 '이렇게 했으니까 이렇게 되겠지' 하는 생각을 가지고 있었지만 예상과 다르게 흘러가는 경우가 많았다. 나는 상황을 통제하는 걸 좋아했던 것 같은데, 그런 상황들이 통제되지 않고 내 맘대로 되는 게 하나도 없어서 힘들었던 것 같다.
상담에서 이런 얘기들을 나누면서 더 이상 어떤 게 잘 되는지 안 되는지 억지로 생각하지 않으려고 하게 되었다. 통제하려는 일들을 많이 줄이려고 노력하고 있다. 지금은 계획이 어긋날 때 그냥 유연하게 대처하려고 생각하고 있다. 무슨 일이 생겨도 마음속으로 힘들어하지 않고 언제든 어긋날 수 있다고 생각한다.
실제로 어긋나면 그 상황에서 최대한 유연하게 대처하고 맡은 일을 처리하려고 노력 중이다. 이렇게 하다 보니 요즘 흘러가는 대로 살자는 생각을 많이 하게 된 것 같다.
포기해야 하는 고통
포기한다는 것은 나에게 가장 어려운 일이었다. 특히 내가 시간과 노력을 쏟아부은 일들을 중단해야 할 때, 그 결정이 정말 힘들었다. 투자한 시간이 아까워서, 남들이 어떻게 볼까 두려워서, 실패를 인정하기 싫어서 계속 붙잡고 있었다.
상담을 통해 깨달은 것은 포기도 하나의 선택이고 용기라는 점이었다. 모든 걸 다 가져갈 수 없다면, 무엇을 놓을 것인지 결정하는 것도 중요한 능력이었다. 안 되는 걸 붙잡고 있는 시간에 새로운 기회를 놓칠 수도 있다는 걸 알게 되었다.
특히 '매몰비용의 오류'에서 벗어나는 게 중요했다. 이미 투자한 시간과 노력 때문에 미래까지 망칠 필요는 없었다. 포기하는 순간은 고통스럽지만, 그 고통을 견디고 나면 오히려 새로운 가능성이 열린다는 걸 경험했다.
관계에 따른 대화의 범주
모든 사람과 깊은 대화를 나눌 필요는 없다는 걸 배웠다. 관계의 깊이에 따라 대화의 수준도 달라져야 한다는 게 상담선생님의 조언이었다.
처음 만난 사람과는 날씨, 음식, 취미 같은 가벼운 주제로 시작하는 게 자연스럽다. 너무 깊은 이야기를 꺼내면 상대방이 부담스러워할 수 있고, 반대로 아무 정보도 주지 않으면 벽을 치는 것처럼 보일 수 있다.
친밀도가 쌓이면서 점진적으로 개인적인 이야기를 나누는 게 건강한 관계다. 나는 그동안 이런 단계를 무시하고, 모든 사람과 0 아니면 1의 관계를 맺으려 했던 것 같다. 지금은 관계의 온도를 맞춰가며 대화하는 법을 연습하고 있다.
좋은 것은 왜 좋은지 탐색해보기
상담선생님이 해주신 흥미로운 질문이 있었다. "좋아하는 것들을 왜 좋아하는지 생각해본 적 있나요?" 단순히 좋다, 싫다로 끝내지 말고 그 이유를 탐색해보라는 것이었다.
예를 들어 코딩이 좋다면, 문제를 해결하는 과정이 좋은 건지, 무언가를 만드는 창조의 기쁨인지, 논리적 사고가 맞는 건지 구체적으로 파악해보는 것이다. 이렇게 하면 내가 진짜 원하는 게 무엇인지 더 명확해진다.
반대로 힘든 것들도 왜 힘든지 분석해보면 해결책이 보인다. 막연히 "취업 준비가 힘들다"가 아니라, "불확실성이 힘들다", "남과 비교되는 게 힘들다" 같은 구체적인 이유를 찾으면 대처 방법도 달라진다.
생각해보니 이건 개발할 때 쓰는 분할 정복(Divide and Conquer)과 비슷했다. 거대한 문제를 통째로 보면 막막하지만, 작은 단위로 쪼개면 각각은 해결 가능한 수준이 된다.
이제는 무슨 문제를 만나든 자연스럽게 쪼개는 습관이 생겼다. 프로젝트가 막막하면 기능 단위로, 버그가 복잡하면 원인별로, 일정이 빡빡하면 우선순위대로. 새로운 기술을 배울 때도 전체를 한 번에 이해하려 하지 않고, 핵심 개념부터 하나씩 정복해 나간다.
알고리즘 문제를 풀 때 배운 사고방식이 일상의 문제 해결에서도 적용해보고 있다. 문제를 작게 만들면 부담이 줄어들고, 작은 성공이 쌓이면 큰 문제도 해결된다. 개발자라서 이런 사고방식이 더 자연스러웠는지도 모르겠다.