2 puan yazan GN⁺ 2024-02-07 | 1 yorum | WhatsApp'ta paylaş
  • Bu kılavuz, geleneksel UNIX ilkelerini modern biçimde güncelleyerek, insanların kullanması kolay ve otomasyon için de sağlam CLI’lar oluşturmak amacıyla hazırlanmış açık kaynaklı bir tasarım rehberidir
  • İyi bir CLI insanı önceleyen şekilde çalışmalı; aynı zamanda stdout/stderr, çıkış kodları, pipe’lar ve JSON gibi teamüllere uyarak diğer programlarla doğal biçimde birleştirilebilmelidir
  • Yardım, dokümantasyon, hata mesajları ve çıktı; kullanıcının bir sonraki adımı anlayabilmesini sağlamalıdır. --help, örnekler, öneriler, ilerleme göstergeleri ve durum açıklamaları burada kilit rol oynar
  • Argümanlar, flag’ler, etkileşimler, yapılandırma ve ortam değişkenleri hem script’ler hem de terminal kullanımı düşünülerek tasarlanmalıdır; gizli değerleri doğrudan flag ya da ortam değişkeni üzerinden almamak daha güvenlidir
  • CLI’ın adı, dağıtımı ve analiz verisi toplaması bile kullanıcının kontrol hissini ve uzun vadeli uyumluluğu zedelememelidir; teamüllerin dışına çıkılması gerektiğinde de amaç net olmalıdır

CLI tasarımının temel felsefesi

  • Bu kılavuz, açık kaynaklı bir belge olarak, geleneksel UNIX ilkelerini temel alır ve modern komut satırı programları için tasarım ilkeleriyle somut yönergeler sunar
  • Geçmişte komut satırı, bir script yazma platformu üzerindeki REPL’e yakın makine öncelikli bir ortamdı; ancak günümüz CLI’ları, çeşitli araçlara, sistemlere ve platformlara erişim sağlayan metin tabanlı bir UI olarak güçlü biçimde insan öncelikli bir karakter taşır
  • Komut satırının eski kısıtları ve kendine özgü alışkanlıkları vardır; buna rağmen neredeyse tüm dizüstü bilgisayarlarda kullanılabilir, hem etkileşimli kullanıma hem de otomasyona uygundur ve diğer sistem bileşenlerine kıyasla daha yavaş değişir
  • Bu kılavuz emacs ya da vim gibi tam ekran terminal programlarını ele almaz; belirli bir programlama diline veya araç zincirine de bağlı değildir

İnsan öncelikli ve birleştirilebilir CLI

  • Bir CLI ağırlıklı olarak insanların kullandığı bir araçsa önce insanları dikkate almalıdır
    • Birçok CLI programı insan kullanıcıları hedeflediği hâlde geçmişin makine merkezli etkileşim tasarımını aynen sürdürür
  • Küçük programların temiz arayüzlerle birlikte çalışmasını öngören UNIX felsefesi hâlâ önemlidir
    • Standart giriş, çıkış ve hata; sinyaller ve çıkış kodları gibi teamüller programlar arası birleştirmeyi mümkün kılar
    • Satır tabanlı düz metin pipe ile aktarmaya uygundur; daha yapılandırılmış veri gerektiğinde JSON kullanışlıdır
  • Tutarlılık, CLI öğrenme maliyetini uzun vadeli verimliliğe dönüştüren temel unsurdur
    • Mevcut kalıpları izlemek, kullanıcıların komutları ve seçenekleri daha kolay tahmin etmesini sağlar
    • Teamüller kullanılabilirliği zedeliyorsa dikkatli biçimde bunların dışına çıkılabilir
  • İyi bir CLI ne aşırı sessiz kalmalı ne de gereğinden fazla çıktı üretmeli; kullanıcının ihtiyaç duyduğu kadar bilgi almasını sağlamalıdır
  • CLI’ların GUI’lara kıyasla keşfedilebilirliğinin zayıf olduğu düşünülür; ancak kapsamlı yardım, örnekler, sonraki komut önerileri ve hata durumunda ne yapılacağını gösteren yönlendirmelerle öğrenilebilirlik artırılabilir

Etkileşimli kullanım ve sağlamlık

  • Komut satırı kullanımı, tek seferlik bir çalıştırmadan çok birden fazla deneme ve düzeltmeden oluşan bir diyaloğa yakındır
    • Hatalı girişlerde olası düzeltmeler önerilebilir
    • Çok aşamalı işlerin ara durumu açıkça gösterilebilir
    • Tehlikeli işlemlerden önce onay alınabilir
  • CLI gerçekten sağlam olmalı; aynı zamanda kullanıcıya sağlam olduğu hissini de vermelidir
    • Beklenmeyen girdileri zarif biçimde ele almalıdır
    • Mümkün olan durumlarda işlemler idempotent olmalıdır
    • Korkutucu görünen stack trace’ler varsayılan çıktıda gösterilmemelidir
  • Kullanıcıya yazılımın kendi tarafında olduğu hissini veren empati önemlidir
    • Buradaki esas nokta emoji kullanmak ya da aracı oyunlaştırmak değil, kullanıcının başarılı olmasını sağlayacak özeni tasarıma yansıtmaktır
  • Terminal ekosisteminde çok sayıda tutarsızlık ve karmaşa vardır; ancak düşük kısıtlar sayesinde yeni icatlar mümkün olmuştur
    • Mevcut kalıplar izlenmeli, ancak üretkenliği ya da kullanıcı memnuniyetini zedeleyen standartlar bilinçli olarak terk edilebilir

Mutlaka uyulması gereken temel kurallar

  • Mümkünse komut satırı argümanı ayrıştırma kütüphanesi kullanılmalıdır
  • Başarı durumunda çıkış kodu 0, başarısızlık durumunda ise 0 olmayan bir değer döndürülmelidir
    • Script’ler programın başarılı mı başarısız mı olduğunu çıkış kodu üzerinden değerlendirir
  • Bir komutun ana çıktısı stdout’a gönderilmelidir
    • Makinenin okuyabileceği çıktılar da varsayılan olarak stdout’a gitmelidir ki pipe’lar düzgün çalışsın
  • Günlük mesajları, hatalar gibi kullanıcıya gösterilecek mesajlar stderr’e gönderilmelidir
    • Pipe ile bağlandığında bu mesajlar sonraki komutun girdisine karışmaz

