2 คะแนน โดย GN⁺ 2024-02-07 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • เอกสารอ้างอิงโอเพนซอร์สที่รวบรวม หลักการออกแบบและแนวทางปฏิบัติอย่างเป็นรูปธรรมสำหรับการสร้างโปรแกรม CLI โดยตีความปรัชญา UNIX แบบดั้งเดิมใหม่ให้เข้ากับยุคปัจจุบัน และมุ่งเน้นผู้อ่านหลักเป็นนักพัฒนาที่สร้างเครื่องมือบรรทัดคำสั่ง
  • CLI ไม่ได้เป็นเพียงแพลตฟอร์มสำหรับสคริปต์เท่านั้น แต่ได้พัฒนาเป็น ข้อความ UI ที่ยึดมนุษย์เป็นศูนย์กลาง และหลักการออกแบบก็ควรถูกอัปเดตให้สอดคล้องกับการเปลี่ยนแปลงนี้
  • ความสามารถในการนำมาประกอบกัน (composability) และความเป็นมิตรต่อมนุษย์ ไม่ได้ขัดแย้งกัน และหากยึดแนวปฏิบัติของ UNIX เช่น standard input/output, pipe, exit code ก็สามารถบรรลุทั้งสองอย่างพร้อมกันได้
  • มีคำแนะนำเชิงปฏิบัติอย่างละเอียด ครอบคลุมหัวข้อที่มักถูกมองข้ามในการทำงานจริง เช่น help text, ข้อความ error, รูปแบบ output, interactivity และระบบ configuration
  • ความเข้ากันได้ในอนาคตและความเชื่อมั่นของผู้ใช้ สำหรับเครื่องมือ CLI ถูกกำหนดโดยเสถียรภาพของอินเทอร์เฟซและความโปร่งใสของข้อมูล analytics และคู่มือนี้ได้เสนอเส้นฐานสำหรับสิ่งเหล่านั้น

ปรัชญา (Philosophy)

การออกแบบที่ยึดมนุษย์เป็นศูนย์กลาง

  • คำสั่ง UNIX แบบดั้งเดิมถูกออกแบบโดยสมมติว่าใช้โดยโปรแกรมอื่นเป็นหลัก แต่ปัจจุบัน CLI ส่วนใหญ่ถูกใช้งานโดยมนุษย์โดยตรง จึงจำเป็นต้องมี การออกแบบที่ให้ความสำคัญกับมนุษย์ก่อน
  • ในอดีต CLI เป็นแบบ "machine-first" แต่ปัจจุบันได้พัฒนาเป็น UI แบบข้อความที่ "human-first"

ชิ้นส่วนเล็ก ๆ ที่นำมาประกอบกันได้

  • แก่นของปรัชญา UNIX คือ การนำโปรแกรมขนาดเล็กและเรียบง่ายมาประกอบกันเพื่อสร้างระบบที่ใหญ่กว่า ซึ่งยังคงใช้ได้ในปัจจุบัน
  • standard stdin/stdout/stderr, signal และ exit code ช่วยรับประกันการเชื่อมต่อระหว่างโปรแกรม ขณะที่ JSON รองรับการแลกเปลี่ยนข้อมูลที่มีโครงสร้างมากขึ้น
  • ซอฟต์แวร์ย่อมต้องเป็นส่วนประกอบของระบบที่ใหญ่กว่าเสมอ และการจะเป็นส่วนประกอบที่ทำงานได้ดีหรือไม่ ถูกกำหนดตั้งแต่ขั้นตอนการออกแบบ

ความสม่ำเสมอ

  • ผู้ใช้ terminal คุ้นเคยกับ convention เดิมอยู่แล้ว จึงแนะนำให้ CLI ทำตามรูปแบบที่มีอยู่เดิม
  • อย่างไรก็ตาม หากความสม่ำเสมอทำลายการใช้งานจริง ก็อาจเลือกแหกธรรมเนียมได้อย่างระมัดระวัง

