많은 개발자에게 터미널은 '애플리케이션 껍데기가 없는 프로그램을 실행하는 곳' 정도로 인식된다. 테스트를 돌리고, 의존성을 설치하고, 컨테이너를 띄우고, 원격 서버에 접속하는 단발성 명령을 하나씩 입력하는 창구다. 개발자 윌 켈러허(Will Keleher)는 자신의 경력 초기가 정확히 그랬다고 고백한다. 명령을 하나씩 실행할 수는 있었지만, 여러 프로그램을 이어 붙이거나 조건 분기·반복 같은 논리를 넣어 '컴퓨터에게 어떤 일을 해내라'고 시키지는 못했다. 그의 표현을 빌리면 터미널은 세상에서 가장 형편없는 GUI였다.
흥미로운 점은 그 한계가 단지 기술 부족만은 아니었다는 것이다. 이론적으로는 Node.js로 얼마든지 그런 프로그램을 짤 수 있었지만 실제로는 한 번도 그러지 않았다. 절반은 사고방식의 문제였다. 명령줄에서 쓰는 프로그램들을 '내가 제어하고 조합할 수 있는 대상'으로 바라보는 데 익숙하지 않았던 것이다. 나머지 절반은 그 프로그램들의 동작을 스크립트에 엮어 넣을 만큼 깊이 알지 못했다는 점이다. 이 두 가지가 맞물리면, 기술 스택이 아무리 좋아도 컴퓨터에게 시킬 수 있는 일의 폭은 좁아진다.
GUI의 편안함이 만드는 천장
저자는 셸을 조금씩 익히면서, 기존 프로그램들을 이어 붙여 목표를 달성하는 능력을 얻은 순간이 프로그래밍을 처음 배웠을 때와 비슷한 전환점이었다고 말한다. 동시에 그는 GUI에 의존하는 뛰어난 엔지니어들도 많이 봐 왔다. 테스트 실행, git 관리, 데이터베이스 접속 같은 일상 업무를 GUI로 처리하는 방식은 GUI가 상정한 범위 안에서는 잘 작동한다. 문제는 그 범위를 벗어나는 순간이다. 명령을 실패할 때까지 반복하는 while 루프나, 디렉터리의 모든 파일에 같은 작업을 적용하는 for 루프를 몰라서 유능한 엔지니어가 엄청난 수고를 들이는 장면은 드물지 않다.
이 한계는 개인 생산성에서 끝나지 않는다. 대부분의 회사에는 빌드·배포·검증·테스트를 담당하는 핵심 로직이 Bash나 Zsh 같은 셸 언어로 상당량 쌓여 있다. 도구가 작성된 언어에 익숙하지 않으면 그 스크립트를 읽거나 개선하기 어렵다. 원격 서버가 어떻게 동작할지는 지시할 수 있으면서, 정작 내 개발 머신에게 린팅과 테스트를 병렬로 돌리라고는 시키지 못하는 아이러니가 생기는 셈이다.
왜 하필 셸로 쓰이는가
그렇다면 왜 이런 스크립트들이 팀의 주력 언어가 아닌 셸로 쓰이곤 할까. 저자는 명령을 이어 붙이도록 설계된 언어가 그 작업에 더 편하기 때문이라고 본다. 예컨대 테스트가 실패할 때까지 반복 실행하는 일은 셸에서 'while pnpm exec mocha ./경로.test.ts; do true; done' 한 줄이면 된다. 같은 일을 Node.js로 하려면 파일을 만들고 child_process를 불러오고 출력을 보기 위해 stdio 설정까지 신경 써야 한다. 파이프로 여러 프로그램을 엮거나 출력을 캡처하지도 않는 단순한 예제인데도 그렇다.
물론 이것이 모든 것을 Bash로 쓰라는 뜻은 아니다. 두 프로그램을 잇는 정도의 단순한 문제에서는 셸이 편하지만, 정교한 논리와 데이터 타입이 필요해지는 순간에는 그것을 표현하고 테스트하기 쉬운 제대로 된 언어를 택해야 한다. JavaScript에 익숙한 팀이라면 zx 같은 도구로 스크립트를 한결 쓰기 쉽게 만들 수 있고, Ruby나 Python도 Node.js보다 이런 잡일에 가볍다는 것이 저자의 경험이다.
문법이 아니라 도구 상자
저자가 가장 강조하는 대목은 셸을 안다는 것의 실체다. 그는 셸 실력이 20%의 문법과 80%의 좋은 도구 상자로 이루어진다고 본다. 명령을 이어 붙이는 스크립트를 다른 언어로 옮긴다 해도, 그 명령들이 실제로 어떻게 동작하는지 모르면 결과물은 똑같이 난해해진다. 반대로 새 프로그램을 하나 익힐 때마다 능력이 곱절로 늘어나는데, 새 도구는 이미 아는 모든 도구와 조합해 쓸 수 있기 때문이다. 셸 스크립트가 조악하다고 불평하는 엔지니어 상당수가 사실 다른 언어로 직접 변환해 본 적은 없다는 지적도 뼈아프다.
한국의 실무자에게 이 글은 두 가지 시사점을 남긴다. 하나는 CI 파이프라인과 배포 스크립트를 남이 관리하는 블랙박스로 두지 말고, 최소한 읽고 고칠 수 있을 만큼 셸에 익숙해질 필요가 있다는 것이다. 다른 하나는 도구 선택의 기준이다. 명령을 단순히 잇는 일이라면 셸이나 zx가 낫고, 복잡한 자료구조와 검증이 필요하면 익숙한 프로그래밍 언어로 옮기는 편이 낫다. 결국 관건은 문법 암기가 아니라, 내가 실제로 쓰는 명령들을 얼마나 잘 아느냐, 그리고 그것들을 조합해 컴퓨터에게 일을 시킬 의지가 있느냐다.