Yardım tasarımı

  • -h ve --help verildiğinde yeterli yardım gösterilmelidir
    • Alt komutlar da kendi yardım metnine sahip olabilir
    • -h başka bir anlamla aşırı yüklenmemelidir
  • Argüman gerektiren bir komut hiç argüman olmadan çalıştırılırsa kısa bir yardım gösterilmelidir
    • Program açıklaması
    • Bir veya iki örnek çağrı
    • Flag açıklamaları
    • Daha ayrıntılı bilgi için --help kullanılması gerektiğine dair yönlendirme
  • Yardım metnine destek kanallarını eklemek iyi olur
    • Web sitesi veya GitHub bağlantısı yaygındır
  • Web dokümantasyonu varsa yardım metninden bu dokümantasyona bağlantı verilmelidir
    • Alt komutlara özel sayfa veya anchor varsa doğrudan oraya bağlanmak faydalıdır
  • Kullanıcılar dokümantasyondan önce örneklerden yararlanma eğilimindedir; bu yüzden yardım metninde örnekleri öne yerleştirmek iyi olur
    • Karmaşık ama yaygın kullanım senaryoları önce gösterilebilir
    • Örnek sayısı fazlaysa bunları ayrı bir cheatsheet komutunda veya web sayfasında tutmak uygundur
  • Yardım metni kolay taranacak şekilde biçimlendirilebilir
    • Kalın başlıklar okunabilirliği artırır
    • Terminalden bağımsız bir yöntem kullanılmalı; kaçış karakterlerinin olduğu gibi görünmesi engellenmelidir
  • Kullanıcı hatalı giriş yaptıysa ve niyeti tahmin edilebiliyorsa öneri sunulmalıdır
    • brew update jq komutu brew upgrade jq kullanımını önerecek şekilde davranabilir
    • Önerilen komutun çalıştırılıp çalıştırılmayacağı sorulabilir, ancak zorla çalıştırmaktan kaçınılmalıdır
  • stdin üzerinden girdi alması gereken bir komutta stdin etkileşimli terminal ise hemen yardım gösterip çıkmalı veya stderr’e mesaj yazmalıdır

Dokümantasyon

  • Yardım metni anlık bir özet ve yaygın işlere yönelik yönlendirme sunar; dokümantasyon ise aracın amacını, neyi amaçlamadığını, çalışma biçimini ve tüm kullanımını ayrıntılı biçimde ele alır
  • Web tabanlı dokümantasyon sağlanmalıdır
    • Aranabilir olmalı ve belirli bölümlere bağlantı verilebilmelidir
    • Web dokümantasyonu en kapsamlı dokümantasyon biçimidir
  • Terminal tabanlı dokümantasyon da sağlanmalıdır
    • Hızlı erişilebilir
    • Kurulu araç sürümüyle senkronizedir
    • İnternet olmadan da çalışır
  • man sayfası sunmak düşünülebilir
    • Birçok kullanıcı önce man mycmd komutuna bakar
    • git ve npm gibi araçlarda olduğu gibi help alt komutu üzerinden man sayfasına erişim sağlanabilir

Çıktı ilkeleri

  • İnsan tarafından okunabilir çıktı en önemli unsurdur
    • Belirli bir çıktı akışının insan tarafından okunup okunmadığını belirlemenin basit ölçütü TTY olup olmadığıdır
  • Kullanılabilirliği bozmadan makine tarafından okunabilir çıktı sunulmalıdır
    • Düz metin satır akışları UNIX’in evrensel arayüzüdür
    • Kullanıcılar çıktıyı grep gibi araçlara aktarınca beklendiği gibi çalışmasını bekler
  • İnsan dostu çıktı makine dostu çıktıyı bozuyorsa --plain sunulabilir
    • Tablo biçimli çıktıda hücreleri birden çok satıra bölmek, her kayıt için bir satır beklentisini bozabilir
    • --plain, betikler için üzerinde oynanmamış tablo biçimli çıktı sağlar
  • --json verilirse biçimlendirilmiş JSON çıktısı üretilmelidir
    • JSON, karmaşık veri yapılarını işlemeyi kolaylaştırır ve jq ile birçok JSON CLI aracıyla birlikte kullanılabilir
    • Web servisleri ve curl üzerinden doğrudan pipe ile bağlamak için de uygundur
  • Başarılı olduğunda çıktı vermeli, ancak kısa tutmalıdır
    • Geleneksel UNIX komutları sorun yoksa çoğu zaman çıktı vermez, ancak bu insanlara durmuş gibi görünebilir
    • Betikler için çıktısız çalışma gerekiyorsa -q seçeneğiyle zorunlu olmayan çıktı gizlenebilir
  • Durumu değiştiren komutlar, kullanıcıya neyin değiştiğini bildirmelidir
    • git push, yürütülen işi ve uzak dalın yeni durumunu gösteren bir örnektir
  • Sistemin mevcut durumu kolayca görülebilmelidir
    • git status, depo durumunu ve bir sonraki çalıştırılabilecek komut ipuçlarını birlikte gösterir
  • Programın iç dünyasının sınırlarını aşan işler genelde açık olmalıdır
    • Kullanıcının argüman olarak vermediği dosyaları okuma veya yazma durumunda
    • Uzak sunucuyla iletişim kurup dosya indirme durumunda
  • Renkler bilinçli kullanılmalıdır
    • Çok fazla kullanılırsa anlamı kaybolur ve okunması zorlaşır
    • TTY değilse, NO_COLOR ayarlanmışsa, TERM=dumb ise veya --no-color verilmişse renkler kapatılmalıdır
  • stdout etkileşimli bir terminal değilse animasyon çıktısı üretilmemelidir
    • CI günlüklerinde ilerleme göstergelerinin ortalığı kirletmesi önlenebilir
  • Çok miktarda metin çıktısı verirken less gibi bir pager kullanılabilir
    • Yalnızca stdin veya stdout etkileşimli terminal olduğunda kullanılması iyi olur
    • less -FIRX makul bir seçenek kümesi olarak kullanılabilir