ปริมาณข้อมูลที่เหมาะสม

  • หากคำสั่งรอหลายนาทีโดยไม่มี output เลย นั่นคือข้อมูล "น้อยเกินไป" และหากพ่น debug log ปริมาณมหาศาลออกมา นั่นคือข้อมูล "มากเกินไป"
  • ความสมดุลของปริมาณข้อมูล มีความสำคัญอย่างยิ่งต่อการที่ซอฟต์แวร์จะช่วยผู้ใช้ได้จริง

การค้นพบได้ง่าย (Ease of Discovery)

  • GUI แสดงความสามารถทั้งหมดไว้บนหน้าจอ แต่ CLI มักถูกเข้าใจผิดว่าต้องพึ่งพาการจดจำ
  • ด้วยการยืมเทคนิคจาก GUI เช่น help text ที่ครอบคลุม ตัวอย่างที่หลากหลาย และการแนะนำคำสั่งถัดไป ก็สามารถทำให้ CLI เรียนรู้ได้ง่ายเช่นกัน

CLI ในฐานะบทสนทนา

  • การใช้ CLI มีโครงสร้างแบบ บทสนทนา ผ่านการลองผิดลองถูกซ้ำ ๆ และสามารถใช้คุณลักษณะนี้ในการออกแบบได้ เช่น การเสนอวิธีแก้ไขข้อผิดพลาด การแสดงสถานะระหว่างทาง และการขอการยืนยันก่อนทำงานที่เสี่ยง
  • ปฏิสัมพันธ์ที่แย่ที่สุดคือบทสนทนาแบบเป็นปฏิปักษ์ที่ทำให้ผู้ใช้รู้สึกหมดแรง ขณะที่แบบที่ดีที่สุดคือการโต้ตอบที่รื่นรมย์และทำให้เกิดความรู้สึกสำเร็จ

ความทนทาน (Robustness)

  • ซอฟต์แวร์ควรดู ทนทานทั้งในความเป็นจริงและในความรู้สึกของผู้ใช้
  • หัวใจสำคัญคือการจัดการ input ที่ไม่คาดคิดอย่างสง่างาม การคงความเป็น idempotence การบอกความคืบหน้า และการหลีกเลี่ยงการแสดง stack trace โดยไม่จำเป็น
  • หากลดกรณีพิเศษที่ซับซ้อนและคงความเรียบง่ายไว้ได้ ความทนทานก็จะสูงขึ้น

ความเห็นอกเห็นใจ (Empathy)

  • เครื่องมือ CLI เป็นเครื่องมือสร้างสรรค์ของนักพัฒนา จึงควรใช้งานได้อย่างเพลิดเพลิน
  • ควรคิดและออกแบบปัญหาให้รอบด้าน เพื่อให้ผู้ใช้ รู้สึกว่าเครื่องมือนี้ยืนอยู่ข้างเขา

ความโกลาหล (Chaos)

  • โลกของ terminal เต็มไปด้วยความไม่สอดคล้องกัน แต่ความโกลาหลนั้นก็เป็นแหล่งกำเนิดของการสร้างสรรค์อย่างอิสระเช่นกัน
  • "ถ้ามาตรฐานใดเป็นโทษต่อประสิทธิภาพการทำงานหรือความพึงพอใจของผู้ใช้อย่างชัดเจน ก็จงทิ้งมาตรฐานนั้นเสีย" — Jef Raskin

แนวทาง — พื้นฐาน (The Basics)

  • ควรใช้ ไลบรารีสำหรับ parse argument: ไลบรารีที่แนะนำตามภาษา ได้แก่ Go(Cobra, cli), Python(Click, Typer, Argparse), Rust(clap), Node(oclif) และอื่น ๆ
  • เมื่อสำเร็จให้คืนค่า exit code 0 และเมื่อผิดพลาดให้คืนค่า code ที่ไม่ใช่ 0 — นี่คือเกณฑ์ที่สคริปต์ใช้ตัดสินความสำเร็จหรือความล้มเหลว
  • output ปกติให้ส่งไปที่ stdout และข้อความอย่าง log หรือ error ให้ส่งไปที่ stderr

