명령줄 인터페이스 가이드라인 (2021)
(clig.dev)- 전통적인 UNIX 철학을 현대적으로 재해석한 CLI 프로그램 설계 원칙과 구체적 가이드라인을 오픈소스 문서로 정리한 레퍼런스로, 커맨드라인 도구를 만드는 개발자를 주요 독자로 삼음
- CLI는 단순 스크립팅 플랫폼이 아니라 인간 중심의 텍스트 UI로 진화했으며, 이 변화에 맞게 설계 원칙도 갱신되어야 함
- 컴포저빌리티(composability)와 인간 친화성은 상충하지 않으며, 표준 입출력·파이프·종료 코드 등 UNIX 관행을 지키면 둘을 동시에 달성 가능
- 헬프 텍스트, 에러 메시지, 출력 형식, 인터랙티비티, 설정 체계 등 실무에서 자주 놓치는 세부 항목까지 구체적 권장 사항으로 제공
- CLI 도구의 미래 호환성과 사용자 신뢰는 인터페이스 안정성과 분석 데이터 투명성에서 결정되며, 이 가이드는 그 기준선을 제시
철학 (Philosophy)
인간 중심 설계
- 전통 UNIX 명령어는 주로 다른 프로그램이 사용하는 것을 전제로 설계되었으나, 현재 CLI는 인간이 직접 사용하는 경우가 대부분이므로 인간 우선 설계가 필요
- 과거 CLI는 "machine-first"였지만 현재는 "human-first" 텍스트 기반 UI로 진화
조합 가능한 작은 부품
- UNIX 철학의 핵심은 작고 단순한 프로그램을 조합해 더 큰 시스템을 구성하는 것으로, 지금도 유효
- 표준 stdin/stdout/stderr, 시그널, 종료 코드가 프로그램 간 연결을 보장하며, JSON은 더 구조화된 데이터 교환을 지원
- 소프트웨어는 반드시 더 큰 시스템의 부품이 되므로, 잘 동작하는 부품이 될지는 설계 단계에서 결정됨
일관성
- 터미널 사용자는 기존 컨벤션에 손이 익어 있으므로, CLI는 기존 패턴을 따를 것을 권장
- 단, 일관성이 사용성을 해칠 경우 신중하게 관례를 깰 수 있음
적절한 정보량
- 명령이 수 분간 아무 출력 없이 대기하면 "너무 적은" 정보, 대량의 디버그 로그를 쏟아내면 "너무 많은" 정보
- 정보량의 균형은 소프트웨어가 사용자를 지원하는 데 절대적으로 중요
발견 가능성 (Ease of Discovery)
- GUI는 화면에 기능을 모두 펼쳐 보이지만, CLI는 기억에 의존하는 것으로 오해받음
- 포괄적인 헬프 텍스트, 풍부한 예시, 다음 명령 제안 등 GUI 기법을 차용해 CLI도 학습하기 쉽게 만들 수 있음
대화로서의 CLI
- CLI 사용은 반복적 시도-실패를 통한 대화 구조를 가지며, 오류 수정 제안·중간 상태 표시·위험 작업 전 확인 등이 이 특성을 활용하는 설계 기법
- 최악의 상호작용은 사용자를 무기력하게 만드는 적대적 대화, 최선은 성취감을 주는 유쾌한 교환
견고성 (Robustness)
- 소프트웨어는 실제로도, 느낌으로도 견고해야 함
- 예기치 않은 입력의 우아한 처리, 멱등성(idempotence) 유지, 진행 상황 안내, 스택 트레이스 노출 자제가 핵심
- 복잡한 특수 케이스를 줄이고 단순하게 유지하면 견고성이 높아짐
공감 (Empathy)
- CLI 도구는 개발자의 창의적 도구이므로 즐겁게 사용할 수 있어야 함
- 사용자가 자신의 편임을 느낄 수 있도록 문제를 충분히 고민하고 설계할 것
혼돈 (Chaos)
- 터미널 세계는 불일치로 가득하지만, 그 혼돈이 자유로운 창조의 원천이기도 함
- "표준이 생산성이나 사용자 만족도에 명백히 해롭다면 그 표준을 버려라" — Jef Raskin
가이드라인 — 기본 (The Basics)
- 인수 파싱 라이브러리를 사용할 것: 언어별 권장 라이브러리는 Go(Cobra, cli), Python(Click, Typer, Argparse), Rust(clap), Node(oclif) 등 다수
- 성공 시 종료 코드 0, 실패 시 0이 아닌 코드 반환 — 스크립트가 성공·실패를 판별하는 기준
- 기본 출력은
stdout, 로그·에러 등 메시지는stderr로 전송
가이드라인 — 헬프 (Help)
-
-h또는--help플래그에 상세 헬프 텍스트 표시, 서브커맨드에도 동일 적용 - 인수 없이 실행 시 간결한 헬프 표시 (설명, 1~2개 예시, 플래그 설명,
--help안내 포함)-
jq가 이를 잘 구현한 예시로 언급됨
-
-
--help/-h/help subcommand등 다양한 형태의 헬프 요청 모두 지원 - 헬프 텍스트 상단에 웹 문서 링크 및 피드백 경로 제공
- 예시를 먼저 보여줄 것 — 복잡한 활용 사례로 점진적으로 이어지는 스토리 구성 권장
- 자주 쓰이는 플래그와 커맨드를 헬프 텍스트 상단에 배치 (git의 구성 방식 참조)
- 굵은 제목 등 서식을 활용해 스캔하기 쉽게 구성하되, 터미널 독립적 방식 사용
- 사용자가 잘못 입력했을 때 의도를 추측해 수정 제안 가능 — 단, 자동 실행은 신중하게 결정할 것
- 잘못된 입력이 단순 오타가 아닌 논리적 실수일 수 있으며, 자동 수정 시 해당 구문을 영구 지원해야 하는 부담 발생
가이드라인 — 문서 (Documentation)
- 웹 기반 문서 제공 — 검색 가능성과 링크 공유를 위해 필수
- 터미널 기반 문서 제공 — 설치된 버전과 동기화되며 오프라인에서도 접근 가능
-
man 페이지 제공 고려 —
ronn같은 도구로 생성 가능하며,npm help ls처럼 서브커맨드로 접근하도록 지원 권장
가이드라인 — 출력 (Output)
- 인간 가독성 최우선 — TTY 여부로 사람이 읽는지 판별
- 텍스트 스트림은 UNIX의 보편 인터페이스로, 머신 가독 출력도 지원할 것
- 인간 친화적 출력이 파이프 호환성을 해칠 경우
--plain플래그로 일반 텍스트 출력 제공 -
--json플래그 전달 시 JSON 형식 출력 지원 - 성공 시 출력은 간결하게, 필요 없으면 출력 없이 — 스크립트용으로
-q옵션으로 출력 억제 지원 -
상태 변경 시 사용자에게 알림 —
git push가 원격 브랜치 상태를 출력하는 것이 좋은 예 -
git status처럼 현재 시스템 상태를 쉽게 확인하고 다음 작업도 안내하는 출력 구성 - 색상은 의도적으로 사용하고, 파이프 상태·
NO_COLOR·TERM=dumb·--no-color등 조건에서 색상 비활성화 필수 - TTY가 아닌 환경에서는 애니메이션·스피너 표시 금지 (CI 로그 오염 방지)
- 이모지·심볼은 명확성을 높이는 경우에만 사용 (
yubikey-agent가 예시로 제시됨) - 개발자만 이해할 수 있는 정보는 기본 출력에서 제외, verbose 모드에서만 표시
-
stderr를 로그 파일처럼 사용하지 말 것 — 기본적으로 로그 레벨 레이블(ERR,WARN) 출력 자제 - 대량 출력 시
less등 페이저 사용 고려 — TTY 환경에서만 활성화하고less -FIRX옵션 권장
가이드라인 — 에러 (Errors)
- 예상 가능한 에러는 인간이 이해할 수 있는 메시지로 재작성 (예: "chmod +w file.txt 실행 필요")
- 신호 대 잡음비 유지 — 같은 유형의 에러는 단일 헤더로 묶어 출력
- 중요한 정보는 출력 끝부분에 배치 — 붉은 텍스트는 의도적으로, 드물게 사용
- 예상치 못한 에러 발생 시 디버그 정보와 버그 리포트 제출 방법 안내 포함
- 버그 리포트 URL에 정보를 자동 채워 제출하기 쉽게 구성
가이드라인 — 인수와 플래그 (Arguments and Flags)
- 인수(args)는 위치 기반, 플래그(flags)는 이름 기반 — 플래그를 인수보다 선호할 것
- 모든 플래그에 전체 이름 버전 제공 (예:
-h와--help동시 지원) - 단일 문자 플래그는 자주 쓰이는 플래그에만 한정
- 표준이 있는 경우 표준 플래그 이름 사용 (
-f/--force,-q/--quiet,-v,--json등) - 기본값은 대부분의 사용자에게 적합한 값으로 설정
- 인수나 플래그 미전달 시 프롬프트로 입력 요청, 단 비대화형 환경에서는 프롬프트 강제 금지
- 위험한 작업 전 확인 요청 — 위험 수준에 따라
y/n확인, dry-run 제공, 또는 직접 텍스트 입력 요구- mild(파일 삭제), moderate(디렉토리 삭제, 원격 리소스 변경), severe(전체 서버 삭제)로 위험도 구분
- 파일 입출력 시
-로 stdin/stdout 읽기/쓰기 지원 (예:curl ... | tar xvf -) - 플래그에서 시크릿 직접 수신 금지 —
--password-file플래그나 stdin 사용 권장 (ps 출력·셸 히스토리 노출 위험)
가이드라인 — 인터랙티비티 (Interactivity)
- 프롬프트·인터랙티브 요소는 stdin이 TTY일 때만 표시
-
--no-input전달 시 모든 프롬프트 비활성화 - 비밀번호 입력 시 에코 비활성화 (입력 내용 화면 미표시)
- 사용자가 언제든 탈출 가능하도록 명확히 안내 — Ctrl-C는 항상 동작하게 유지
가이드라인 — 서브커맨드 (Subcommands)
- 서브커맨드 간 플래그 이름·출력 형식 일관성 유지
- 복잡한 도구는
noun verb또는verb noun형태의 2단계 서브커맨드 구조 사용 (예:docker container create) - 모호하거나 유사한 이름의 서브커맨드 회피 (예: update와 upgrade 동시 사용 지양)
가이드라인 — 견고성 (Robustness Guidelines)
- 입력 검증을 초기에 수행하고, 잘못된 데이터는 이해하기 쉬운 에러와 함께 조기 종료
- 응답성이 속도보다 중요 — 100ms 이내에 무언가 출력할 것
- 오래 걸리는 작업에는 진행 표시줄(progress bar) 제공 — Python(tqdm), Go(schollz/progressbar), Node(node-progress) 라이브러리 활용 가능
- 병렬 처리 시 출력이 뒤섞이지 않도록 주의
- 네트워크 타임아웃 설정 — 기본값 포함, 영구 대기 방지
- 일시적 오류 발생 후 재시도 시 이전 상태에서 재개 가능하도록 설계
- crash-only 설계 — 정리 작업 없이 즉시 종료 가능한 구조로 멱등성 확보
가이드라인 — 미래 호환성 (Future-proofing)
- 변경은 하위 호환 추가(additive) 방식으로 유지
- 호환성 깨는 변경 전 프로그램 내에서 사전 경고 표시
- 인간용 출력 변경은 일반적으로 허용 — 스크립트용은
--plain·--json사용 유도 - catch-all 서브커맨드 금지 — 나중에 해당 이름의 서브커맨드 추가 불가 문제 발생
- 서브커맨드 약어 자동 허용 금지 — 명시적 alias만 허용, 안정적으로 유지
- "타임 폭탄" 금지 — 20년 후에도 동작할 수 있도록 외부 의존성 최소화
가이드라인 — 시그널과 제어 문자 (Signals)
- Ctrl-C(INT 시그널) 수신 시 즉시 종료, 정리 작업에 타임아웃 설정
- 정리 중 Ctrl-C 재입력 시 강제 종료 가능하도록 안내 (Docker Compose 예시 참조)
- 프로그램은 정리 작업이 완료되지 않은 상태에서 시작될 수 있음을 가정하고 설계
가이드라인 — 설정 (Configuration)
설정 적용 우선순위 (높음 → 낮음):
- 플래그 → 현재 셸 환경변수 → 프로젝트 수준 설정(
.env) → 사용자 수준 설정 → 시스템 전체 설정
설정 유형별 권장:
-
호출마다 달라지는 설정 (디버그 수준, dry-run): 플래그 사용
-
프로젝트·머신별로 다른 설정 (경로, 색상, HTTP 프록시): 플래그 + 환경변수 조합
-
프로젝트 전체 공유 설정 (Makefile, package.json 유형): 버전 관리 파일 사용
-
XDG Base Directory 스펙 준수 —
~/.config기반 설정 경로 권장 (yarn, fish, neovim, tmux 등 지원) -
다른 프로그램의 설정 파일 자동 수정 시 사용자 동의 획득 필수
가이드라인 — 환경변수 (Environment Variables)
- 환경변수는 실행 컨텍스트에 따라 달라지는 동작에 적합
- 이름은 대문자·숫자·언더스코어만 사용, 숫자로 시작 금지
-
한 줄 값 권장 — 멀티라인은
env명령과 호환 문제 발생 -
NO_COLOR,DEBUG,EDITOR,HTTP_PROXY,SHELL,TMPDIR,HOME,PAGER등 범용 환경변수 우선 확인 - 프로젝트별
.env파일 읽기 지원 권장 — 단,.env는 정식 설정 파일의 대체재가 아님-
.env의 한계: 버전 관리 미포함, 이력 없음, 문자열 단일 타입, 인코딩 문제 취약
-
-
환경변수에서 시크릿 읽기 금지 — 모든 프로세스로 전파, 로그 유출, Docker inspect·systemctl show로 노출 위험
- 시크릿은 크리덴셜 파일, 파이프,
AF_UNIX소켓, 시크릿 관리 서비스를 통해서만 수신
- 시크릿은 크리덴셜 파일, 파이프,
가이드라인 — 네이밍 (Naming)
- 단순하고 기억하기 쉬운 단어 사용 — 너무 일반적이면 다른 명령과 충돌 위험
-
소문자와 필요 시 대시만 사용 (
curl은 좋은 예,DownloadURL은 나쁜 예) - 짧게 유지하되,
cd·ls·ps처럼 극도로 짧은 이름은 범용 유틸리티용으로 예약 - Docker Compose의 전신인
plum→fig→docker compose개명 사례 — 타이핑 편의성이 네이밍의 중요 기준임을 보여주는 실제 사례
가이드라인 — 배포 (Distribution)
- 가능하면 단일 바이너리로 배포 — PyInstaller 등 활용
- 단일 바이너리 불가 시 플랫폼 네이티브 패키지 인스톨러 사용
- 제거 방법을 설치 안내 하단에 명시
가이드라인 — 분석 데이터 (Analytics)
- 사용자 동의 없이 사용 데이터·크래시 데이터 전송 금지
- 수집 시 수집 항목, 이유, 익명화 방법, 보존 기간을 명확히 공개
- 기본 opt-in 권장 — opt-out 방식이라면 첫 실행 또는 웹사이트에서 명확히 고지
- Angular.js(명시적 opt-in), Homebrew(Google Analytics, FAQ 공개), Next.js(기본 활성화 익명 통계) 세 가지 사례 소개
- 분석 대안으로 웹 문서 계측, 다운로드 수 계측, 사용자 직접 인터뷰 활용 가능
Hacker News 의견
-
현재 많은 사람들이 커맨드 라인이 무엇인지 모르며, 왜 그것을 사용해야 하는지에 대해서도 관심이 없음.
- 1980년대에도 이러한 상황은 마찬가지였지만, 현재는 그 어느 때보다 커맨드 라인을 아는 사람들이 많아졌음. CLI(커맨드 라인 인터페이스)의 황금기라고 할 수 있음.
-
스크립트에서는 서브커맨드의 임의 축약을 허용하지 말 것. 예를 들어, mycmd install 대신 mycmd ins 또는 mycmd i를 허용하면, i로 시작하는 새로운 커맨드를 추가할 수 없게 됨.
- 스크립트에서 짧은 인자 사용을 피해야 함. 짧은 인자는 사람이 사용할 때 타이핑을 줄이기 위한 편의성을 제공하지만, 스크립트에서는 명시적으로 작성하는 것이 비용이 적고, 읽기와 쓰기 비율을 고려할 때 더 바람직함.
-
--dry-run 옵션을 고려해볼 것. 실제 변경을 하지 않고 어떤 작업이 수행될지 미리 보여주는 기능은 도구를 배우고 복잡한 옵션을 올바르게 설정했는지 확인하는 데 매우 유용함.
-
stdout이 대화형 터미널이 아닌 경우, 애니메이션을 표시하지 말 것. 이는 CI 로그 출력에서 진행 상황 바가 크리스마스트리처럼 변하는 것을 방지함.
- stdout에서는 절대 애니메이션을 표시하지 말 것. stderr는 로깅, 정보 제공 등을 위한 것이며, stdout은 tty 여부와 관계없이 유용한 출력을 제공해야 함.
-
심볼과 이모지는 명확성을 높일 때만 사용할 것.
- 심볼과 이모지는 터미널 간에 렌더링이 일관되지 않을 수 있으며, 사용자의 취향에 따라 호불호가 갈릴 수 있으므로 매우 신중하게 사용해야 함.
-
현재 Unix 커맨드 라인은 한편으로는 "놀라울 정도로 유용"하고 다른 한편으로는 "설계상의 결함"이 있음.
- Unix 커맨드 라인이 유용한 이유는 C나 Rust로 같은 작업을 수행하는 데 걸리는 시간을 생각해보면 알 수 있음.
- 설계상의 결함은 커맨드 라인 인터페이스가 동시에 인간과 기계가 읽을 수 있어야 한다는 점에서 비롯됨. 이 문제를 해결하는 정석적인 방법은 없음.
-
CLI가 매우 크고 중첩이 필요한 경우(예: aws)를 제외하고, 대부분의 앱은 모든 옵션을 도움말에 출력하고 사용자가 less를 사용하여 필요한 내용을 찾게 하는 것을 선호함.
-
전통적으로 UNIX 명령어는 다른 프로그램에 의해 주로 사용될 것이라고 가정하에 작성됨.
- 실제로는 대화형 로그인 쉘 내에서 상호작용적으로 사용되기 위해 의도되었음. 출력을 생성하는 프로그램과 "조용한" 텍스트 필터로 나뉘며, 복잡한 프로그램은 C로 작성됨.
-
환경 변수에서 비밀번호를 읽지 말 것.
- 비밀번호는 크리덴셜 파일, 파이프, AF_UNIX 소켓, 비밀 관리 서비스 또는 다른 IPC 메커니즘을 통해서만 받아야 함.
-
CLI 가이드라인에 대한 가장 포괄적인 책은 Eric Raymond의 저서임.
- 오랜 시간이 지났지만, clig.dev를 훑어보니 시간이 지남에 따라 의견이 많이 변화했음을 알 수 있음.