Hata mesajları

  • Hataları belge gibi hazırlamak, kullanıcının dokümantasyon arama süresini azaltabilir
  • Öngörülebilir hatalar yakalanıp insanın anlayacağı şekilde yeniden yazılmalıdır
    • Örn: file.txt dosyasına yazılamadığı ve chmod +w file.txt gerekebileceği yönünde bir yönlendirme
  • Sinyal-gürültü oranı önemlidir
    • İlgisiz çıktı ne kadar fazlaysa kullanıcının sorunu anlaması o kadar zorlaşır
    • Aynı türden birden çok hata varsa tek bir açıklama başlığı altında gruplanabilir
  • En önemli bilgiyi çıktının sonuna koymak iyi olur
    • Kullanıcının bakışı kırmızı metne çekildiği için bu renk bilinçli olarak az kullanılmalıdır
  • Beklenmeyen veya açıklanması zor bir hataysa debug/traceback bilgisi ve hata bildirme yöntemi sağlanmalıdır
    • Kullanıcıyı bunaltmamak için debug günlüğü terminal yerine dosyaya yazılabilir
  • Hata bildirmeyi kolaylaştırmak gerekir
    • Mümkün olan bilgileri önceden doldurulmuş bir URL sağlamak buna örnektir

Argümanlar ve bayraklar

  • Argümanlar konuma dayalı parametrelerdir; bayraklar ise adlandırılmış parametrelerdir
    • cp foo bar içinde dosya yolları argümandır
    • -r, --recursive, --file foo.txt bayraktır
  • Mümkün olduğunda argüman yerine bayraklar tercih edilmelidir
    • Daha fazla yazmayı gerektirir ama anlamı nettir
    • Gelecekte giriş biçimini değiştirmeyi kolaylaştırır
  • Tüm bayraklar için uzun ad sağlanmalıdır
    • -h ile --helpi birlikte bulundurmak gibi
    • Betiklerde anlamı açıkça göstermeye yarar
  • Tek harfli bayraklar yalnızca sık kullanılan seçenekler için kullanılmalıdır
    • Sonradan eklenecek bayraklar için kısa ad alanı korunabilir
  • Birden çok dosyaya aynı basit işlem uygulanıyorsa birden çok argüman uygundur
    • rm file1.txt file2.txt file3.txt biçimi globbing ile iyi uyum sağlar
  • Farklı anlamlarda 2 veya daha fazla argüman varsa tasarımın hatalı olma olasılığı yüksektir
    • İstisna olarak cp <source> <destination> gibi yaygın ve temel işlemlerde kısalık hatırlamaya değerdir
  • Standart bayrak adları varsa bunlara uyulmalıdır
    • -a, --all
    • -d, --debug
    • -f, --force
    • --json
    • -h, --help
    • -n, --dry-run
    • --no-input
    • -o, --output
    • -p, --port
    • -q, --quiet
    • -u, --user
    • --version
  • Varsayılan değerler çoğu kullanıcı için doğru davranış olmalıdır
    • Kullanıcının uygun bayrağı bulup her seferinde hatırlayarak kullanacağını varsaymak çoğu kullanıcı deneyimini kötüleştirir
  • Girdi yoksa prompt ile sorulabilir, ancak prompt zorunlu olmamalıdır
    • Girdiyi bayrak veya argümanla iletmenin her zaman bir yolu sunulmalıdır
    • stdin etkileşimli terminal değilse prompt atlanmalı ve gerekli bayrak veya argüman istenmelidir
  • Tehlikeli işlemlerden önce onay alınmalıdır
    • Etkileşimli çalıştırmada y veya yes girilmesi istenebilir
    • Etkileşimli olmayan çalıştırmada -f veya --force istenebilir
    • Ciddi işlemler için silinecek hedefin adı doğrudan yazdırılabilir ya da --confirm="name-of-thing" gibi bir bayrak sunulabilir
  • Dosya girdisi/çıktısı alınıyorsa - ile stdin veya stdout desteklenmelidir
    • Geçici dosya olmadan başka komutların çıktısıyla bağlanabilir
  • Mümkün olduğunda argüman, bayrak ve alt komut sırası bağımsız işlenmelidir
    • Kullanıcıların önceki komutun sonuna seçenek ekleyip yeniden çalıştırması yaygındır
  • Gizli değerler doğrudan bayrakla okunmamalıdır
    • --password değeri ps çıktısında veya kabuk geçmişinde görünebilir
    • --password-file gibi dosya girdisi ya da stdin düşünülmelidir

Etkileşim

  • Promptlar veya etkileşimli öğeler yalnızca stdin TTY olduğunda kullanılmalıdır
    • Betiklerde veya pipe girdisi sırasında prompt çalışmayacağı için hangi bayrağın iletilmesi gerektiği hata olarak bildirilmelidir
  • --no-input verilirse prompt veya etkileşimli davranış olmamalıdır
    • Girdi gerekiyorsa işlem başarısız olmalı ve bayrakla iletme yöntemi açıklanmalıdır
  • Parola alınırken kullanıcının yazdığı değer ekrana basılmamalıdır
    • Bu, terminalin echo özelliğini kapatarak yapılır
  • Kullanıcının çıkabilmesi gerekir
    • Ağ I/O gibi nedenlerle takılı kalmış olsa bile Ctrl-C çalışmalıdır
    • SSH, tmux, telnet gibi Ctrl-C ile sonlandırılamayan sarmalayıcılarda çıkış yöntemi açıkça belirtilmelidir

