50 คะแนน โดย xguru 2024-09-03 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • หนึ่งในวิธีที่มีประโยชน์ที่ทีมพัฒนาใช้ในการรวบรวมและเก็บรักษาความรู้ขององค์กร คือการเพิ่มชุด snippet, script หรือ workflow ที่มีประโยชน์ให้มากขึ้น
  • นั่นจึงเป็นเหตุผลที่หลายรีโพซิทอรีมีสิ่งอย่าง Makefile หรือ bash script ถูกสร้างขึ้นมา
  • แล้วสิ่งอย่างการติดตั้งเครื่องมือที่มีประโยชน์ทั่วทั้งองค์กร, การสร้าง boilerplate code หรือการรันคำสั่ง AWS ที่ซับซ้อนซึ่งไม่มีใครจำได้ ควรทำอย่างไร?
    • บางบริษัท เช่น Slack หรือ Shopify มี CLI ภายในของตัวเอง
    • เทอร์มินัลสมัยใหม่อย่าง Warp มีความสามารถในการจัดทำเอกสารและแชร์ workflow ได้
  • CLI สำหรับใช้งานภายในองค์กรสามารถสร้างได้ง่าย ตัวอย่างนี้จะลองสร้าง CLI สำหรับบริษัทชื่อ acme

ข้อกำหนดในการออกแบบ CLI

  • มีจุดเข้าใช้งานร่วมที่สามารถรันคำสั่งจากที่ไหนก็ได้ด้วย acme <command>
    • นักพัฒนาทุกคนสามารถสั่ง acme <command> จากที่ใดก็ได้เพื่อทริกเกอร์คำสั่ง โดยไม่ต้องย้ายไปยังรีโพซิทอรีใดรีโพซิทอรีหนึ่งก่อน
  • เปิดให้นักพัฒนาร่วมเพิ่มคำสั่งใหม่ได้ง่าย
  • ทำให้สามารถปล่อยเวอร์ชันใหม่ได้ง่ายด้วย acme update
  • รองรับข้ามแพลตฟอร์ม (เช่น ถ้าสั่ง acme download something บน Linux ให้ใช้ curl แต่บน Windows ให้ใช้ Invoke-WebRequest)
  • ให้ acme list แสดงรายการคำสั่งที่ใช้งานได้พร้อมคำอธิบายสั้น ๆ

เริ่มโปรเจ็กต์ด้วย just

  • just เป็นเครื่องมือคล้าย make แต่เน้นการรันคำสั่งโดยเฉพาะ
  • รองรับข้ามแพลตฟอร์ม และยังสามารถรันคำสั่งเฉพาะแพลตฟอร์มได้ด้วย
  • ตัวเลือกอื่นมีเช่น magic-cli ของ Slack (เหมาะมากถ้าคุณถนัด Ruby) หรือ make

การตั้งค่าโปรเจ็กต์

  • ติดตั้ง just โดยทำตามคำแนะนำ ที่นี่
  • สร้างโฟลเดอร์ ~/acme/cli แล้วเพิ่ม justfile ต่อไปนี้ไว้ที่ root:
default:  
  just --list  
  
# Show arch and os name   
os-info:  
  echo "Arch: {{arch()}}"  
  echo "OS: {{os()}}"  
  • ในเอกสารของ just คำสั่งถูกเรียกว่า "recipes"
  • ถ้ารัน just โดยไม่ระบุ recipe ระบบจะรัน recipe แรกใน justfile โดยปกติรูปแบบที่นิยมคือกำหนดชื่อ recipe แรกว่า "default"
$ just  
just --list  
Available recipes:  
    default  
    os-info # Show arch and os name  
  • recipe default จะรัน just list เพื่อแสดงรายการ recipe ทั้งหมดพร้อมคอมเมนต์
  • ควรซ่อน recipe default ไว้
  • เมื่อรัน recipe แต่ละคำสั่งจะถูกพิมพ์ออกมาก่อนการทำงาน สามารถใช้ prefix @ เพื่อปิดการแสดงผลนี้ได้ คล้ายกับ Makefile
[private]  
@default:  
  just --list  
  
# Show arch and os name  
@os-info:  
  echo "Arch: {{arch()}}"  
  echo "OS: {{os()}}"  

สร้าง alias acme

  • เพื่อให้รันในรูปแบบ acme <command> ให้เพิ่ม alias ใน .bashrc
    alias acme='just --justfile ~/acme/cli/justfile'  
    
  • โหลด alias ใหม่ด้วย source ~/.bashrc หรือ exec bash

การเขียน recipe ใหม่

recipe แบบง่าย

  • ดึงข้อมูลผู้ใช้/บทบาท AWS IAM
    @aws-id:  
      aws sts get-caller-identity  
    
    • การทำให้คำสั่งที่ไม่มีใครจำได้กลายเป็นเรื่องง่าย น่าจะเป็น use case หลักของ CLI ภายในองค์กร
    • สมมติว่า awscli รองรับข้ามแพลตฟอร์ม ดังนั้น recipe นี้จึงทำงานได้ไม่ว่าจะถูกเรียกจากที่ใด

recipe เฉพาะแพลตฟอร์ม

  • snippet ที่มีเครื่องมืออย่าง systemd จะถูกเปิดให้เห็นเฉพาะเมื่อนักพัฒนาใช้เครื่อง Linux เท่านั้น
  • ใช้แอตทริบิวต์ [linux] เพื่อให้ recipe แสดงเฉพาะบน Linux
