컴퓨터 역사에는 수많은 기술이 등장했고, 또 수많은 기술이 사라졌다.어떤 것은 혁신적이었지만 너무 복잡해서 사라졌고, 어떤 것은 시대를 잘못 만나 잊혀졌다. 또 어떤 것은 한때 세상을 지배했지만 새로운 기술의 등장과 함께 조용히 역사 속으로 들어갔다.그러나 그 수많은 기술의 변화 속에서도, 놀랍게도 거의 변하지 않고 살아남은 것들이 있다.
바로 Unix의 작은 명령어들과 그 뒤에 숨은 설계 철학이다.
이 시리즈는 바로 그 작은 것들에서 시작했다. 터미널에서 무심코 사용하던 몇 개의 기호들, 단순해 보이는 리디렉션 문법, 그리고 파이프 같은 것들 말이다.처음 보면 그저 명령어의 일부처럼 보인다. 하지만 조금만 깊이 들여다보면, 그 안에는 수십 년 동안 소프트웨어 세계를 지탱해 온 설계 원리가 숨어 있다.
그리고 놀랍게도 그 원리들은 지금도 여전히 살아 있다.클라우드에서도, 컨테이너에서도, 그리고 현대의 개발 도구에서도.
stdout과 stderr — 단순한 분리가 만든 구조적 자유
시리즈의 첫 글은 stdout과 stderr라는 개념에서 시작했다.표면적으로 보면 이것은 단순한 출력 채널의 분리처럼 보인다. 프로그램이 정상적인 출력과 오류 메시지를 서로 다른 스트림으로 보내는 것.
그러나 이 단순한 분리는 사실 Unix 설계의 중요한 특징을 보여준다.
Unix는 처음부터 출력의 의미를 분리했다.정상적인 데이터 흐름과 오류 정보를 분리함으로써, 프로그램은 다른 프로그램과 연결될 때 훨씬 더 유연하게 동작할 수 있게 되었다.
예를 들어 어떤 프로그램의 출력이 다른 프로그램의 입력이 되는 경우, 오류 메시지가 섞여 들어가면 전체 파이프라인이 깨질 수 있다. 하지만 stderr가 따로 존재하기 때문에 데이터 흐름은 깨지지 않는다.
이 작은 설계는 결국 프로그램을 서로 연결할 수 있는 기반이 되었다.
그리고 그 결과로 등장한 것이 바로 Unix 파이프였다.
파이프 — 프로그램을 조합하는 방식
| 라는 기호는 오늘날 너무나 익숙하다.하지만 이 기호는 단순한 문법이 아니다. 그것은 소프트웨어를 만드는 방식 자체를 바꿔버린 발명이었다.
파이프의 아이디어는 매우 단순하다.프로그램 하나가 만든 출력을 다른 프로그램의 입력으로 바로 연결하는 것.
하지만 이 단순한 연결 방식은 놀라운 결과를 만들어냈다.Unix에서는 프로그램을 하나의 거대한 시스템으로 만들지 않는다. 대신 작은 프로그램들을 연결해서 하나의 시스템을 만든다.
이 철학은 이후 수많은 소프트웨어 설계에 영향을 미쳤다.오늘날 우리가 사용하는 데이터 처리 파이프라인, 스트리밍 시스템, 그리고 심지어 현대의 마이크로서비스 아키텍처까지도 어느 정도는 이 철학의 영향을 받았다.
Unix의 파이프는 단순한 기능이 아니라 구성(composition)이라는 개념을 프로그래밍 세계에 도입한 것이다.
fork와 exec — 프로세스의 분리
셸 리디렉션의 내부를 들여다보면 또 하나의 중요한 설계 원리를 발견하게 된다.
바로 fork와 exec라는 프로세스 모델이다.현대의 많은 운영체제에서는 프로세스를 생성하는 방식이 복잡하다. 하지만 Unix에서는 매우 명확한 두 단계로 나뉜다.
먼저 fork로 현재 프로세스를 복제하고, 그 다음 exec로 새로운 프로그램을 실행한다.이 모델은 매우 단순하지만 강력하다.
셸은 먼저 자식 프로세스를 만든 다음, 그 프로세스에서 파일 디스크립터를 조작하고, 필요한 리디렉션을 설정한 뒤 새로운 프로그램을 실행한다.
그 결과 우리는 다음과 같은 명령어를 아무 생각 없이 사용할 수 있다.
command1 | command2 > output.txt하지만 이 한 줄의 명령어 뒤에서는 여러 개의 프로세스가 생성되고, 파일 디스크립터가 복제되고, 파이프가 생성되고, 리디렉션이 설정된다.
이 모든 것이 가능해진 이유는 Unix가 처음부터 프로세스와 프로그램 실행을 명확하게 분리했기 때문이다.
Everything is a file
Unix 철학을 이야기할 때 빠지지 않는 문장이 있다.
Everything is a file.
처음 들으면 약간 과장된 말처럼 보인다. 하지만 Unix 시스템을 조금만 깊이 들여다보면 이 말이 단순한 슬로건이 아니라 실제 설계 원리라는 것을 알게 된다.
Unix에서는 파일만 파일이 아니다.디스크 파일도 파일이고, 네트워크 소켓도 파일이고, 터미널도 파일이고, 심지어 장치 드라이버도 파일처럼 동작한다.
이렇게 모든 것을 파일 인터페이스로 통일한 결과, 프로그램은 다양한 종류의 데이터를 동일한 방식으로 처리할 수 있게 되었다.
read 와 write 같은 단순한 시스템 호출만으로도 다양한 장치를 다룰 수 있게 된 것이다.
이 설계는 소프트웨어의 복잡도를 극적으로 줄였다.그리고 동시에 확장성을 만들어냈다.새로운 장치가 등장하더라도 기존 프로그램은 거의 수정 없이 그대로 사용할 수 있기 때문이다.
컨테이너 시대에도 살아남은 설계
이 시리즈의 마지막 글에서는 Docker 로그 이야기를 다루었다.
현대의 컨테이너 시스템은 놀라울 정도로 복잡하다. 클라우드 인프라, 오케스트레이션 시스템, 분산 네트워크, 수많은 서비스들이 서로 연결되어 있다.
하지만 그 복잡한 시스템의 한가운데에서 우리는 여전히 다음과 같은 방식을 사용한다.
stdout
stderr컨테이너 로그는 대부분 표준 출력으로 수집된다.
Kubernetes도, Docker도, 그리고 대부분의 로그 수집 시스템도 결국 이 오래된 Unix 인터페이스를 기반으로 동작한다.왜일까?이유는 간단하다.
이미 충분히 잘 설계되어 있기 때문이다.Unix의 I/O 모델은 단순하면서도 강력하다. 프로그램은 단지 stdout으로 데이터를 출력하기만 하면 되고, 나머지 처리 — 로그 수집, 저장, 분석 — 는 시스템이 담당한다.
이 구조는 수십 년이 지나도 여전히 유효하다.
왜 Unix 철학은 오래 살아남았을까
Unix 철학이 특별한 이유는 기술 자체가 아니라 설계 방식에 있다.
Unix는 처음부터 다음과 같은 원칙을 가지고 만들어졌다.
작게 만들 것.
단순하게 만들 것.
서로 연결될 수 있게 만들 것.
이 원칙은 놀라울 정도로 강력하다.복잡한 시스템은 시간이 지나면 무너지기 쉽다. 하지만 단순한 시스템은 오랫동안 살아남는다.
Unix는 바로 그 단순함을 선택했다.
그 결과 Unix의 작은 인터페이스들은 수십 년 동안 거의 변하지 않은 채 살아남을 수 있었다.
작은 인터페이스의 힘
오늘날 우리는 거대한 시스템을 만들고 있다.클라우드 플랫폼, 분산 데이터베이스, AI 모델, 글로벌 서비스 인프라. 이 모든 것들은 과거의 컴퓨터 시스템과 비교할 수 없을 정도로 복잡하다.
하지만 그 복잡한 시스템을 구성하는 가장 아래층에는 여전히 작은 인터페이스들이 존재한다.
파일 디스크립터.
표준 입력과 출력.
프로세스.
파이프.
이 모든 것들은 1970년대에 만들어진 개념들이다.그리고 지금도 여전히 작동하고 있다.
결국 중요한 것은 기술이 아니라 철학이다
이 시리즈를 통해 우리가 살펴본 것은 단순한 명령어의 동작 방식이 아니었다.
2>&1
|
fork
dup2
stdout
이 모든 것들은 사실 Unix 철학이 구현된 작은 인터페이스들이다.
Unix는 거대한 프레임워크를 만들지 않았다.대신 작은 도구들을 만들었고, 그 도구들이 서로 연결될 수 있도록 설계했다.
그 결과로 탄생한 것이 바로 오늘날 우리가 사용하는 수많은 시스템들이다.
그리고 우리는 여전히 그 위에 서 있다
지금 이 글을 읽고 있는 컴퓨터에서도, 아마 수많은 Unix 아이디어들이 작동하고 있을 것이다.
터미널에서 실행되는 명령어들.
컨테이너의 로그 시스템.
클라우드 인프라의 프로세스 모델.
이 모든 것들은 어떤 의미에서는 Unix의 후손들이다.
그리고 그것은 하나의 사실을 보여준다.
좋은 설계는 시간이 지나도 사라지지 않는다는 것.
작은 명령어 뒤에는 언제나 설계가 있다
터미널에서 다음과 같은 명령어를 입력할 때를 생각해 보자.
grep error log.txt | sort | uniq -c우리는 보통 이 명령어를 아무 생각 없이 사용한다.
하지만 그 한 줄의 명령어 뒤에는 수십 년 동안 축적된 설계 철학이 숨어 있다.
stdout과 stderr의 분리.
파이프를 통한 데이터 흐름.
프로세스 생성 모델.
파일 인터페이스의 통일.
이 모든 것이 합쳐져서 한 줄의 명령어가 된다.그리고 그것이 바로 Unix가 만든 세계다.
에필로그
Unix의 많은 아이디어들은 매우 오래되었다.하지만 오래되었다는 것은 반드시 낡았다는 뜻은 아니다.
때로는 오히려 그 반대다.오랫동안 살아남은 설계는 보통 이미 충분히 좋은 설계이기 때문이다.
우리가 터미널에서 사용하는 작은 기호들.
그 뒤에는 수십 년 동안 살아남은 설계 철학이 있다.
그리고 아마 앞으로도 꽤 오랫동안 살아남을 것이다.
작은 명령어 뒤에는 언제나 이야기가 있다.그리고 Unix는 그 이야기로 만들어진 운영체제였다.