แนวทาง — Help

  • แสดง help text แบบละเอียด เมื่อใช้แฟล็ก -h หรือ --help และใช้หลักการเดียวกันกับ subcommand ด้วย
  • เมื่อรันโดยไม่มี argument ให้แสดง help แบบกระชับ (รวมคำอธิบาย ตัวอย่าง 1~2 รายการ คำอธิบายแฟล็ก และคำแนะนำ --help)
    • มีการยก jq เป็นตัวอย่างที่ทำสิ่งนี้ได้ดี
  • รองรับ รูปแบบการขอ help ที่หลากหลาย ทั้ง --help / -h / help subcommand เป็นต้น
  • ที่ส่วนบนของ help text ควรมี ลิงก์เอกสารบนเว็บและช่องทางส่ง feedback
  • ควร แสดงตัวอย่างก่อน — แนะนำให้เล่าเป็นลำดับจากกรณีใช้งานพื้นฐานไปสู่กรณีที่ซับซ้อนขึ้น
  • วาง แฟล็กและคำสั่งที่ใช้บ่อย ไว้ด้านบนของ help text (อ้างอิงรูปแบบของ git)
  • ใช้ รูปแบบอย่างหัวข้อหนา เพื่อให้อ่านแบบกวาดสายตาได้ง่าย แต่ควรใช้วิธีที่ไม่ขึ้นกับ terminal
  • เมื่อผู้ใช้พิมพ์ผิด สามารถ คาดเดาเจตนาและเสนอการแก้ไข ได้ — แต่ควรตัดสินใจอย่างระมัดระวังว่าจะสั่งรันให้อัตโนมัติหรือไม่
    • สิ่งที่พิมพ์ผิดอาจไม่ใช่แค่ typo แต่อาจเป็นความผิดพลาดเชิงตรรกะ และหากแก้อัตโนมัติ ก็อาจต้องแบกรับภาระในการรองรับไวยากรณ์นั้นถาวร

แนวทาง — เอกสาร (Documentation)

  • ควรมี เอกสารบนเว็บ — จำเป็นต่อการค้นหาและการแชร์ลิงก์
  • ควรมี เอกสารบน terminal — ซิงก์กับเวอร์ชันที่ติดตั้งอยู่และเข้าถึงได้แม้ออฟไลน์
  • ควรพิจารณาจัดทำ man page — สามารถสร้างได้ด้วยเครื่องมืออย่าง ronn และแนะนำให้รองรับการเข้าถึงผ่าน subcommand เช่น npm help ls

