2 poin oleh GN⁺ 2024-02-07 | 1 komentar | Bagikan ke WhatsApp
  • Sebuah referensi dokumen open source yang merangkum prinsip perancangan program CLI dan panduan konkret sebagai reinterpretasi modern dari filosofi UNIX tradisional, dengan pembaca utama para pengembang yang membuat alat command-line
  • CLI telah berevolusi bukan sekadar platform scripting sederhana, melainkan UI teks yang berpusat pada manusia, sehingga prinsip desainnya juga perlu diperbarui mengikuti perubahan ini
  • Composability dan keramahan terhadap manusia tidak saling bertentangan; dengan mengikuti konvensi UNIX seperti standard input/output, pipe, dan exit code, keduanya dapat dicapai sekaligus
  • Tersedia rekomendasi yang konkret hingga ke rincian yang sering terlewat dalam praktik, seperti teks bantuan, pesan error, format output, interaktivitas, dan sistem konfigurasi
  • Kompatibilitas masa depan dan kepercayaan pengguna pada alat CLI ditentukan oleh stabilitas antarmuka dan transparansi data analitik, dan panduan ini memberikan garis dasar untuk itu

Filosofi (Philosophy)

Desain berpusat pada manusia

  • Perintah UNIX tradisional pada dasarnya dirancang dengan asumsi akan dipakai terutama oleh program lain, tetapi kini CLI lebih sering digunakan langsung oleh manusia, sehingga diperlukan desain yang mengutamakan manusia
  • Dulu CLI bersifat "machine-first", tetapi sekarang telah berevolusi menjadi UI berbasis teks yang "human-first"

Komponen kecil yang dapat digabungkan

  • Inti dari filosofi UNIX adalah menggabungkan program kecil dan sederhana untuk membentuk sistem yang lebih besar, dan ini masih relevan hingga sekarang
  • stdin/stdout/stderr standar, signal, dan exit code menjamin keterhubungan antarprogram, sementara JSON mendukung pertukaran data yang lebih terstruktur
  • Perangkat lunak pada akhirnya selalu menjadi bagian dari sistem yang lebih besar, dan apakah ia akan menjadi komponen yang bekerja baik ditentukan sejak tahap desain

Konsistensi

  • Pengguna terminal sudah terbiasa dengan konvensi yang ada, sehingga CLI disarankan untuk mengikuti pola yang sudah ada
  • Namun, bila konsistensi justru merusak usability, konvensi boleh dilanggar dengan pertimbangan matang

Jumlah informasi yang tepat

  • Jika sebuah perintah menunggu beberapa menit tanpa output apa pun, itu berarti informasi yang diberikan "terlalu sedikit"; jika malah membanjiri pengguna dengan log debug dalam jumlah besar, itu berarti "terlalu banyak"
  • Keseimbangan jumlah informasi sangat penting agar perangkat lunak dapat mendukung pengguna secara efektif

Kemudahan ditemukan (Ease of Discovery)

  • GUI menampilkan semua fungsinya di layar, sedangkan CLI kerap disalahpahami sebagai antarmuka yang sepenuhnya bergantung pada ingatan
  • Dengan meminjam teknik GUI seperti teks bantuan yang komprehensif, contoh yang kaya, dan saran untuk perintah berikutnya, CLI juga bisa dibuat mudah dipelajari

CLI sebagai percakapan

  • Penggunaan CLI memiliki struktur percakapan melalui siklus coba-gagal yang berulang, dan karakteristik ini bisa dimanfaatkan lewat desain seperti saran perbaikan error, tampilan status sementara, dan konfirmasi sebelum operasi berisiko
  • Interaksi terburuk adalah percakapan yang bermusuhan hingga membuat pengguna tak berdaya; yang terbaik adalah pertukaran menyenangkan yang memberi rasa pencapaian

Ketangguhan (Robustness)

  • Perangkat lunak harus tangguh baik secara nyata maupun secara rasa yang ditangkap pengguna
  • Kuncinya adalah menangani input tak terduga dengan elegan, menjaga idempotence, memberi tahu progres, dan menahan diri untuk tidak menampilkan stack trace
  • Mengurangi special case yang rumit dan menjaga sistem tetap sederhana akan meningkatkan ketangguhan