Alt komutlar

  • Araç yeterince karmaşıksa alt komut kümesiyle karmaşıklık azaltılabilir
    • Birden çok ilişkili aracı tek bir komutta toplamak kullanımı ve keşfi kolaylaştırabilir
    • Genel bayrakları, yardımı, ayarları ve depolama mekanizmalarını paylaşmak için uygundur
  • Alt komutlar arasında tutarlılık gerekir
    • Aynı anlam için aynı bayrak adı kullanılmalıdır
    • Çıktı biçimi de benzer olmalıdır
  • Birden çok seviyeli alt komutlarda tutarlı bir adlandırma sistemi kullanılmalıdır
    • docker container create gibi isim ve fiilden oluşan iki seviyeli kalıp yaygındır
    • Hem noun verb hem verb noun mümkündür, ancak noun verb daha yaygın görünür
  • Belirsiz veya birbirine benzeyen komut adlarından kaçınılmalıdır
    • update ve upgrade birlikte varsa kafa karıştırıcı olabilir

Sağlamlık

  • Kullanıcının girdiği tüm veriler doğrulanmalı
    • Hatalı veri gelebileceği için hızlıca kontrol edilmeli ve anlaşılır bir hatayla durulmalı
  • Hızlı olmaktan çok tepki verebilirlik daha önemlidir
    • 100 ms içinde kullanıcıya bir şey çıktısı vermek iyidir
    • Ağ isteğinden önce bile bir mesaj yazdırarak takılmış gibi görünmesi engellenmeli
  • Uzun süren işler için ilerleme durumu gösterilmeli
    • Bir süre çıktı olmazsa program bozulmuş gibi görünür
    • İlerleme göstergesi uzun süre aynı yerde kalırsa, kalan süre tahmini veya animasyonla çalışmanın sürdüğü gösterilebilir
  • Paralel işlem mümkünse yapılmalı, ancak dikkatli olunmalı
    • Paralel işlerin ilerlemesini shell’de göstermek zordur; çıktıların birbirine karışması kafa karıştırır
    • docker pull içindeki birden fazla ilerleme çubuğu, neler olduğunu gösteren bir örnektir
    • Normal çalışmada günlükler ilerleme çubuğunun arkasına gizlense bile, hata olduğunda günlükler çıktılanmalı ki hata ayıklama mümkün olsun
  • Ağ işlemlerinin zaman aşımı olmalı
    • Zaman aşımı yapılandırılabilir olmalı ve makul bir varsayılan değere sahip olmalı
  • Hata sonrası kurtarma mümkün olmalı
    • Geçici bir hatadan sonra <up> ve <enter> ile yeniden çalıştırıldığında kaldığı yerden devam edebilmeli
  • Mümkünse crash-only yaklaşımı iyidir
    • Hata veya kesinti durumunda hemen çıkılabilir, temizlik bir sonraki çalıştırmaya bırakılabilir
  • Kullanıcılar aracı beklenmedik şekillerde kullanabilir
    • Betiklerle sarabilir, kararsız internette kullanabilir, aynı anda birden fazla örnek çalıştırabilir veya test edilmemiş ortamlarda çalıştırabilir

Geleceğe dönük uyumluluk

  • Alt komutlar, argümanlar, bayraklar, yapılandırma dosyaları ve ortam değişkenlerinin hepsi arayüzdür; uzun süre çalışır kalacak şekilde korunmalıdır
  • Mümkün olan değişiklikler eklemeli olmalı
    • Mevcut bir bayrağın davranışını bozmak yerine yeni bir bayrak eklenebilir
  • Eklemeli olmayan bir değişiklik gerekiyorsa önceden uyarılmalı
    • Artık önerilmeyen bir bayrak kullanıldığında ilerideki değişiklik bildirilmeli ve şimdiden kullanılabilecek geleceğe uyumlu yöntem de anlatılmalı
  • İnsanlara yönelik çıktının değişmesi genelde sorun değildir
    • Kullanıcılar, betiklerde kararlı çıktı için --plain veya --json kullanmaya yönlendirilmeli
  • Her şeyi yakalayan alt komutlardan kaçınılmalı
    • Bilinen bir alt komut değilse otomatik olarak run gibi ele alan bir yaklaşım, ileride yeni bir alt komut eklendiğinde mevcut kullanımları bozabilir
  • Alt komutlar için keyfi kısaltmalara izin verilmemeli
    • install için i veya ins kabul edilirse, ileride i ile başlayan başka bir komut eklemek zorlaşır
    • Takma adlar açık ve kararlı tutulmalı
  • Komutun 20 yıl sonra da aynı şekilde çalışıp çalışmayacağı düşünülmeli
    • Dış internet bağımlılıkları değişip kaybolduğunda komutu durduran bir saatli bomba yaratılmamalı

Sinyaller ve kontrol karakterleri

  • Kullanıcı Ctrl-C, yani INT sinyali gönderdiğinde mümkün olduğunca hızlı çıkılmalı
    • Temizlik işine başlamadan önce hemen bir şey söylenmeli
    • Temizlik kodu için zaman aşımı konulmalı
  • Uzun süren temizlik sırasında Ctrl-C tekrar girilirse temizlik atlanabilmeli
    • Docker Compose, kapanış sırasında Ctrl-C’ye bir kez daha basılırsa konteynerlerin hemen zorla durdurulabileceğini bildirir
  • Program, önceki temizlik işinin çalıştırılmadığı bir durumda başlatılabileceğini varsaymalı