แนวทาง — Output

  • ให้ความสำคัญกับ ความอ่านง่ายสำหรับมนุษย์เป็นอันดับแรก — ใช้การเป็น TTY เพื่อตรวจว่าผู้อ่านเป็นมนุษย์หรือไม่
  • text stream คืออินเทอร์เฟซสากลของ UNIX ดังนั้นควรรองรับ output ที่เครื่องอ่านได้ ด้วย
  • หาก output ที่เป็นมิตรต่อมนุษย์ทำให้ความเข้ากันได้กับ pipe เสียไป ให้มีแฟล็ก --plain สำหรับ output ข้อความธรรมดา
  • เมื่อส่งแฟล็ก --json ควรรองรับ output รูปแบบ JSON
  • เมื่อสำเร็จ output ควรกระชับ และถ้าไม่จำเป็นก็ไม่ต้องแสดงอะไร — สำหรับสคริปต์ควรรองรับตัวเลือก -q เพื่อปิด output
  • แจ้งผู้ใช้เมื่อมีการเปลี่ยนสถานะ — ตัวอย่างที่ดีคือ git push ที่แสดงสถานะของ remote branch
  • จัด output ให้ ตรวจสอบสถานะปัจจุบันของระบบได้ง่าย และแนะนำงานถัดไปด้วย เช่น git status
  • ใช้สีอย่างตั้งใจ และต้อง ปิดสีได้ ในเงื่อนไขอย่างการใช้ pipe, NO_COLOR, TERM=dumb, --no-color เป็นต้น
  • ในสภาพแวดล้อมที่ไม่ใช่ TTY ห้ามแสดง animation หรือ spinner (เพื่อหลีกเลี่ยงการทำให้ CI log สกปรก)
  • ใช้ emoji หรือสัญลักษณ์เฉพาะเมื่อช่วยเพิ่มความชัดเจนเท่านั้น (มีการยก yubikey-agent เป็นตัวอย่าง)
  • ข้อมูลที่มีแต่ผู้พัฒนาเท่านั้นที่เข้าใจควรถูกตัดออกจาก output ปกติ และแสดงเฉพาะใน verbose mode
  • อย่าใช้ stderr เหมือนเป็นไฟล์ log — โดยปกติควรหลีกเลี่ยงการพิมพ์ label ระดับ log (ERR, WARN)
  • เมื่อมี output จำนวนมาก ควรพิจารณาใช้ pager เช่น less — เปิดใช้เฉพาะในสภาพแวดล้อม TTY และแนะนำตัวเลือก less -FIRX

แนวทาง — Error

  • สำหรับ error ที่คาดการณ์ได้ ควร เขียนข้อความใหม่ให้อยู่ในรูปที่มนุษย์เข้าใจได้ (เช่น "ต้องรัน chmod +w file.txt")
  • รักษา อัตราส่วนสัญญาณต่อสัญญาณรบกวน — error ประเภทเดียวกันควรถูกรวมไว้ใต้หัวข้อเดียว
  • ข้อมูลสำคัญควร วางไว้ท้าย output — ข้อความสีแดงควรใช้โดยมีเจตนาและใช้น้อยครั้ง
  • เมื่อเกิด error ที่ไม่คาดคิด ควรมีข้อมูล debug และ วิธีส่ง bug report รวมอยู่ด้วย
  • ควรจัดให้ URL ของ bug report เติมข้อมูลให้อัตโนมัติ เพื่อให้ส่งรายงานได้ง่าย

แนวทาง — Argument และ Flag

  • argument (args) อิงตามตำแหน่ง ส่วน flag อิงตามชื่อ — ควร เลือกใช้ flag มากกว่า argument
  • ทุกแฟล็กควรมี เวอร์ชันชื่อเต็ม (เช่น รองรับทั้ง -h และ --help)
  • แฟล็กตัวอักษรเดี่ยว ควรจำกัดไว้สำหรับแฟล็กที่ใช้บ่อยเท่านั้น
  • หากมีมาตรฐานอยู่แล้ว ให้ใช้ ชื่อแฟล็กตามมาตรฐาน (-f/--force, -q/--quiet, -v, --json เป็นต้น)
  • ค่าเริ่มต้นควรถูกตั้งเป็น ค่าที่เหมาะกับผู้ใช้ส่วนใหญ่
  • หากไม่มี argument หรือ flag ที่จำเป็น ควร ขอ input ผ่าน prompt แต่ในสภาพแวดล้อมที่ไม่โต้ตอบ ห้ามบังคับให้มี prompt
  • ก่อนทำงานที่เสี่ยง ควรมี การขอการยืนยัน — ตามระดับความเสี่ยงอาจใช้การยืนยัน y/n, มี dry-run หรือให้พิมพ์ข้อความยืนยันเองโดยตรง
    • แบ่งระดับความเสี่ยงเป็น mild(ลบไฟล์), moderate(ลบไดเรกทอรี, เปลี่ยนทรัพยากรระยะไกล), severe(ลบเซิร์ฟเวอร์ทั้งหมด)
  • เมื่อมี file input/output ควรรองรับการอ่าน/เขียน stdin/stdout ด้วย - (เช่น curl ... | tar xvf -)
  • ห้ามรับ secret ผ่านแฟล็กโดยตรง — แนะนำให้ใช้แฟล็กอย่าง --password-file หรือใช้ stdin (เพราะเสี่ยงถูกเปิดเผยผ่านผลลัพธ์ ps และ shell history)