Empati (Empathy)

  • Alat CLI adalah alat kreatif bagi pengembang, sehingga harus menyenangkan untuk digunakan
  • Rancanglah dengan mempertimbangkan masalah secara mendalam agar pengguna merasakan bahwa alat ini berada di pihak mereka

Kekacauan (Chaos)

  • Dunia terminal penuh dengan ketidakkonsistenan, tetapi kekacauan itu juga merupakan sumber kreativitas yang bebas
  • "Jika standar jelas-jelas merugikan produktivitas atau kepuasan pengguna, buang standar itu." — Jef Raskin

Panduan — Dasar-dasar (The Basics)

  • Gunakan library parsing argumen: library yang direkomendasikan per bahasa antara lain Go(Cobra, cli), Python(Click, Typer, Argparse), Rust(clap), Node(oclif), dan banyak lagi
  • Saat berhasil, kembalikan exit code 0; saat gagal, kode selain 0 — inilah dasar bagi script untuk membedakan sukses dan gagal
  • Output default dikirim ke stdout, sedangkan pesan seperti log dan error dikirim ke stderr

Panduan — Bantuan (Help)

  • Tampilkan teks bantuan yang detail untuk flag -h atau --help, dan terapkan hal yang sama pada subcommand
  • Saat dijalankan tanpa argumen, tampilkan bantuan singkat (termasuk deskripsi, 1–2 contoh, penjelasan flag, dan petunjuk --help)
    • jq disebut sebagai contoh implementasi yang baik
  • Dukung berbagai bentuk permintaan bantuan seperti --help, -h, dan help subcommand
  • Sediakan tautan dokumentasi web dan jalur umpan balik di bagian atas teks bantuan
  • Tampilkan contoh lebih dulu — disarankan menyusun alur yang berkembang bertahap menuju kasus penggunaan yang lebih kompleks
  • Tempatkan flag dan command yang paling sering digunakan di bagian atas teks bantuan (mengacu pada cara git menyusunnya)
  • Gunakan pemformatan seperti judul tebal agar mudah dipindai, tetapi dengan cara yang independen dari terminal
  • Saat pengguna memasukkan hal yang salah, CLI boleh menebak maksudnya dan menyarankan perbaikan — tetapi keputusan untuk menjalankannya otomatis harus dipertimbangkan dengan hati-hati
    • Input yang salah bisa jadi bukan sekadar typo, melainkan kesalahan logis, dan auto-correct juga menambah beban untuk mendukung sintaks itu secara permanen

Panduan — Dokumentasi (Documentation)

  • Sediakan dokumentasi berbasis web — penting untuk kemudahan pencarian dan berbagi tautan
  • Sediakan dokumentasi berbasis terminal — tersinkron dengan versi yang terpasang dan tetap dapat diakses secara offline
  • Pertimbangkan menyediakan halaman man — bisa dibuat dengan alat seperti ronn, dan disarankan agar bisa diakses lewat subcommand seperti npm help ls

Panduan — Output

  • Keterbacaan bagi manusia adalah prioritas utama — gunakan status TTY untuk menentukan apakah output dibaca manusia
  • Text stream adalah antarmuka universal UNIX, sehingga output yang dapat dibaca mesin juga perlu didukung
  • Jika output yang ramah manusia merusak kompatibilitas pipe, sediakan output teks polos lewat flag --plain
  • Jika flag --json diberikan, dukung output berformat JSON
  • Saat sukses, buat output tetap ringkas; bila tidak perlu, tidak usah menampilkan apa pun — untuk keperluan script, dukung penekanan output lewat opsi -q
  • Beri tahu pengguna saat status berubah — output git push yang menampilkan status branch remote adalah contoh yang baik
  • Seperti git status, susun output agar status sistem saat ini mudah dipahami dan langkah berikutnya juga terlihat
  • Gunakan warna dengan sengaja, dan wajib menonaktifkan warna dalam kondisi seperti output dipipe, NO_COLOR, TERM=dumb, atau --no-color
  • Di lingkungan non-TTY, jangan tampilkan animasi atau spinner (untuk mencegah log CI tercemar)
  • Emoji dan simbol hanya dipakai jika benar-benar meningkatkan kejelasan (yubikey-agent disebut sebagai contoh)
  • Informasi yang hanya dipahami pengembang jangan dimasukkan ke output default; tampilkan hanya dalam mode verbose
  • Jangan gunakan stderr seperti file log — secara default, hindari label level log (ERR, WARN)
  • Untuk output dalam jumlah besar, pertimbangkan pager seperti less — aktifkan hanya di lingkungan TTY dan direkomendasikan opsi less -FIRX