Yapılandırma ve ortam değişkenleri

  • Yapılandırma yöntemi özgüllük, kararlılık ve karmaşıklığa göre değişmeli
    • Her çalıştırmada sık değişen ayarlar için bayraklar uygundur
    • Kullanıcıya, projeye veya makineye göre değişen nispeten kararlı ayarlar için bayraklar ve ortam değişkenleri uygundur
    • Proje içinde tüm kullanıcılar için kararlı ayarlar için sürüm kontrolüne alınan, komuta özel yapılandırma dosyası uygundur
  • XDG Base Directory Specification izlenmesi iyidir
    • ~/.config gibi genel amaçlı yapılandırma konumlarını destekleyerek ana dizindeki dotfile artışını azaltma amacı taşır
  • Kendi programınızın yapılandırması olmayan dosyaları otomatik değiştiriyorsanız kullanıcı onayı alınmalı ve tam olarak ne yapıldığı anlatılmalı
    • Mevcut sistem yapılandırma dosyasına ek yapmak yerine yeni bir yapılandırma dosyası oluşturmak daha iyidir
  • Yapılandırma önceliği yüksekten düşüğe doğru uygulanmalı
    • Bayraklar
    • Çalışan shell’in ortam değişkenleri
    • Proje düzeyi yapılandırma
    • Kullanıcı düzeyi yapılandırma
    • Sistem geneli yapılandırma
  • Ortam değişkenleri, komutun çalıştırıldığı bağlama göre değişen davranışlar için uygundur
  • Ortam değişkeni adları, en yüksek taşınabilirlik için yalnızca büyük harf, rakam ve alt çizgi kullanmalı; rakamla başlamamalı
  • Değerler mümkünse tek satır olmalı
    • Çok satırlı değerler env komutuyla birlikte kullanıldığında kullanılabilirlik sorunları çıkarır
  • Yaygın kullanılan adlar gelişigüzel sahiplenilmemeli
    • POSIX standart ortam değişkenleri listesi referans alınabilir
  • Mümkün olduğunda genel amaçlı ortam değişkenleri kontrol edilmeli
    • NO_COLOR, FORCE_COLOR
    • DEBUG
    • EDITOR
    • HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, NO_PROXY
    • SHELL
    • TERM, TERMINFO, TERMCAP
    • TMPDIR
    • HOME
    • PAGER
    • LINES, COLUMNS
  • Uygun olduğunda .env içinden ortam değişkenleri okunabilir
    • Belirli bir dizinde çalışırken neredeyse hiç değişmeyen değişkenler için yararlıdır
  • .env, resmi yapılandırma dosyasının yerine geçmez
    • Çoğu zaman kaynak kontrolüne kaydedilmez
    • Yalnızca string türü vardır
    • Düzeninin bozulması kolaydır
    • Kodlama sorunları çıkması kolaydır
    • Hassas kimlik bilgileri ve anahtar malzemesi içermesi kolaydır
  • Gizli değerler ortam değişkenlerinden okunmamalı
    • Ortam değişkenleri süreçler, günlükler, docker inspect, systemctl show vb. üzerinden açığa çıkabilir
    • Gizli bilgiler kimlik bilgisi dosyaları, pipe’lar, AF_UNIX soketleri, gizli bilgi yönetim servisleri veya başka IPC yöntemleriyle alınmalı

Adlandırma, dağıtım ve analiz toplama

  • CLI program adları kullanıcılar tarafından sık yazıldığı için basit ve hatırlanması kolay olmalı
    • Çok genel olursa diğer komutlarla çakışabilir veya kullanıcıların kafasını karıştırabilir
  • Adlarda küçük harf ve gerektiğinde tire kullanılması iyidir
    • curl iyi bir addır; DownloadURL ise iyi olmayan bir örnektir
  • Ad kısa olmalı, ancak çok kısa adlar cd, ls, ps gibi çok yaygın yardımcı programlara yakışır
  • Yazması kolay bir ad olmalı
    • Docker Compose’un ilk adının plum olduğu, tek elle yazması garip olduğu için fig olarak değiştirildiği bir örnek vardır
  • Mümkünse tek bir binary olarak dağıtılmalı
    • Tek binary zorsa, platformun varsayılan paket yükleyicisi kullanılarak kaldırması kolay bir yöntemle dağıtılmalı
    • Dile özel araçlar, örneğin kod linter’ları, kullanıcının ilgili dil yorumlayıcısına sahip olduğunu varsayabilir
  • Kaldırması kolay olmalı
    • Kurulumdan hemen sonra kaldırmak isteme durumu yaygın olduğundan, kaldırma yönergesini kurulum yönergesinin altına koymak iyidir
  • Kullanım metrikleri aracı iyileştirmeye yardımcı olabilir, ancak CLI kullanıcıları kendi ortamlarını kontrol ettiklerini varsayar
  • Onay almadan kullanım veya çökme verileri gönderilmemeli
    • Nelerin toplandığı, neden toplandığı, ne kadar anonimleştirildiği, nasıl anonimleştirildiği ve ne kadar süre saklandığı açıkça belirtilmeli
    • İdeal olan opt-in’dir; varsayılan toplama olan opt-out seçilirse web sitesinde veya ilk çalıştırmada açıkça bildirilmeli ve kolayca kapatılabilmeli
  • Analiz toplamanın alternatifleri de değerlendirilebilir
    • Web dokümantasyonu ölçümlenebilir
    • İndirmeler ölçümlenebilir
    • Kullanıcılarla doğrudan konuşulabilir; dokümantasyon ve depolarda geri bildirim ve özellik istekleri teşvik edilebilir

