कमांड लाइन इंटरफ़ेस गाइडलाइंस
(clig.dev)पारंपरिक Unix सिद्धांतों का पालन करते हुए आधुनिक रूप से अपडेट की गई open source गाइड
-
CLI डिज़ाइन दर्शन
→ इंसान पहले
→ साथ काम करने वाले सरल हिस्से
→ प्रोग्रामों के बीच एकरूपता बनाए रखना
→ जितनी ज़रूरत हो उतना ही बोलना (न बहुत कम, न बहुत ज़्यादा output)
→ आसानी से खोजा जा सके ऐसा बनाना (व्यापक help, उदाहरण, अगला चलाने योग्य command सुझाना, error होने पर क्या करना है यह सुझाना)
→ सामान्य बातचीत की तरह
→ मज़बूती से
→ उपयोगकर्ता के प्रति सहानुभूति रखना
→ अव्यवस्था: अगर नियम तोड़ने पड़ें, तो इरादा और उद्देश्य स्पष्ट रखें
-
CLI गाइडलाइन
→ बुनियाद
✓ command-line parsing library का उपयोग करें: Go(Cobra,cli), Node(oclif), Python (Click,Typer), Ruby(TTY)
✓ सफलता पर 0, error पर 0 के अलावा कोई code return करें
✓ output
stdoutपर दें✓ log, error आदि संदेश
stderrपर दें→ Help
✓ बिना कोई option दिए चलाने पर help दिखाएँ (
-h,--help)✓ default रूप से संक्षिप्त help दिखाएँ
· यह प्रोग्राम क्या करता है · एक-दो invocation उदाहरण · flag का विवरण (अगर बहुत ज़्यादा न हों) · अतिरिक्त विवरण के लिए `--help`✓
-h,--helpoption पर पूरी help दिखाएँ✓ feedback/issues पाने के लिए रास्ता दें
✓ help में web version docs का link दें
✓ उदाहरणों से समझाएँ
✓ अगर उदाहरण बहुत हैं, तो उन्हें कहीं और रखें (cheat sheet या web page)
✓ man page की चिंता न करें (कम इस्तेमाल होती है, और Windows पर भी काम नहीं करती)
✓ अगर help लंबी हो, तो pager में pipe करें
✓ सबसे ज़्यादा उपयोग होने वाले flags और commands को help की शुरुआत में दिखाएँ
✓ help में formatting का उपयोग करें (bold)
✓ अगर उपयोगकर्ता ने कुछ गलत किया है, और आप उसका अंदाज़ा लगा सकते हैं, तो सुझाव दें
✓ अगर आपका command किसी चीज़ को pipe से लेना चाहता है, लेकिन
stdininteractive terminal है, तो help दिखाकर तुरंत बंद हो जाए→ Output
✓ Human-readable output सबसे महत्वपूर्ण है
✓ अगर usability पर असर न पड़े, तो machine-readable output भी दें
✓ अगर human-readable की वजह से machine-readable output संभव नहीं है, तो
--plainoption दें ताकिgrep/awkआदि के साथ इस्तेमाल हो सके✓
--jsoninput मिलने पर JSON format में output दें✓ सफलता पर output न होना बेहतर है, लेकिन अगर ज़रूरी हो तो संक्षिप्त रखें।
-qoption से गैर-ज़रूरी output हटाने का समर्थन दें✓ अगर state बदलती है, तो उपयोगकर्ता को बताएं (
git pushके output को देखें)✓ वर्तमान system state को आसानी से समझ आने वाला बनाएं
✓ उपयोगकर्ता कौन-सा command चला सकता है, यह सुझाएँ। (जैसे
git statusपरgit add/restoreदिखता है)✓ प्रोग्राम की आंतरिक सीमाओं से बाहर जाने वाले actions स्पष्ट होने चाहिए। जैसे उपयोगकर्ता के कहे बिना file पढ़ना/लिखना (cache), या remote server से जुड़ना (file download)
✓ जानकारी की घनत्व बढ़ाने के लिए ASCII art का उपयोग करें
✓ color का उपयोग उद्देश्यपूर्ण ढंग से करें। ज़रूरत से ज़्यादा न करें
✓ terminal न होने पर, या उपयोगकर्ता के अनुरोध पर color बंद करें
✓ अगर
stdoutinteractive terminal नहीं है, तो animation न दिखाएँ✓ symbols/emoji केवल तब उपयोग करें जब वे कुछ स्पष्ट करें
✓ default रूप से ऐसा output न दें जिसे केवल बनाने वाले ही समझ सकें
✓
stderrको log file की तरह इस्तेमाल न करें (कम से कम default में नहीं। verbose mode मेंERR,WARNजैसे log level दिखाएँ)✓ अगर बहुत सारा text output करना है, तो
lessजैसे paging tool का उपयोग करें→ Error
✓ error को catch करें और इंसानों के लिए संदेश दोबारा लिखें
✓ Signal-to-noise ratio महत्वपूर्ण है। अगर वही error कई बार आती है, तो समझाने वाले header के साथ समूहित करके दिखाएँ
✓ सोचें कि उपयोगकर्ता सबसे पहले क्या देखेगा
✓ अगर कोई unexpected / समझ से बाहर error आए, तो debug/trace जानकारी दें, और यह bug developer को कैसे भेजें यह समझाएँ
✓ bug report बिना अतिरिक्त मेहनत के भेजी जा सके ऐसा बनाएं। (सारी जानकारी वाला URL बना दें, ताकि browser में डालते ही रिपोर्ट हो जाए)
→ Argument & Flags : arguments और flags
✓ argument: positional parameter। क्रम महत्वपूर्ण है।
cp bar fooऔरcp foo barअलग हैं✓ flag: named parameter।
-rजैसे एक अक्षर वाला, या--recursiveजैसे कई अक्षर वाला। क्रम आम तौर पर महत्वपूर्ण नहीं होताइनमें user value भी हो सकती है। `--file foo.txt` या `--file=foo.txt`✓ arguments की बजाय flags को प्राथमिकता दें। टाइपिंग ज़्यादा होगी, लेकिन यह अधिक स्पष्ट है। बहुत सारे arguments होने पर बाद में feature विस्तार करना कठिन होता है
✓ flags के short version और full version दोनों रखें। script में full version उपयोग करने पर अतिरिक्त व्याख्या की ज़रूरत नहीं पड़ती
✓ केवल अक्सर उपयोग होने वाले flags के लिए ही single-letter flag का उपयोग करें
✓ सरल कामों के लिए कई arguments लेना भी ठीक हो सकता है
✓ अगर दो या अधिक अलग arguments चाहिए, तो संभव है कि आप कुछ गलत कर रहे हों
✓ flags के लिए (अगर पहले से मौजूद हों) standard नामों का उपयोग करें
`-a --all`, `-d --debug`, `-f --force`, `-h --help`, `-o --output`, `-p --port`, `-q --quiet`, `-u --user`✓ default को ऐसा रखें जो अधिकतर उपयोगकर्ताओं के लिए सही हो
✓ अगर उपयोगकर्ता ने ऐसा argument/flag दिया है जिसे input value चाहिए, लेकिन value नहीं मिली, तो उपयोगकर्ता से input माँगें
✓ हमेशा argument/flag के जरिए value देने का तरीका दें, और input prompt को अनिवार्य न बनाएं
✓ कुछ ख़तरनाक करने से पहले हमेशा confirmation माँगें
✓ अगर input या output file है, तो
-के जरिएstdinसे input लेना याstdoutपर output देना support करें$ curl https://example.com/something.tar.gz | tar xvf -✓ अगर कोई flag अतिरिक्त value ले सकता है, तो
noneजैसे special शब्द की अनुमति दें।ssh -F none✓ जहाँ संभव हो, arguments, flags और subcommands को order-independent बनाएं
✓ sensitive (जैसे password) argument values को file से input किए जाने योग्य बनाएं
→ Interactivity
✓ prompt या interactive features केवल तब उपयोग करें जब
stdininteractive terminal हो✓ अगर
--no-inputदिया गया है, तो prompt या कोई भी interactive feature उपयोग न करें✓ password input लेते समय, उपयोगकर्ता द्वारा टाइप किया गया मान दिखाई न दे
✓ उपयोगकर्ता आसानी से बाहर निकल सके ऐसा बनाएं (vim जैसा नहीं)।
Ctrl-Cकाम करना चाहिए। अगरssh,tmuxआदि की तरह program execution से जुड़े कारणों सेCtrl-Cसंभव नहीं है, तोSSHकी तरह~से शुरू होने वाली escape sequence उपलब्ध है, यह स्पष्ट रूप से दिखाएँ→ Subcommands
✓ जटिल tools में subcommand देकर complexity कम की जा सकती है
✓ अगर कई tools आपस में काफ़ी जुड़े हों, तो उन्हें एक command में बाँधकर उपयोग आसान बनाया जा सकता है
✓ subcommands के बीच consistency रखें। वही flag वही अर्थ दे, और output format भी समान हो
✓ कई स्तर वाले subcommands में naming लगातार एक जैसी रखें
✓ भ्रमित करने वाले या मिलते-जुलते नाम वाले commands न रखें। जैसे
updateऔरupgrade→ Robustness
✓ सभी user input को validate करें। जल्दी जाँचें, और समझ में आने वाली error दिखाएँ
✓ गति से अधिक responsiveness महत्वपूर्ण है
✓ अगर समय लगे, तो progress दिखाएँ
✓ जहाँ संभव हो, काम parallel में करें। लेकिन सोच-समझकर
✓ timeout रखें
✓ idempotent बनाएं। (दोबारा चलाने पर परिणाम न बदले)। error आने पर shell में up-arrow दबाकर फिर से पहले से जारी रखने योग्य हो
✓ crash-only बनाएं। यह idempotence का अगला चरण है। अगर काम के बाद cleanup करना ज़रूरी न हो, या अगली run तक cleanup टाला जा सके, तो program failure या interruption पर तुरंत बंद हो सकता है
✓ लोग आपके program का misuse करेंगे
→ Future-proofing
✓ जहाँ संभव हो, बदलाव additive तरीके से करें। मौजूदा behavior बदलकर compatibility न तोड़ें, नया flag जोड़ें
✓ अगर additive बदलाव संभव न हो, तो पहले warning दें
✓ इंसानों के लिए output में बदलाव अधिकतर ठीक हैं
✓ किसी subcommand के लोकप्रिय होने पर भी ऐसा catch-all subcommand न बनाएं जो बिना स्पष्ट रूप से बताए वही चला दे
✓ मनमाने subcommand abbreviation की अनुमति न दें
✓ ऐसे "time bomb" न बनाएं जो किसी दिन आकर काम करना बंद कर दें
→ Signals and control Characters
✓ उपयोगकर्ता
Ctrl-C(INTsignal) दबाए तो यथासंभव जल्दी रुकें✓ अगर उपयोगकर्ता लंबे cleanup के दौरान
Ctrl-Cदबाए, तो पहली बार उसे अनदेखा करें। दूसरी बार दबाने पर force quit की अनुमति दें`^CGracefully stopping... (press Ctrl+C again to force)`→ Configuration
✓ XDG(X Desktop Group) spec का पालन करें
✓ अगर आप अपने program के अलावा किसी और की settings बदलते हैं, तो उपयोगकर्ता से पुष्टि लें, और साफ़-साफ़ बताएं कि क्या किया जा रहा है
✓ configuration parameters को priority क्रम में लागू करें
flags > shell environment variables > project-level settings (`.env`) > user settings > system settings→ Environment Variables
✓ environment variables उन behaviors के लिए हैं जो command चलने के context के अनुसार बदलते हैं
✓ portability अधिकतम करने के लिए, environment variable में केवल uppercase अक्षर/संख्याएँ/underscore हों, और वे संख्या से शुरू न हों
✓ जहाँ संभव हो, environment variables में single-line value उपयोग करें
✓ व्यापक रूप से उपयोग होने वाले नामों का उपयोग न करें
✓ जहाँ संभव हो, सामान्य environment variables को जाँचें और उपयोग करें
`NO_COLOR`, `DEBUG`, `EDITOR`, `HTTP_PROXY`, `SHELL`, `TERM`, `TERMINFO`, `HOME`, `TMPDIR`, `PAGER`, `LINES` ..✓ ज़रूरत हो तो
.envसे environment variables load करें✓ configuration file के लिए
.envextension का उपयोग न करें→ Naming
✓ नाम सरल और याद रखने में आसान शब्द हों
✓ केवल lowercase का उपयोग करें, और
-(dash) सिर्फ़ जब बहुत ज़रूरी हो तभी✓ जहाँ संभव हो, नाम छोटा रखें
✓ keyboard पर टाइप करने में आसान हो
→ Distribution
✓ जहाँ संभव हो, single binary के रूप में distribute करें
✓ आसानी से uninstall किया जा सके ऐसा बनाएं
→ Analytics
✓ tool का usage और crash data उपयोगकर्ता की सहमति के बिना अपने पास न भेजें
3 टिप्पणियां
अच्छी सामग्री के लिए धन्यवाद।
ऐसा लगता है कि Rust और Go की वजह से, जो single binary में अच्छे tools बनाना आसान बनाते हैं, अच्छे command line tools लगातार बढ़ते जा रहे हैं.
इन दिनों उपयोगी command line tools का संग्रह https://hi.news.hada.io/topic?id=793
productivity बढ़ाने वाली Rust command line utilities https://hi.news.hada.io/topic?id=2958
इन्हें बनाना भी अब और आसान तथा अधिक शक्तिशाली होता जा रहा है.
Rust से Command Line app बनाना https://hi.news.hada.io/topic?id=972
Caporal.js - Node CLI development के लिए full framework https://hi.news.hada.io/topic?id=2378
create-node-cli - Node.js से आसानी से CLI बनाना https://hi.news.hada.io/topic?id=3268
Gooey से सभी भाषाओं और CLI tools के लिए GUI बनाना https://hi.news.hada.io/topic?id=582
ink - React से CLI बनाना https://hi.news.hada.io/topic?id=2041
संक्षेप में अनुवाद करते हुए मैंने भी बहुत कुछ सीखा। काम खत्म करने के बाद लगा... शायद पूरे repo का अनुवाद करना बेहतर होता। ^^;;