แนวทาง — Interactivity

  • prompt และองค์ประกอบแบบ interactive ควร แสดงเฉพาะเมื่อ stdin เป็น TTY
  • เมื่อส่ง --no-input ต้องปิด prompt ทั้งหมด
  • เมื่อต้องรับรหัสผ่าน ให้ ปิด echo (ไม่แสดงสิ่งที่พิมพ์บนหน้าจอ)
  • ควรอธิบายให้ชัดเจนว่าผู้ใช้ สามารถออกจากกระบวนการได้ตลอดเวลา — และต้องทำให้ Ctrl-C ใช้งานได้เสมอ

แนวทาง — Subcommand

  • รักษา ความสม่ำเสมอของชื่อแฟล็กและรูปแบบ output ระหว่าง subcommand ต่าง ๆ
  • เครื่องมือที่ซับซ้อนควรใช้ โครงสร้าง subcommand สองระดับ แบบ noun verb หรือ verb noun (เช่น docker container create)
  • หลีกเลี่ยง subcommand ที่ชื่อกำกวมหรือคล้ายกัน (เช่น ไม่ควรใช้ทั้ง update และ upgrade พร้อมกัน)

แนวทาง — ความทนทาน (Robustness Guidelines)

  • ทำ การตรวจสอบ input ตั้งแต่เนิ่น ๆ และหากข้อมูลไม่ถูกต้องให้จบการทำงานอย่างรวดเร็วพร้อม error ที่เข้าใจง่าย
  • ความตอบสนองสำคัญกว่าความเร็ว — ควร แสดงอะไรบางอย่างภายใน 100ms
  • สำหรับงานที่ใช้เวลานาน ควรมี progress bar — สามารถใช้ไลบรารีอย่าง Python(tqdm), Go(schollz/progressbar), Node(node-progress)
  • เมื่อต้องประมวลผลแบบขนาน ควรระวังไม่ให้ output ปะปนกัน
  • ควร ตั้งค่า network timeout — รวมค่าเริ่มต้นไว้ด้วย เพื่อป้องกันการรอแบบไม่สิ้นสุด
  • หลังเกิดข้อผิดพลาดชั่วคราว ควรออกแบบให้ ลองใหม่แล้วทำต่อจากสถานะเดิมได้
  • การออกแบบแบบ crash-only — ทำให้สามารถจบการทำงานได้ทันทีโดยไม่ต้องมีขั้นตอน cleanup เพื่อคง idempotence

แนวทาง — การรองรับอนาคต (Future-proofing)

  • การเปลี่ยนแปลงควรคงไว้ในรูปแบบ เพิ่มแบบไม่ทำลายความเข้ากันได้เดิม (additive)
  • ก่อนมีการเปลี่ยนแปลงที่ทำลายความเข้ากันได้ ควร แสดงคำเตือนล่วงหน้าในโปรแกรม
  • การเปลี่ยน output สำหรับมนุษย์โดยทั่วไปทำได้ — ส่วนกรณีสำหรับสคริปต์ควรชี้นำให้ใช้ --plain และ --json
  • ห้ามมี catch-all subcommand — เพราะจะทำให้ภายหลังเพิ่ม subcommand ชื่อนั้นไม่ได้
  • ห้ามรองรับตัวย่อของ subcommand แบบอัตโนมัติ — อนุญาตเฉพาะ alias ที่ประกาศชัดเจนและดูแลให้เสถียร
  • ห้ามสร้าง "ระเบิดเวลา" — ควรลดการพึ่งพาภายนอกให้มากที่สุดเพื่อให้ยังทำงานได้อีก 20 ปีข้างหน้า