1 yorum

 
GN⁺ 2024-02-07
Hacker News yorumları
  • “Günümüzde çoğu kişi komut satırının ne olduğunu bile bilmiyor” sözü doğru, ama TFA'nın ölçüt aldığı 1980'lerde de durum aynıydı
    Fark şu: Bugün komut satırını bilen ve kullanabilen kişi sayısı tarihteki en yüksek seviyede; en azından tek haneli, belki de çift haneli katlar kadar arttığı için buna CLI'nin altın çağı denebilir

    • Monolitleri parçalamak için uygulamanın bazı bölümlerine komut satırı araçları ekliyorum
      Küresel durum ve bağımlılıklar akıl yürütmeyi zorlaştırıyor, sonunda hata ayıklamayı ve performans optimizasyonunu da güçleştiriyor
      500 satır, 1.000 satır, 5.000 satır, 10.000 satır, bazen 50 bin satırlık kodu ayrı çalışacak şekilde dışarı çıkarınca birçok şey çok daha netleşiyor
      Doğru yapılırsa Functional Core, Imperative Shell yapısını da teşvik edebilir; çünkü Unix felsefesine uygun bir komut satırında yan etkisiz davranışlar çok, yan etkili davranışlar az olmalı
      Kötü bir karar verilmeden hemen önceki sistem durumunu üretip çıktılayan küçük komutlar oluşturabilirsiniz; bunlar üretim ortamında da fiilen güvenle çalıştırılabilir
      Böylece bus factor kapsamına girmesi gereken kişilere de bu araçları devredip sürece dahil etmek kolaylaşır
    • “İnsanlar”ı “bilgisayar kullanıcıları”yla değiştirirseniz yazarın ana fikri doğru
      Amazon'un ücra bir uygarlık köyündeki birinin terminal hakkında ne düşündüğü konuyla ilgili değil
    • Mutlak sayı ile oranı ayırmak gerekiyor
      Niceliği büyümüş bir şeyin nitel değişimini değerlendirmek için orana bakmak gerekir; yalnızca mutlak sayıya bakarsanız doğru ama anlamsız bir cümle elde edersiniz
      Örneğin bugün caz dinleyicilerinin mutlak sayısı, türün kültürel altın çağındakinden fazla olabilir; ama bu cazın daha popüler olmasından değil, müzik dinleyen insanların genel olarak artmasından kaynaklanır
      Buna bakarak cazın ABD'de altın çağındakinden daha önemli ve etkili olduğunu söylemek zordur
    • Asıl mesele, 1980'lerde bilgisayar kullanıcıları arasında oran olarak da böyle olup olmadığı
  • Gerçek bir değişiklik yapmadan hangi işlemlerin gerçekleşeceğini önceden gösteren --dry-run seçeneğinin de dikkate alınmasını isterdim
    Bir aracı öğrenirken ya da geri alınması zor işlemleri çalıştırmadan önce karmaşık seçenekleri ve dosya glob'larını doğru kullanıp kullanmadığınızı kontrol etmek için gerçekten faydalı

    • Komut geri alınamıyorsa ve yan etkileri büyükse, varsayılanı --dry-run yapmak ve gerçek çalıştırma için --execute bayrağı istemek daha iyi
    • PowerShell'in WhatIf özelliği en sevdiğim özelliklerden biri
      Onsuz ne yapardım bilmiyorum; birçok kez tamamen berbat etmek üzere olduğum durumdan beni kurtardı
    • Tersine, varsayılan davranışın gerçek değişiklik yapmamasını ve gerçekten çalıştırmak için --commit geçirilmesini tercih ediyorum
      Geri alınamayan ya da geri alınması zor işler yapan script'ler için bu yaklaşım bana daha güvenli geliyor
    • dry run bayrağı olan komut satırı aracı örneklerini merak ediyorum
      Geliştirdiğim araçlarda bunu nasıl tasarlamam gerektiği konusunda kafam karışık
      Veri almak için API çağıran bir durumda bunu nasıl dry run yapabileceğimi bilmiyorum
      Sahte bir örnek ve sahte çıktı mı vermem gerekiyor?
    • Bence dry-run, herhangi bir komuta pipe edilebilen bir fonksiyon olmalı: do_thing.py | dry-run
      Bunu, istemde “işlem sürecini adım adım açıkla” diye sormak gibi düşünebilirsiniz
  • Standart çıktı etkileşimli terminal değilse animasyon göstermeyin demek yetmez; stdout'ta asla animasyon gösterilmemeli
    TFA genel olarak iyiydi, ama stderr ile stdout arasındaki farkı açıklayacak bir bölüm ararken bunu yapmadığını görünce üzüldüm
    stderr yalnızca hataların değil, log'ların ve bilgilendirici çıktının tamamının gitmesi gereken yerdir; terminalse animasyon da koyabileceğiniz alandır
    stdout kullanışlı gerçek çıktı olmalı ve terminal olup olmamasından bağımsız olarak tutarlı kalmalı
    Örneğin echo foo | mysed 's/oo/aa/' | cat içinde mysed'in stdout'u faa olmalı; stderr'e ise sürüm bilgisi ya da bulunan içerikler gibi log'lar gitmeli
    Sırf gerçek çıktıyı almak için grep ile araçla boğuşmak istemiyorum; | cat kısmını çıkarınca davranışın değişmesi yüzünden hata ayıklamanın zorlaşmasını da istemiyorum

    • “stdout kullanışlı çıktıdır” kuralını biraz inceltirsek, stdout kullanıcının istediği şey olmalı
      --help istendiyse stdout'a gitmeli; log istendiyse log'lar da stdout'a gitmeli
      İstenmeyen bilgiyse doğru yer stderr'dir
    • İyi bir kural ama adı talihsiz
      Zamanı geri alabilseydik stdin, stdout, stdext gibi adlar verilseydi insanların bu geleneği izleme olasılığı olurdu gibi geliyor
      Ama adı stderr olduğu için geliştiriciler makul biçimde bunun “hata raporlama için” olduğunu düşünüyor ve hata değilse stdout'a koyuyor
      Yine de program yapısı açısından bu yaklaşım daha iyi; başta daha kafa karıştırıcı olsa da çıktı üzerinden daha faydalı işler yapılabildiği için kazançlı
    • O halde animasyonların nerede gösterilmesi gerektiğini merak ediyorum
      Rengin de bilgi sayılmasının zor olduğunu düşünüyorum
  • “Netlik sağladığı yerlerde sembol ve emoji kullanın” tavsiyesinden lütfen kaçınılsın
    Örnek verilen yubikey-agent, GitHub README'lerinde ve oyuncu kullanıcı arayüzlerinde sevmediğim şeyleri aynen gösteriyor
    Teknik olarak semboller ve emojiler farklı terminallerde farklı render edilerek mesajı kafa karıştırıcı hale getirebilir
    Estetik açıdan da oyunculuk ve neşelilik toleransı kişiden kişiye çok değiştiği için çok ölçülü, gerçekten ne yaptığınızı bildiğiniz durumlarda kullanılmalı

    • Ben bu tür çıktıları seviyorum
      Renkli terminal çıktısını da seviyorum; emojiler de renkli olduğu için durumun genel resmini hızlıca kavramaya yardımcı oluyor
      Sözdizimi vurgulamayı da seviyorum; olmayınca kodu okumak bana çok daha zor geliyor
      Herkes böyle değil; kendi zevkimin varsayılan olmasını beklemediğim gibi, zıt zevk de varsayılan olarak dayatılmamalı
    • İsteğe bağlı bir özellik olursa iyi olur
      Seven de var, sevmeyen de; bu yüzden varsayılan kapalı olsun ama kullanıcı seçebilsin
    • Kılavuz olarak, çıktıda kullanılan emoji söz varlığını en fazla ikiyle sınırlamak iyi olur
      Örneğin bir başarı, bir de hata için olan yeterlidir
      Ayrıca emojinin ilettiği bilgi mutlaka metinle de yinelenmeli
    • Kesinlikle katılıyorum
      CLI Guidelines'ı ilk gördüğümde de o bölümde okumayı bırakmıştım
      Bu kez geri kalanını da okudum ve genel olarak oldukça iyiydi
  • Bazı CLI’ların aws gibi çok büyük olduğu için iç içe yapıya ihtiyaç duyduğunu anlıyorum, ama iç içe CLI içinde ilerlemek gerçekten sinir bozucu
    Çoğu uygulamanın help içinde tüm seçenekleri dökmesi ve benim de less ile ihtiyacım olanı bulmamı sağlaması daha iyi

    • Çok sayıda TUI uygulaması geliştiriyorum ve tüm uygulamalara daha az teknik kişilerin, örneğin QA’nın kullanabileceği iyi bir TUI ön yüzü ekliyorum
      Bu TUI, istenirse kullanılan saf bir UI/UX; seçilen ayarları ayrı bir üretilen dosyaya veya fonksiyona aktarıyor
      O dosya veya fonksiyon her zaman terminalden doğrudan çağrılabiliyor ve TUI’de kullanılan tüm seçenekleri ve yardım metinlerini de sunuyor
      Böylece betiklerde de kullanılabiliyor ve farklı yetkinlik seviyelerindeki kullanıcılar için faydalı oluyor
    • Alt komutların sayısına ve bu komutların ne kadar açık olduğuna bağlı
      Gerekli alt komutu biliyorsanız seçenekleri yalnızca gerekenlere indirmesi oldukça yararlı; bilmiyorsanız acı verici olabilir
      Büyük seçenek listelerinde grep ile aramak da zor, bu yüzden bir denge gerekiyor
    • Bu man sayfalarının görevi değil mi?
    • Alt komutun --help çıktısını üst komutun içine açarak yerleştirmek yardımcı olabilir
      Örneğin git stash --help komutunun, her maddeyi içeren git stash yardımını olduğu gibi göstermesi gibi
  • “Geleneksel olarak UNIX komutları, öncelikle başka programlar tarafından kullanılacağı varsayımıyla yazıldı” açıklaması doğru değil
    Başlangıçta esas olarak oturum açma shell’i içinde etkileşimli kullanım amaçlanmıştı
    stdout’a çıktı üreten programlar (ls, cat, find, tty, who, date) ve sessiz metin filtreleri (tr, grep, cut, uniq, sort, wc) vardı; o dönemde tek satırlık komutlarla temel bilişim işleri yapılabiliyordu
    Karmaşık programlar C ile yazılıyordu; sed ve AWK gibi alana özgü diller ortaya çıktıktan sonra, yoğun dize işleme yapan bazı programlar shell’e taşındı
    Shell düzgün bir programlama ortamı değildir ve hiçbir zaman bu amaçla tasarlanmamıştır

    • 10 bin satırlık bir C programının 10 satır shell ile yapılabildiği durumlar da var; 1.000 satırlık bir shell programının 100 satır C ile yapılabileceği durumlar da var
      Günümüzde ikisini de Python ya da Lua ile yapmak çoğu zaman daha iyi olabilir, ama shell ve C en yaygın kurulu olanlar
    • Düzgün olsun ya da olmasın, shell bir programlama dilidir ve erken dönem Unix’te bu durum çok daha belirgindi
      sh, bash, ksh, csh ayrışması bunun iyi bir örneği
      Standart POSIX araç takımını, çeşitli shell dillerinin standart kütüphanesi olarak görmek bence oldukça makul
  • Mevcut Unix komut satırı bir yandan “inanılmaz derecede faydalı”, diğer yandan tasarım gereği bozuk
    Aşağıdakini C veya Rust ile yazmanın ne kadar süreceğini düşününce faydası açık:
    curl -sS https://go.dev/doc/devel/release | html2text | grep -o -P '\bgo\d+\.\d+\.\d+\b' | sort -V | uniq | tail -1
    Ama neden tasarım gereği bozuk olduğunu görmek için https://news.ycombinator.com/item?id=29747034 adresine bakabilirsiniz
    Sorun, komut satırı arayüzünün hem insanlar için okunabilir hem de makineler için okunabilir olması gerekmesi ve bunu çözmenin standart bir yolunun olmaması

    • Bu örneğin kendisi, neden tasarım gereği bozuk olduğunu iyi gösteriyor
      İnsanların ve makinelerin aynı anda okuyabilmesi sorununa aslında standart bir çözüm olabilirdi
      Apple, masaüstü UI’nin görsel soyutlama anlamını somutlaştırmak için Human Interface Guidelines’ı oluşturdu
      Ama komut satırını Apple tasarımcıları gibi düşünen insanlar değil, “tembellik, sabırsızlık ve kibir erdemdir; istediğimi en az kodla nasıl ifade ederim” diye düşünen insanlar yaptı
      O dönem için yanlış bir tercih de değildi ve her bayt önemliydi; fakat o tasarım kararı bugün artık yerinden oynatılamayan bir araç zincirine gömülmüş durumda
      Bugünkünden daha iyi bir şey elde etmek için POSIX araç zincirinden fiilen vazgeçmek gerekecek gibi görünüyor; mevcut temel üzerine keşfedilebilir ve kavramsal olarak tutarlı bir UX inşa etmeyi hayal etmek zor
    • Bilgisayarlar nihayetinde bize hizmet etmek için var; bu yüzden nihai çözüm makinelerin insanlar kadar iyi okuyabilmesini sağlamak olmalı
    • Gerçekte “aynı anda”dan ziyade, genellikle insanlar ve makineler aynı komutu farklı zamanlarda kullanır
      Aynı anda bile farklı çıktılar sunmayı mümkün kılan pek çok yöntem var
      Ancak herkesin uyduğu bir standart olmalı; iş tam da bu noktada karmaşıklaşıyor
    • Bu örnek tasarım gereği bozuk olduğunu kanıtlamamakla kalmıyor, nispeten kolay bir çözümü de gösteriyor gibi
      ls uygulamalarının çok azı dosya adlarını satır sonu yerine NUL karakteriyle bitirmeye izin veriyorsa, çözüm o kadar açık görünüyor ki bir şeyi kaçırıyor gibiyim
      Shell arayüzü bunu bir nedenle reddediyor mu?
    • Yazıda ele alınan yaklaşım, --json gibi makine tarafından okunabilir çıktı modlarıdır
  • “Gizli değerleri ortam değişkenlerinden okumayın” deyip kimlik bilgisi dosyaları, pipe’lar, AF_UNIX soketleri, gizli değer yönetim servisleri ve diğer süreçler arası iletişim yöntemlerini öneriyor; bunların arasında hangisinin en kullanışlı ve taşınabilir olduğunu merak ediyorum
    Gizli değer yönetim servislerinin yalnızca işte mi kullanıldığını, kişisel projelerde de kullanılıp kullanılmadığını da merak ediyorum

    • CLI Guidelines yazarlarından biriyim
      Komut satırında gizli değerlerle çalışma konusunu biraz daha derinlemesine ele alan yazı https://smallstep.com/blog/command-line-secrets/ adresinde
      Kimlik bilgisi dosyaları basit ve taşınabilir bir seçenek
      Dosyaların zaten bir izin modeli var ve harici servislere ya da tescilli API’lere bağımlı değiller
      Bir program kimlik bilgisi dosyası kabul ediyorsa systemd credentials ile de uyumlu olur
      systemd credentials, şifrelenmemiş kimlik bilgisi dosyalarından daha güvenlidir; şifrelenir ve TPM’e de bağlanabilir, ancak kimlik bilgilerini kullanan yazılımın TPM’i kendi başına desteklemesi gerekmez
    • Programın gizli değeri getirecek komutu belirtmeye izin vermesi iyi olur
      Örneğin mbsync(https://isync.sourceforge.io/mbsync.html) IMAP kimlik doğrulama parolasını sağlamanın kabaca üç yolunu sunar
      Parola ayarlanmazsa çalıştırma sırasında bir istem çıkar; yapılandırma dosyasına düz metin parola da koyabilirsiniz ama bu, paylaşım için elverişsizdir
      Ayrıca parolayı getirecek bir komut ayarlanabildiğinden, işlem pass(1)(https://www.passwordstore.org/) gibi bir parola yöneticisine veya etkileşimli grafik bir isteme devredilebilir
    • Gizli değer yönetim servisi muhtemelen en kullanışlısı olur
      Belgeleri iyi hazırlanmıştır; ek bir şey geliştirmeye gerek kalmadan kolayca ayarlanabilir
      Doppler(https://Doppler.com) veya AWS Secrets Manager(https://aws.amazon.com/secrets-manager/) gibi gizli değer yöneticileri, gizli değerleri güvenli bir yerde koruma altına alma ve bunların açığa çıkmasını en aza indirme avantajına sahiptir
      Hatta şirket içi geliştiricilere karşı bile görünürlüğü azaltabilir; bu da kolayca önlenebilecek veri sızıntılarını engellemeye yardımcı olur
      Bu tür sızıntılar tüm şirketi riske atabilir ve giderek daha yaygın hale geliyor
  • İlgili yazılar: Command Line Interface Guidelines - https://news.ycombinator.com/item?id=38053692 - Ekim 2023, 1 yorum
    Command Line Interface Guidelines - https://news.ycombinator.com/item?id=31651161 - Haziran 2022, 1 yorum
    Command Line Interface Guidelines - https://news.ycombinator.com/item?id=25492119 - Aralık 2020, 5 yorum

  • Panodan yapıştırılan dizgenin sonunda satır sonu karakteri varsa bazı terminallerin komutu otomatik olarak çalıştırması gerçekten sinir bozucu
    Kişisel olarak komut satırı arayüzlerinin böyle yapmaması gerektiğini düşünüyorum

    • Bash’te bind 'set enable-bracketed-paste on' kullanabilirsiniz
    • macOS’taki iTerm, satır sonu içeren bir dizge yapıştırmaya çalıştığınızda onay ister
      Rahatsız ediyorsa kapatılabilir
    • Fish shell varsayılan olarak beklendiği gibi yalnızca ekler ve çalıştırmadan önce komutu düzenlemenize izin verir
      Gerekirse çok satırlı da olabilir ve çalışması için Enter’a basmanız gerekir
      Fish shell’in varsayılanları çoğu zaman mantıklıydı; istem dışında özellikle özelleştirmek istediğim bir yer henüz bulamadım
    • Bir pano yöneticisi kullanmayı denemeye değer
      Denediklerimin çoğunda pano içeriğinden satır sonlarını kaldırma seçeneği vardı
    • En fazla bir satır sonu olacağını biliyorsanız önce # yazıp sonra yapıştırın
      Satır sonu yorumlansa bile tüm satır yorum olur, böylece güvenlidir; gerçekten çalıştırmadan önce satırın başındaki # karakterini silmeniz yeterli