Panduan — Error

  • Error yang dapat diprediksi harus ditulis ulang menjadi pesan yang bisa dipahami manusia (contoh: "Anda perlu menjalankan chmod +w file.txt")
  • Jaga rasio signal terhadap noise — error dengan tipe yang sama sebaiknya dikelompokkan di bawah satu header
  • Letakkan informasi penting di bagian akhir output — teks merah harus dipakai dengan sengaja dan jarang
  • Saat terjadi error tak terduga, sertakan informasi debug dan petunjuk cara mengirim bug report
  • Atur URL bug report agar informasi bisa terisi otomatis dan mudah dikirim

Panduan — Argumen dan Flag (Arguments and Flags)

  • Argumen (args) berbasis posisi, sedangkan flag berbasis nama — utamakan flag daripada argumen
  • Sediakan versi nama lengkap untuk semua flag (misalnya mendukung -h dan --help sekaligus)
  • Flag satu karakter sebaiknya dibatasi hanya untuk flag yang sering digunakan
  • Jika ada standar, gunakan nama flag standar seperti -f/--force, -q/--quiet, -v, --json, dan sebagainya
  • Tetapkan nilai default yang sesuai untuk sebagian besar pengguna
  • Jika argumen atau flag tidak diberikan, minta input lewat prompt, tetapi jangan memaksa prompt di lingkungan non-interaktif
  • Sebelum operasi berisiko, minta konfirmasi — tergantung tingkat risikonya, bisa berupa konfirmasi y/n, dry-run, atau meminta pengguna mengetik teks tertentu secara langsung
    • Risiko dibagi menjadi mild (menghapus file), moderate (menghapus direktori, mengubah resource remote), dan severe (menghapus seluruh server)
  • Untuk I/O file, dukung pembacaan/penulisan stdin/stdout dengan - (contoh: curl ... | tar xvf -)
  • Jangan menerima secret langsung lewat flag — gunakan flag seperti --password-file atau stdin (karena ada risiko bocor melalui output ps dan riwayat shell)

Panduan — Interaktivitas (Interactivity)

  • Prompt dan elemen interaktif hanya boleh ditampilkan saat stdin adalah TTY
  • Jika --no-input diberikan, nonaktifkan semua prompt
  • Saat memasukkan kata sandi, nonaktifkan echo (isi input tidak ditampilkan di layar)
  • Jelaskan dengan jelas agar pengguna selalu bisa keluar kapan saja — Ctrl-C harus selalu tetap berfungsi

Panduan — Subcommand

  • Jaga konsistensi nama flag dan format output antar-subcommand
  • Untuk alat yang kompleks, gunakan struktur subcommand dua tingkat berbentuk noun verb atau verb noun (contoh: docker container create)
  • Hindari subcommand dengan nama ambigu atau terlalu mirip (misalnya jangan gunakan update dan upgrade sekaligus)

Panduan — Ketangguhan (Robustness Guidelines)

  • Lakukan validasi input sejak awal, dan hentikan lebih cepat dengan error yang mudah dipahami jika datanya salah
  • Responsivitas lebih penting daripada kecepatan — tampilkan sesuatu dalam 100ms
  • Untuk pekerjaan yang memakan waktu lama, sediakan progress bar — bisa memanfaatkan library Python(tqdm), Go(schollz/progressbar), atau Node(node-progress)
  • Saat memproses secara paralel, perhatikan agar output tidak saling tercampur
  • Atur network timeout — termasuk nilai default, agar tidak menunggu selamanya
  • Setelah error sementara, desain agar retry dapat melanjutkan dari status sebelumnya
  • Terapkan desain crash-only — struktur yang bisa langsung berhenti tanpa proses cleanup untuk menjamin idempotence