แนวทาง — Signal และอักขระควบคุม (Signals)

  • เมื่อได้รับ Ctrl-C (สัญญาณ INT) ให้ จบการทำงานทันที และกำหนด timeout สำหรับขั้นตอน cleanup
  • ระหว่าง cleanup หากกด Ctrl-C ซ้ำ ควรมีคำแนะนำว่าผู้ใช้สามารถบังคับจบการทำงานได้ (ดูตัวอย่าง Docker Compose)
  • โปรแกรมควรถูกออกแบบโดยสมมติว่า อาจเริ่มทำงานในสถานะที่ cleanup จากครั้งก่อนยังไม่เสร็จสมบูรณ์

แนวทาง — Configuration

ลำดับความสำคัญของการใช้ configuration (สูง → ต่ำ):

  • flag → environment variable ของ shell ปัจจุบัน → configuration ระดับโปรเจกต์ (.env) → configuration ระดับผู้ใช้ → configuration ทั้งระบบ

คำแนะนำตามประเภท configuration:

  • configuration ที่เปลี่ยนในแต่ละครั้งที่เรียกใช้ (ระดับ debug, dry-run): ใช้ flag

  • configuration ที่ต่างกันไปตามโปรเจกต์หรือเครื่อง (path, สี, HTTP proxy): ใช้ flag + environment variable ร่วมกัน

  • configuration ที่แชร์ร่วมกันทั้งโปรเจกต์ (ประเภท Makefile, package.json): ใช้ไฟล์ที่อยู่ภายใต้ version control

  • ปฏิบัติตาม XDG Base Directory spec — แนะนำเส้นทาง configuration บนพื้นฐาน ~/.config (รองรับโดย yarn, fish, neovim, tmux เป็นต้น)

  • หากจะปรับแก้ไฟล์ configuration ของโปรแกรมอื่นโดยอัตโนมัติ ต้อง ขอความยินยอมจากผู้ใช้ก่อนเสมอ


แนวทาง — Environment Variables

  • environment variable เหมาะกับ พฤติกรรมที่เปลี่ยนไปตาม execution context
  • ชื่อควรใช้เฉพาะ ตัวพิมพ์ใหญ่ ตัวเลข และ underscore และห้ามขึ้นต้นด้วยตัวเลข
  • แนะนำให้ใช้ ค่าแบบบรรทัดเดียว — ค่าแบบหลายบรรทัดอาจมีปัญหาความเข้ากันได้กับคำสั่ง env
  • ควรตรวจสอบ environment variable ทั่วไป ก่อน เช่น NO_COLOR, DEBUG, EDITOR, HTTP_PROXY, SHELL, TMPDIR, HOME, PAGER
  • แนะนำให้รองรับการอ่านไฟล์ .env ของแต่ละโปรเจกต์ — แต่ .env ไม่ใช่ตัวแทนของไฟล์ configuration อย่างเป็นทางการ
    • ข้อจำกัดของ .env: ไม่อยู่ภายใต้ version control, ไม่มีประวัติการเปลี่ยนแปลง, มี type เดียวคือ string, และเปราะบางต่อปัญหา encoding
  • ห้ามอ่าน secret จาก environment variable — เพราะถูกส่งต่อไปยังทุก process, อาจรั่วใน log และเสี่ยงถูกเปิดเผยผ่าน Docker inspect หรือ systemctl show
    • secret ควรรับผ่าน credential file, pipe, AF_UNIX socket หรือบริการจัดการ secret เท่านั้น

