무한한 자유가 독이 될 때: 10년차 개발자의 '한계 활용법'
2026. 8. 21.
무한한 자유가 독이 될 때: 10년차 개발자의 '한계 활용법'
지난 2주간 이 글을 쓰는 데 매달렸다는 게 믿기지 않습니다.
얼마 전, 커서 커뮤니티 행사에서 AI가 소프트웨어 개발 방식을 어떻게 바꾸고 있는지에 대해 강연할 기회가 있었습니다. 행사는 성공적이었고, 강연 후에는 꽤 많은 분이 저에게 개인적인 대화를 청해왔죠.
그중 한 분이 제 눈길을 사로잡았습니다. 기술 분야에 종사하는 분은 아니었지만, 흥미로운 질문을 던지더군요.
"요즘처럼 많은 도구와 기술이 쏟아져 나오는 시대에, 도대체 이 모든 것을 어떻게 헤쳐나가고 적절한 것을 선택하나요?"
그는 분명 압도적으로 느껴질 것이라고 생각하는 눈치였습니다. 그러더니 수많은 옵션 덕분에 더 멋진 것들이 많이 만들어지기를 바란다며 미소 지었습니다.
저도 잠시 생각에 잠겼다가 미소 지으며 답하려던 찰나, 그분은 떠나야 했습니다… 하지만 그의 질문은 제 머릿속을 떠나지 않았습니다.
며칠 뒤, 도서관에 앉아 읽을거리를 찾다가 뜻밖의 답을 발견했습니다. 바로 W. 리처드 스티븐스의 『UNIX Network Programming』였습니다. (참고로 정말 훌륭한 책이니 꼭 한번 읽어보세요!)
90년대 기술, 제한적인 메모리, 부족한 처리 능력, 협소한 대역폭, 변변찮은 도구들… 모든 것이 부족했습니다.
하지만 우리는 그런 환경 속에서도 UNIX, TCP/IP, 초기 운영체제, 엄청난 수학적 발견들, 거대한 엔지니어링 프로젝트, 그리고 역대 가장 우아한 기술 작품들을 만들어냈습니다.
이것이 저를 생각하게 만들었습니다.
우리에게 제약을 가했던 것들이 사실은 우리를 더 나은 존재로 만들었던 것은 아닐까? 위대함은 항상 더 많은 것을 가짐으로써 만들어지는 것이 아니라, 적은 것으로 더 많은 것을 해내야만 했을 때 비로소 탄생하는 것은 아닐까?
그분은 더 많은 도구가 위대함으로 가는 더 나은 기회를 의미한다고 생각했지만, 제 손에 들린 책은 그 반대의 증거를 제시하고 있었습니다.
한계의 역설
저는 부족함이 때때로 우리를 더 낫게 만드는 이유가 있다고 믿습니다.
우리는 보통 한계를 극복해야 할 대상으로 생각합니다. 돈이 부족하고, 시간이 모자라며, 자원이 없고, 지식이 부족한 것. 이 모든 것이 우리가 성취하고 싶은 목표와 우리 사이에 놓여있다고 여기죠.
하지만 한계에는 우리가 충분히 이야기하지 않는 또 다른 면이 있습니다.
한계는 단순히 무언가를 빼앗아 가는 것에 그치지 않습니다. 그것은 '될 수 있었던 것'까지도 없애버립니다.
그리고 아마도 그것이 바로 우리에게 필요한 것일지도 모릅니다. 모든 것이 가능하고, 모든 방향이 열려 있으며, 모든 도구가 손안에 있고, 모든 접근 방식이 자유로울 때, 그것은 분명 자유처럼 들립니다.
그러나 경계 없는 자유는 놀랍도록 살기 힘든 공간이 될 수 있습니다.
누군가에게 무한한 자원을 준다면, 그 사람은 무엇을 해야 할지 평생을 결정하며 보낼 수도 있습니다. 반대로 아무것도 주지 않으면, 질문은 갑자기 단순해집니다.
내가 가진 것으로 얼마만큼을 이룰 수 있을까?
그 질문은 당신의 사고방식을 바꿉니다. 완벽한 도구를 찾는 것을 멈춥니다. 애초에 그런 것은 존재하지 않으니까요. 그리고 눈앞에 있는 것으로 구축하기 시작합니다. 평소에는 보이지 않았을 세부사항들을 알아챕니다. 타고나게 더 관찰력이 뛰어나서가 아니라, 더 이상 무시할 사치를 부릴 수 없기 때문입니다.
어쩌면 그것이 한계의 진정한 선물일지도 모릅니다. 선택지를 좁히는 동시에, 당신의 집중력을 날카롭게 만드는 것 말입니다.
아마 이것이 역설일 겁니다. 문이 적을수록, 우리는 우리가 서 있는 문을 더 명확하게 보게 됩니다.
그리고 사실, 이 아이디어가 전혀 새로운 것은 아닙니다.
제약은 창의력을 강제한다
그 책의 메시지
스티븐스의 책을 잠시 살펴보죠. 이 책은 기본적으로 소켓 API, 즉 socket(), bind(), listen(), accept(), connect(), read(), write(), close() 함수들에 대한 상세한 설명서입니다.
이것이 지구 반대편에 있는 두 컴퓨터가 안정적으로 통신하게 만드는 전체 '어휘'입니다.
하지만 스티븐스가 이 함수들을 발명한 것은 아닙니다. 버클리 소켓은 1983년경 UC 버클리의 CSRG에서 4.2BSD와 함께 탄생했습니다. 스티븐스는 한 세대의 프로그래머들에게 이들이 실제로 어떻게 작동하는지를 가르치는 책을 썼을 뿐이죠.
그는 무한한 컴퓨팅 파워의 시대를 위해 설계한 것이 아니었습니다. 그는 비싼 메모리, 느린 CPU, 불안정하고 낮은 대역폭의 링크가 지배하던 시대에 만들어진 API를 기록하고 있었습니다. 그곳에는 실수, 모든 것을 하려 드는 비대한 인터페이스, 또는 일반적인, 모든 것을 수용하는 계약을 위한 공간이 없었습니다.
모든 함수는 그 자리를 차지할 만한 이유가 있어야만 했습니다.
그리고 설계자들이 이러한 제약에 직면하면서, 결과적으로 만들어진 API는 너무나 간결하고 잘 구성되어, 40년이 지난 오늘날, 그 어떤 초기 제약도 존재하지 않는 세상에서도 거의 모든 프로그래밍 언어가 네트워크를 위해 이 인터페이스를 랩핑하여 사용하고 있습니다.
파이썬의 socket 모듈, Node의 net 모듈, Go의 net 패키지 모두 이 여덟 가지 정도의 원시적인 함수들로 그 형태를 거슬러 올라갑니다.
작은 규모의 역설이죠. 비대한 것을 만들 사치가 없었기 때문에, 그들은 대신 시대를 초월하는 것을 만들 수밖에 없었습니다. BSD는 부족함 속에서 그것을 구축했고, 스티븐스는 왜 그것이 그렇게 정교할 수밖에 없었는지를 설명했습니다.
솔직히 90년대 책이라길래 좀 딱딱하고 시대에 뒤떨어진 내용일까 싶었는데, 막상 펼쳐보니 그 통찰력에 깜짝 놀랐습니다. 제가 실무에서 막연하게 '이렇게 해야 효율적이지 않을까?' 하고 고민했던 부분들이 이미 그 시절에 치열하게 고민되고 정리된 것을 보면서 시대를 초월하는 원칙이 있음을 다시금 깨달았죠. 덕분에 낡았으리라 예상했던 책에서 오늘날 제가 만드는 소프트웨어에도 적용할 수 있는 많은 것을 배울 수 있었습니다.
C 언어
우리가 오늘날 가진 모든 것의 토대를 마련한 언어, C입니다.
C는 좋은 예시입니다. 우아하면서도 놀랍도록 적은 것을 제공합니다. GC도 없고, 정교한 표준 추상화도 없으며, 메모리와 당신 사이에 안전망도 없습니다. 무언가를 원한다면, 종종 밑단에서 무슨 일이 일어나는지 이해해야 합니다.
오늘날의 기준으로 보면 '안전하지 않다'고 평가하거나 약점으로 분류하겠지만, 그 한계는 특정 종류의 사고방식을 강제합니다. 더 많은 세부 사항에 주의를 기울여야 하고, 메모리, 데이터 레이아웃, 소유권, 그리고 기계가 실제로 무엇을 하는지에 대해 더 의식하게 됩니다.
이 언어는 당신에게 많은 옵션이나 답을 주지 않지만, 대신 더 나은 질문을 던지고, 더 현명하고 시대를 초월하는 결정을 내리도록 만듭니다. 저도 C언어를 처음 배울 때는 '이렇게 불편한데 이걸 왜 써야 하나?' 싶었지만, 나중에 임베디드 시스템이나 저수준 최적화 작업을 하면서 C가 강제하는 디테일의 중요성을 뼈저리게 느꼈습니다.
Go 언어
미래로 돌아와 Go를 살펴보겠습니다. Go는 다른 방향을 택했습니다. 그 제약은 하드웨어에 의해 부과된 것이 아니라, 대부분 설계자들에 의해 의도적으로 선택된 것이었습니다.
당시 사용 가능한 모든 것들을 고려할 때, 이 언어는 의도적으로 최소화되고 단순한 기능들을 유지하도록 설계되었습니다. 문법적으로든, 타입 시스템적으로든, 같은 아이디어를 표현하는 방법이 더 적습니다.
언어가 문제를 해결하는 더 적은 방법을 제공할 때, 당신은 어떤 영리한 추상화를 사용할지 논쟁하는 시간을 줄이고 문제 자체를 해결하는 데 더 많은 시간을 보낼 수 있습니다.
Go의 절제는 곧 기능입니다. 포함하지 않은 것들은 포함한 것만큼이나 의도적입니다.
음악
저는 피아노를 칩니다. 그래서 이 부분은 이론적인 이야기가 아닙니다.
오늘날 노트북 하나에 DAW, 수천 개의 플러그인, AI 보컬 보정 도구를 넣고 어디서든 음반을 만들 수 있습니다. 70년대와 80년대에는 그 작업의 상당 부분이 물리적이었습니다. 테이프를 잘못 자르면 그 부분은 영원히 사라졌죠. 제한된 트랙 수, 제한된 스튜디오 시간, 비싼 장비… 밴드는 각 파트를 정확히 알고 있어야 했습니다. 한 번의 실수는 때때로 모두가 처음부터 다시 시작해야 하는 상황을 만들었습니다.
녹음 시간이 돈으로 직결될 때, 스네어 드럼에 6시간을 쓸 수는 없습니다. 8개의 트랙밖에 없다면, 어떤 소리가 트랙을 차지할 자격이 있는지 결정해야 합니다. 음반에서 그 결과물을 들을 수 있습니다. 연주, 불완전함, 그리고 그 결정들 말이죠.
저는 우리가 테이프를 자르던 시절로 돌아가자고 주장하는 것이 아닙니다. 다만, 무한한 되돌리기 기능이 할 수 없는 일을 '제약'이 해냈다는 것을 말하고 싶을 뿐입니다.
모든 것을 가졌을 때의 문제점
풍요는 안일함을 낳고, 끝없는 선택지를 만들어냅니다… 그리고 이는 모든 문제를 그저 '더 많은 것'을 투입함으로써 해결하려는 유혹으로 이어집니다.
AI에 대한 이야기로 돌아가 봅시다. 현대의 DAW처럼, AI는 우리 작업의 훌륭한 파트너라고 저는 믿습니다. 하지만 그와 동시에, AI는 우리가 이전에 보았던 거의 모든 것보다 빠르게 엄청난 양의 제약을 제거하고 있습니다.
불과 몇 년 전만 해도, 요청받은 기능 하나를 구현하는 데 한두 달이 걸리곤 했습니다. 다른 아키텍처를 시도한다는 것은 실제로 그것을 구축하는 것을 의미했습니다. 코드 블록을 다시 작성하는 데는 시간이 걸렸고, 제 코드가 아니라면 먼저 맥락을 이해해야 했습니다.
이제는 AI에게 그 모든 것을 몇 초 만에 요청할 수 있습니다. 과거에는 '노력'이 우리를 멈추게 하는 요소였습니다. 그 비용이 급격히 떨어지면, 애초에 '이걸 해야 하는가?'라는 질문 자체를 멈추기 쉽습니다. 우리는 하나를 고르는 대신 다섯 가지 버전을 생성합니다. 모델이 이미 알고 있다는 이유로 또 다른 라이브러리를 추가합니다. 새 초안이 더 깔끔해 보인다는 이유로 잘 작동하는 코드를 다시 작성합니다.
이제는 "이걸 만들 수 있을까?"가 아니라, **"이걸 만들어야 하는가?"**로 질문이 바뀐 것입니다.
아무것도 없을 때는 한계가 당신에게 부과됩니다. 모든 것을 가졌을 때는, 당신이 스스로에게 몇 가지 한계를 부과해야만 합니다.
최근 AI 코파일럿을 활용하면서 정말 경이로운 속도로 기능 구현이나 코드 리팩토링이 가능해졌습니다. 한 번은 복잡한 도메인 로직을 AI에게 여러 버전으로 생성하게 한 뒤 비교해 봤는데, 단순한 '있으면 좋다'를 넘어 '정말 이걸 지금 추가하는 게 최선인가?'라는 본질적인 질문을 던지게 되더라고요. 과거엔 엄두도 못 냈을 시도를 단 몇 초 만에 해볼 수 있는 거죠.
그렇다면 어떻게 해야 할까요?
그 행사에서 그분에게 답을 해드릴 기회는 없었습니다. 지금 제가 답할 수 있다면, 도구 목록을 알려드리지 않을 겁니다.
저는 그에게 더 많은 옵션이 더 나은 작업을 보장하지 않으며, 단지 결정을 내리지 못하게 할 뿐이라고 말해줄 것입니다. 90년대에 UNIX가 탄생한 것은 사람들이 더 많은 것을 가졌기 때문이 아닙니다. 그들은 가진 것이 적었고, 그 부족함이 작업에 정직함을 강요했기 때문에 탄생했습니다.
그렇다고 AI를 버리거나, 테이프를 자르던 시절로 돌아가거나, 모든 것을 C로 작성하라는 뜻은 아닙니다. 이는 환경이 더 이상 당신에게 무료로 한계를 부여하지 않을 것이라는 의미입니다. 날카로움을 원한다면, 당신이 직접 한계를 선택해야 합니다. 하나의 사용 사례만 출시하세요. 모델이 지루한 부분을 생성하게 하고 핵심 결정은 당신이 내리세요. 더 이상 추가할 수 없을 만큼 빠듯한 마감 기한을 스스로에게 부여하세요.
이번 주에는 스택을 최소한으로 제한해 보는 건 어떨까요?
원문: https://dev.to/adamthedeveloper/greatness-is-forged-by-limitation-e20 수집일: 2026-08-21 00:32:35