[linux]  
@list-systemd-services:  
  systemctl list-units --type=service  

recipe แบบข้ามแพลตฟอร์ม

  • ตัวอย่างการหาขนาดโฟลเดอร์โดยแยก implementation สำหรับ Windows และ Linux
    [windows]  
    [no-cd]  
    get-folder-size path:  
      (Get-ChildItem "{{path}}" -Recurse -Force | Measure-Object -Property Length -Sum).Sum / 1MB  
    
    [linux]  
    [no-cd]  
    get-folder-size path:  
      du -sh {{path}}  
    

recipe แบบสคริปต์

  • สามารถฝังสคริปต์ทั้งชุดลงใน recipe ได้
  • recipe ที่เริ่มด้วย shebang (#!) จะถูกบันทึกเป็นไฟล์แยกแล้วจึงนำไปรัน
  • มีประโยชน์เมื่อ workflow ต้องการตรรกะที่ซับซ้อนขึ้นเล็กน้อย เช่น control flow (if-else, loop), การเก็บและจัดการตัวแปร เป็นต้น
# Say hello world in sh  
hello-world-sh:  
  #!/usr/bin/env sh  
  hello='Yo'  
  echo "$hello from a shell script!"  
  • นี่หมายถึงสามารถใช้ภาษาโปรแกรมที่มีความสามารถด้าน scripting ที่ทรงพลังได้ งานบางอย่างทำใน Python ได้ง่ายกว่า Bash
# scale jpg image by 50%  
[no-cd]  
scale-jpg path:  
  #!/usr/bin/env python3  
  
  import PIL.Image  
  image = PIL.Image.open("{{path}}")  
  factor = 0.5  
  image = image.resize((round(image.width * factor), round(image.height * factor)))  
  image.save("{{path}}.s50.jpg")  
  • ไม่ใช่นักพัฒนาทุกคนจะติดตั้ง Python ไว้ในเครื่อง และถึงติดตั้งแล้วก็อาจไม่มี pillow ดังนั้นจึงสามารถใช้ nix เพื่อรันสคริปต์พร้อม dependency ได้:
# scale jpg image by 50%  
[no-cd]  
scale-jpg path:  
  #! /usr/bin/env nix-shell  
  #! nix-shell -i python3 -p python3Packages.pillow  
  
  import PIL.Image  
  ...  

การแจกจ่าย recipe

  • ใช้ git แทนการเขียนกลไก deploy เอง
  • สร้างรีโพซิทอรีบน GitHub แล้ว push สิ่งที่ทำมาจนถึงตอนนี้ขึ้นไป
$ git init  
$ git commit -m "first commit"  
$ git branch -M main  
$ git remote add origin git@github.com:acme/cli.git  
$ git push -u origin main  
  • ตอนนี้ใครก็ตามที่เข้าถึงรีโพนี้ได้ ก็สามารถสร้าง PR เพื่อร่วมส่งการเปลี่ยนแปลงเข้ามาได้
  • ทำ git pull อัตโนมัติด้วย recipe acme update
# Update the Acme CLI  
@update:  
  git fetch  
  git checkout main  

เอกสารประกอบ

  • ความสำเร็จของเครื่องมือภายในขึ้นอยู่กับการยอมรับใช้งานอย่างมาก ดังนั้นคู่มือการใช้งานที่ดีซึ่งช่วยให้ผู้ใช้ใหม่ติดตั้งและสำรวจเครื่องมือได้จึงสำคัญมาก
  • แนะนำวิธีติดตั้งและใช้งานใน README
# Acme CLI  
  
## Prerequisites  
  
`just`: Install just [here](https://github.com/casey/just/blob/master/README.md#installation)  
  
## Installation  
  
Clone this repo:  
...  
  
Set up the `acme` alias:  
...  
  
## Usage  
  
List all available recipes:  
...  
  • ตอนนี้นักพัฒนาทุกคนใน Acme Corp สามารถใช้งานได้แล้ว!
  • โพสต์ข้อความใน Slack ภายในบริษัทเพื่อชวนให้ทุกคนลองใช้ และแต่ละคนก็สามารถส่ง snippet ของตัวเองเข้ามาได้

ฟีเจอร์เพิ่มเติม

  • ฟังก์ชัน Completion คือกลไกที่ช่วยเติมคำสั่งย่อย, path ของไฟล์, option ฯลฯ อัตโนมัติเมื่อกดปุ่ม TAB
  • shell ส่วนใหญ่มีความสามารถนี้ และ CLI tool หลัก ๆ ส่วนใหญ่ก็มักมีวิธีติดตั้ง completion ให้ด้วย
    • CLI framework หลักส่วนมาก เช่น Click ของ Python, Cobra ของ Golang, clap ของ Rust สามารถสร้าง completion ได้อัตโนมัติ
  • Just สามารถสร้าง Completion ได้ด้วยการรัน just --completion <shell>.

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

 
bus710 2024-09-03

ดูเหมือนว่าการออกแบบ DX ภายในบริษัทจะเป็นหัวข้อสำคัญสำหรับทีมแพลตฟอร์มเอนจิเนียริงมาโดยตลอด