แนวทาง — การตั้งชื่อ (Naming)

  • ใช้ คำที่เรียบง่ายและจำง่าย — หากกว้างเกินไปอาจเสี่ยงชนกับคำสั่งอื่น
  • ใช้เฉพาะ ตัวพิมพ์เล็กและขีดเมื่อจำเป็น (curl เป็นตัวอย่างที่ดี ส่วน DownloadURL เป็นตัวอย่างที่ไม่ดี)
  • ควรรักษาให้สั้น แต่ชื่อที่สั้นมากระดับ cd, ls, ps ควรถูกสงวนไว้สำหรับยูทิลิตีทั่วไป
  • กรณีเปลี่ยนชื่อจาก plumfigdocker compose ซึ่งเป็นชื่อก่อนหน้าของ Docker Compose แสดงให้เห็นว่า ความสะดวกในการพิมพ์เป็นเกณฑ์สำคัญของการตั้งชื่อ

แนวทาง — การแจกจ่าย (Distribution)

  • หากเป็นไปได้ ควร แจกจ่ายเป็นไบนารีเดียว — เช่น ใช้ PyInstaller
  • หากไม่สามารถทำเป็นไบนารีเดียวได้ ให้ใช้ ตัวติดตั้งแพ็กเกจแบบ native ของแพลตฟอร์ม
  • ควร ระบุวิธีถอนการติดตั้งไว้ด้านล่างของคำแนะนำการติดตั้ง

แนวทาง — Analytics

  • ห้ามส่งข้อมูลการใช้งานหรือข้อมูล crash โดยไม่ได้รับความยินยอมจากผู้ใช้
  • หากมีการเก็บข้อมูล ต้องเปิดเผยอย่างชัดเจนว่ารวบรวมอะไร ทำไมต้องเก็บ ทำให้ไม่ระบุตัวตนอย่างไร และเก็บไว้นานเท่าใด
  • แนะนำให้ใช้แบบ opt-in เป็นค่าเริ่มต้น — หากเป็นแบบ opt-out ต้องแจ้งอย่างชัดเจนตั้งแต่การรันครั้งแรกหรือบนเว็บไซต์
    • มีการแนะนำสามกรณีศึกษา: Angular.js (opt-in อย่างชัดเจน), Homebrew (Google Analytics พร้อม FAQ ที่เปิดเผย), Next.js (สถิติไม่ระบุตัวตนที่เปิดใช้โดยค่าเริ่มต้น)
  • ทางเลือกแทน analytics ได้แก่ การวัดผลเอกสารบนเว็บ, การวัดจำนวนดาวน์โหลด และการสัมภาษณ์ผู้ใช้โดยตรง