Panduan — Kompatibilitas Masa Depan (Future-proofing)

  • Pertahankan perubahan dalam bentuk penambahan yang kompatibel ke belakang (additive)
  • Sebelum perubahan yang mematahkan kompatibilitas, tampilkan peringatan lebih dulu di dalam program
  • Perubahan output untuk manusia umumnya dapat diterima — untuk script, arahkan penggunaan --plain atau --json
  • Jangan buat catch-all subcommand — nanti akan menghalangi penambahan subcommand dengan nama tersebut
  • Jangan otomatis mengizinkan singkatan subcommand — hanya alias eksplisit yang boleh, dan harus dijaga stabil
  • Jangan buat "bom waktu" — minimalkan dependensi eksternal agar tetap bisa berjalan bahkan 20 tahun kemudian

Panduan — Signal dan Karakter Kontrol (Signals)

  • Saat menerima Ctrl-C (signal INT), segera keluar, dan beri timeout pada proses cleanup
  • Saat Ctrl-C ditekan lagi selama cleanup, beri tahu bahwa penghentian paksa dimungkinkan (lihat contoh Docker Compose)
  • Rancang program dengan asumsi bahwa ia bisa dimulai saat proses cleanup sebelumnya belum selesai

Panduan — Konfigurasi (Configuration)

Prioritas penerapan konfigurasi (tinggi → rendah):

  • flag → environment variable shell saat ini → konfigurasi tingkat proyek (.env) → konfigurasi tingkat pengguna → konfigurasi seluruh sistem

Rekomendasi menurut jenis konfigurasi:

  • Konfigurasi yang berubah pada setiap pemanggilan (level debug, dry-run): gunakan flag

  • Konfigurasi yang berbeda per proyek atau mesin (path, warna, HTTP proxy): kombinasi flag + environment variable

  • Konfigurasi bersama untuk seluruh proyek (tipe Makefile, package.json): gunakan file yang dikelola version control

  • Patuhi spesifikasi XDG Base Directory — disarankan memakai path konfigurasi berbasis ~/.config (didukung oleh yarn, fish, neovim, tmux, dan lain-lain)

  • Jika hendak mengubah file konfigurasi program lain secara otomatis, wajib minta persetujuan pengguna


Panduan — Environment Variable

  • Environment variable cocok untuk perilaku yang berubah sesuai konteks eksekusi
  • Nama hanya boleh memakai huruf kapital, angka, dan underscore, dan tidak boleh diawali angka
  • Disarankan memakai nilai satu baris — multiline dapat menimbulkan masalah kompatibilitas dengan perintah env
  • Periksa lebih dulu environment variable umum seperti NO_COLOR, DEBUG, EDITOR, HTTP_PROXY, SHELL, TMPDIR, HOME, PAGER
  • Disarankan mendukung pembacaan file .env per proyek — tetapi .env bukan pengganti file konfigurasi resmi
    • Keterbatasan .env: tidak masuk version control, tidak punya riwayat, hanya satu tipe string, dan rentan terhadap masalah encoding
  • Jangan membaca secret dari environment variable — karena akan diteruskan ke semua proses, bisa bocor ke log, dan terekspos lewat Docker inspect atau systemctl show
    • Secret hanya boleh diterima melalui file kredensial, pipe, socket AF_UNIX, atau layanan manajemen secret

Panduan — Penamaan (Naming)

  • Gunakan kata yang sederhana dan mudah diingat — bila terlalu umum, ada risiko bentrok dengan perintah lain
  • Gunakan huruf kecil dan dash seperlunya saja (curl adalah contoh baik, DownloadURL contoh buruk)
  • Jaga agar tetap singkat, tetapi nama yang terlalu pendek seperti cd, ls, ps sebaiknya dicadangkan untuk utility umum
  • Contoh penggantian nama pendahulu Docker Compose dari plumfigdocker compose menunjukkan bahwa kemudahan mengetik adalah kriteria penting dalam penamaan

Panduan — Distribusi (Distribution)

  • Jika memungkinkan, distribusikan sebagai binary tunggal — misalnya dengan PyInstaller
  • Jika binary tunggal tidak memungkinkan, gunakan installer paket native platform
  • Cantumkan cara uninstall di bagian bawah petunjuk instalasi