1 ความคิดเห็น

 
GN⁺ 2024-02-07
ความเห็นจาก Hacker News
  • ปัจจุบันมีคนจำนวนมากที่ไม่รู้ว่าคอมมานด์ไลน์คืออะไร และก็ไม่ได้สนใจด้วยว่าทำไมจึงควรใช้งานมัน

    • สถานการณ์แบบนี้ก็เป็นเหมือนกันในช่วงทศวรรษ 1980 แต่ตอนนี้มีคนที่รู้จักคอมมานด์ไลน์มากกว่าที่เคย จึงอาจเรียกได้ว่าเป็นยุคทองของ CLI (Command Line Interface)
  • ในสคริปต์ไม่ควรอนุญาตให้ย่อ subcommand แบบตามอำเภอใจ ตัวอย่างเช่น หากอนุญาตให้ใช้ mycmd ins หรือ mycmd i แทน mycmd install ก็จะไม่สามารถเพิ่มคำสั่งใหม่ที่ขึ้นต้นด้วย i ได้อีก

    • ควรหลีกเลี่ยงการใช้อาร์กิวเมนต์แบบสั้นในสคริปต์ อาร์กิวเมนต์แบบสั้นมีไว้เพื่อช่วยลดการพิมพ์เวลาที่มนุษย์ใช้งาน แต่สำหรับสคริปต์ การเขียนให้ชัดเจนตรงไปตรงมามีต้นทุนต่ำกว่า และเมื่อคำนึงถึงสัดส่วนการอ่านต่อการเขียนก็ยิ่งเหมาะสมกว่า
  • ควรพิจารณาตัวเลือก --dry-run ฟังก์ชันที่แสดงล่วงหน้าว่าจะมีการทำงานอะไรเกิดขึ้นโดยไม่ทำการเปลี่ยนแปลงจริงนั้น มีประโยชน์มากในการเรียนรู้เครื่องมือและตรวจสอบว่าตั้งค่าตัวเลือกที่ซับซ้อนได้ถูกต้องหรือไม่

  • หาก stdout ไม่ได้เป็นเทอร์มินัลแบบโต้ตอบ ก็อย่าแสดงแอนิเมชัน วิธีนี้ช่วยป้องกันไม่ให้แถบความคืบหน้าในล็อกของ CI กลายเป็นเหมือนต้นคริสต์มาส

    • ไม่ควรแสดงแอนิเมชันบน stdout เด็ดขาด stderr มีไว้สำหรับการล็อก การให้ข้อมูล และงานลักษณะนั้น ส่วน stdout ควรให้ผลลัพธ์ที่เป็นประโยชน์ไม่ว่าจะเป็น tty หรือไม่ก็ตาม
  • ควรใช้สัญลักษณ์และอีโมจิก็ต่อเมื่อมันช่วยเพิ่มความชัดเจน

    • สัญลักษณ์และอีโมจิอาจแสดงผลไม่สม่ำเสมอในแต่ละเทอร์มินัล และอาจมีทั้งคนชอบและไม่ชอบตามรสนิยมของผู้ใช้ จึงควรใช้อย่างระมัดระวังมาก
  • คอมมานด์ไลน์ Unix ในปัจจุบันนั้นด้านหนึ่งก็ "มีประโยชน์อย่างน่าทึ่ง" แต่อีกด้านหนึ่งก็มี "ข้อบกพร่องด้านการออกแบบ"

    • เหตุผลที่คอมมานด์ไลน์ Unix มีประโยชน์นั้น จะเห็นได้ชัดเมื่อคิดว่าหากต้องทำงานเดียวกันด้วย C หรือ Rust จะต้องใช้เวลามากเพียงใด
    • ข้อบกพร่องด้านการออกแบบเกิดจากการที่ command line interface ต้องอ่านได้ทั้งโดยมนุษย์และเครื่องจักรพร้อมกัน ซึ่งไม่มีวิธีมาตรฐานตายตัวในการแก้ปัญหานี้
  • เว้นแต่กรณีที่ CLI มีขนาดใหญ่มากและจำเป็นต้องมีการซ้อนกันหลายระดับ (เช่น aws) แอปส่วนใหญ่ควรแสดงตัวเลือกทั้งหมดใน help และปล่อยให้ผู้ใช้ใช้ less เพื่อค้นหาสิ่งที่ต้องการ

  • ตามธรรมเนียมแล้ว คำสั่ง UNIX ถูกเขียนขึ้นบนสมมติฐานว่าจะถูกใช้งานโดยโปรแกรมอื่นเป็นหลัก

    • ในความเป็นจริง มันถูกตั้งใจให้ใช้แบบโต้ตอบภายใน interactive login shell โดยแบ่งเป็นโปรแกรมที่สร้างเอาต์พุต กับ text filter แบบ "เงียบ" และโปรแกรมที่ซับซ้อนจะเขียนด้วย C
  • อย่าอ่านรหัสผ่านจาก environment variable

    • ควรรับรหัสผ่านผ่านไฟล์ credential, pipe, AF_UNIX socket, บริการจัดการความลับ หรือกลไก IPC อื่น ๆ เท่านั้น
  • หนังสือที่ครอบคลุมเรื่องแนวทางปฏิบัติของ CLI มากที่สุดคือหนังสือของ Eric Raymond

    • แม้จะผ่านมานานแล้ว แต่พอลองไล่อ่าน clig.dev ก็จะเห็นได้ว่ามุมมองหลายอย่างเปลี่ยนไปมากตามกาลเวลา