Panduan — Data Analitik (Analytics)

  • Jangan kirim data penggunaan atau data crash tanpa persetujuan pengguna
  • Jika mengumpulkan data, jelaskan secara terbuka apa yang dikumpulkan, alasannya, cara anonimisasi, dan lama penyimpanannya
  • Opt-in sebagai default direkomendasikan — bila memakai model opt-out, beri tahu dengan jelas saat pertama kali dijalankan atau di situs web
    • Diperkenalkan tiga contoh: Angular.js (opt-in eksplisit), Homebrew (Google Analytics, FAQ dipublikasikan), Next.js (telemetri anonim aktif secara default)
  • Sebagai alternatif analitik, dapat digunakan instrumentasi dokumentasi web, pengukuran jumlah unduhan, dan wawancara langsung dengan pengguna

1 komentar

 
GN⁺ 2024-02-07
Opini Hacker News
  • Saat ini banyak orang tidak tahu apa itu command line, dan juga tidak tertarik mengapa mereka harus menggunakannya.

    • Pada tahun 1980-an situasinya juga sama, tetapi sekarang justru lebih banyak orang yang memahami command line daripada sebelumnya. Bisa dibilang ini adalah masa keemasan CLI (command line interface).
  • Dalam skrip, jangan izinkan singkatan arbitrer untuk subcommand. Misalnya, jika mycmd install juga mengizinkan mycmd ins atau mycmd i, maka nantinya Anda tidak bisa menambahkan command baru yang diawali dengan i.

    • Dalam skrip, sebaiknya hindari penggunaan argumen pendek. Argumen pendek memberi kemudahan bagi manusia dengan mengurangi pengetikan, tetapi dalam skrip, penulisan yang eksplisit lebih murah biayanya, dan jika mempertimbangkan rasio baca/tulis, itu lebih diinginkan.
  • Pertimbangkan opsi --dry-run. Fitur yang memperlihatkan terlebih dahulu pekerjaan apa yang akan dilakukan tanpa melakukan perubahan nyata sangat berguna untuk mempelajari alat dan memeriksa apakah opsi yang kompleks sudah dikonfigurasi dengan benar.

  • Jika stdout bukan terminal interaktif, jangan tampilkan animasi. Ini mencegah progress bar di log output CI berubah seperti pohon Natal.

    • Jangan pernah tampilkan animasi di stdout. stderr digunakan untuk logging, pemberian informasi, dan sebagainya, sedangkan stdout harus tetap memberikan output yang berguna terlepas dari apakah itu tty atau bukan.
  • Gunakan simbol dan emoji hanya jika itu meningkatkan kejelasan.

    • Simbol dan emoji bisa dirender secara tidak konsisten antar-terminal, dan dapat menimbulkan suka atau tidak suka tergantung preferensi pengguna, jadi harus digunakan dengan sangat hati-hati.
  • Command line Unix saat ini di satu sisi "sangat berguna", tetapi di sisi lain juga memiliki "cacat desain".

    • Alasan command line Unix berguna bisa dipahami jika Anda memikirkan waktu yang dibutuhkan untuk melakukan pekerjaan yang sama dalam C atau Rust.
    • Cacat desainnya berasal dari kenyataan bahwa command line interface harus bisa dibaca oleh manusia sekaligus mesin. Tidak ada cara baku yang benar-benar menyelesaikan masalah ini.
  • Kecuali jika CLI sangat besar dan membutuhkan nesting yang dalam (misalnya aws), kebanyakan aplikasi sebaiknya menampilkan semua opsi di bantuan dan membiarkan pengguna memakai less untuk menemukan bagian yang diperlukan.

  • Secara tradisional, perintah UNIX ditulis dengan asumsi bahwa mereka terutama akan digunakan oleh program lain.

    • Pada praktiknya, perintah tersebut dimaksudkan untuk digunakan secara interaktif di dalam login shell. Ada pembagian antara program yang menghasilkan output dan text filter yang "hening", sementara program yang kompleks ditulis dalam C.
  • Jangan membaca kata sandi dari environment variable.

    • Kata sandi sebaiknya hanya diterima melalui file kredensial, pipe, socket AF_UNIX, layanan manajemen rahasia, atau mekanisme IPC lainnya.
  • Buku paling komprehensif tentang pedoman CLI adalah karya Eric Raymond.

    • Sudah cukup lama berlalu, tetapi setelah menelusuri clig.dev, terlihat bahwa banyak pandangan telah berubah seiring waktu.