2 คะแนน โดย GN⁺ 2023-09-29 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • แม้ YAML จะถูกใช้ราวกับเป็นมาตรฐานในงานตั้งค่า DevOps และ CI แต่เพราะมี การแปลงชนิดข้อมูลโดยปริยาย และความต่างของ parser ทำให้แม้เป็นค่าตั้งค่าเดียวกันก็อาจถูกตีความไม่ตรงอย่างที่คาด
  • ใน YAML 1.1 ค่าอย่าง NO, 07, 08, 04:30, 0666 อาจถูกเปลี่ยนเป็น บูลีน·ตัวเลข·เวลา·เลขฐานแปด ได้ จึงต้องระบุเจตนาให้ชัดหากต้องการให้เป็นสตริง
  • ตัวอย่างจาก GitHub Actions, Kubernetes, CloudFormation และบริการ CI หลายเจ้า แสดงให้เห็นว่าไวยากรณ์ YAML และโครงสร้างเฉพาะของแต่ละบริการอาจนำไปสู่ การ commit ซ้ำๆ, การซ้อน escape หลายชั้น, และรูปแบบการเขียน job ที่กระจัดกระจายไม่เหมือนกัน
  • ลิงก์อ้างอิงที่แนบมารวมทั้งเรื่อง YAML ที่รันได้, ความต่างของพฤติกรรมระหว่าง parser, รูปแบบการเขียนสตริงหลายบรรทัด, ปัญหาที่เวอร์ชัน 1.70 ถูก parse เป็น 1.7, และเหตุผลเชิงออกแบบของ StrictYAML
  • แม้จะมีการเสนอทางเลือกอย่าง Nickel, Dhall, CUE, Jsonnet แต่ตัวหน้าเว็บเองก็ยังถูกทำให้ดูเหมือน ช่องข้อความขนาดยักษ์ที่แก้ไขได้ เพื่อสานต่อการเสียดสีเรื่อง usability ของ YAML แบบตรงๆ

บทเสียดสี YAML ในฐานะภาษาสำหรับตั้งค่า DevOps

  • แม้ YAML จะถูกใช้บ่อยในการตั้งค่า DevOps แต่หน้านี้สื่ออารมณ์ ความเหนื่อยล้ากับ YAML ผ่านประโยคทำนองว่า “ไม่มีใครอยากใช้ YAML หรอก”
  • มีการไล่เหตุผลที่ใช้ YAML ในงาน DevOps แบบประชดประชัน
    • เสียดสีว่ามันถูกคอมไพล์และพร้อม deploy อยู่ตลอดเวลา
    • ประชดเรื่องที่ระหว่างพัฒนาไม่มีการบังคับจัดการข้อผิดพลาด แต่ปัญหากลับไประเบิดตอนรันจริงใน production
    • พูดทำนองว่าข้อความ “มีบางอย่างพัง” ดีกว่า stack trace ที่มีเลขบรรทัด
    • สะท้อนความไม่พอใจว่าต้องเผาเวลาไปกับการสร้าง CI pipeline ใหม่
    • เสียดสีสถานการณ์ที่เพียงเพราะ Kubernetes ใช้ มันเลยถูกมองเป็นตัวเลือกที่ปลอดภัย
    • พร้อมเอ่ยถึงข้อดีว่าอย่างน้อยก็รองรับคอมเมนต์ ไม่เหมือน JSON

กับดักจากการแปลงชนิดข้อมูลโดยปริยาย

  • ใน YAML 1.1 ค่า NO อาจถูก parse เป็น ชนิดบูลีน
    • NO: Norway อาจก่อปัญหาจากการตีความเป็นบูลีน แทนที่จะเป็นรหัสประเทศ
    • ถ้าต้องการให้เป็นสตริง ควรใส่เครื่องหมายอัญประกาศเช่น "NO"
    • มีการชี้ว่าในสเปก YAML 1.1 มีวิธีเขียน true หรือ false ได้ถึง 22 แบบ
  • ค่าที่ดูเหมือนตัวเลขก็อาจถูก parser แต่ละตัวรับไปต่างกัน
    • ตัวอย่าง 07 และ 08 แสดงให้เห็นว่าผลลัพธ์อาจออกมาเป็น [ 7, "08" ]
    • มีการเสียดสีว่า Kubernetes cluster จะ deploy ผ่านถึงตัวที่เจ็ด แล้วไปพังที่ตัวที่แปด
  • สตริงที่ดูเหมือนเวลาก็อาจถูกแปลงอัตโนมัติด้วย
    • 04:30 อาจไม่ถูกมองเป็นเวลาที่ผู้ใช้พิมพ์ แต่กลายเป็นค่า 16200 ซึ่งคือจำนวนวินาทีหลังเที่ยงคืน
    • ถ้าต้องการให้เป็นสตริง ต้องระบุชัดเช่น !!str 04:30
  • ความต่างของการเขียนเลขฐานแปดใน YAML ก็ทำให้งงได้เช่นกัน
    • YAML 1.1 ใช้รูปแบบ 0666
    • YAML 1.2 ใช้รูปแบบ 0o666
    • และมีการพูดถึงการที่ Kubernetes ใช้ YAML 1.1 ราวกับเป็น “พิธีกรรมผ่านด่านของสาย DevOps”

ปัญหาเรื่องเวอร์ชัน, SHA, และการจัดการสตริง

  • เวอร์ชันของแพ็กเกจอาจถูก parse ราวกับเป็นเลขทศนิยม
    • foo: 1.7 และ bar: 1.70 อาจถูกตีความว่าเป็นเวอร์ชันเดียวกัน
    • ขณะที่ fizz: 1.7.0 และ buzz: 1.70.0 อาจยังถูกมองเป็นสตริงเวอร์ชันคนละค่า
  • Git SHA แบบสั้นที่ใช้ใน CI ก็อาจไม่ปลอดภัยเสมอไป
    • SHA แบบ 8 ตัวอักษรอาจเป็นตัวเลขล้วนทั้งหมดได้
    • my.flaky_version ที่ใส่ ${GIT_SHORT_SHA} โดยไม่ใส่อัญประกาศ อาจไม่ถูกมองว่าเป็นสตริง
    • บทความยกว่าค่านี้จะเป็นสตริงประมาณ 98% และถ้าใส่ครอบแบบ "${GIT_SHORT_SHA}" ก็จะเป็นสตริง 100%
  • มีกรณี Rust toolchain อยู่ในลิงก์อ้างอิงด้วย

ต้นทุนที่โผล่ออกมาในงานตั้งค่า CI และโครงสร้างพื้นฐาน

  • มีตัวอย่างว่าระหว่างเรียนรู้ GitHub Actions ผู้เขียน commit/push ไป 8 ครั้งในหนึ่งชั่วโมง และข้อความ commit สุดท้ายคือ “I don't really like yml”
  • ยังมีตัวอย่างให้เห็นด้วยว่าถ้าเขียน SQL เป็น YAML จะหน้าตาเป็นอย่างไร
    • โครงสร้าง SQL อย่าง SELECT, FROM, WHERE EXISTS, AND, EQUALS, LT ถูกเปลี่ยนให้กลายเป็นโครงสร้างซ้อนกันแบบ YAML
    • ใช้เพื่อเสียดสีว่าคำสั่ง SQL ที่สั้นกระชับ กลับกลายเป็น YAML ที่ยาวและเยิ่นเย้อ
  • วิธีเขียน job และ step ของแต่ละบริการ CI ก็ไม่เหมือนกันอีก
    • Azure DevOps ใช้รูปแบบ jobs ใต้ job, steps, script
    • CircleCI ใช้รูปแบบ jobs, job1, steps, checkout, run
    • ตัวอย่าง “ระบบ CI แห่งอนาคต” ก็ชี้ให้เห็นว่างานเดียวกันอาจถูกเขียนเป็นโครงสร้างซ้อนอีกแบบหนึ่งได้
  • ใน CloudFormation หากใส่ฟังก์ชัน SEARCH ไว้ใน DashboardBody ของ CloudWatch ก็มีตัวอย่างที่ต้อง escape ข้อความที่ escape มาแล้วอีกครั้ง และต้องครอบ JSON ทั้งก้อนด้วยเครื่องหมายอัญประกาศคู่

YAML ที่รันได้และความต่างของ parser

แหล่งข้อมูลที่เกี่ยวข้องและทางเลือกอื่น

ปฏิกิริยาต่อหน้าเว็บเอง

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

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

 
GN⁺ 2023-09-29
ความคิดเห็นจาก Hacker News
  • เรื่องปวดหัวที่ผมชอบที่สุดคืออันนี้:
    07
    08
    ผลลัพธ์กลายเป็น [ 7, "08" ]
    เพราะสมมติฐานเกี่ยวกับ เลขฐานแปด และสตริง
    สมมติฐานนี้ถูกพบใน YAML ที่ถูกสร้างจากเทมเพลตลงไปลึกสามชั้น และทำให้ คลัสเตอร์ k8s ทั้งหมดของเราใช้งานไม่ได้ แต่มีแค่คลัสเตอร์ 08 เท่านั้นที่พัง ส่วน 7 คลัสเตอร์ก่อนหน้านั้นยังทำงานได้ดี

    • ผมเป็นคนทำเว็บไซต์นี้ ถ้าส่งอันนี้มาเป็น pull request ได้ก็ดีมาก
    • บ้าเอ๊ย ผมเดาว่านักพัฒนาส่วนใหญ่สมัยนี้คงไม่รู้จักเลขฐานแปดหรือ ลิเทอรัลตัวเลขฐานแปด ที่ใช้คำนำหน้า 0 กันแล้ว
      อ่านคอมเมนต์นี้แล้วก็ขำอยู่ แต่พอคิดว่าในปี 2023 แทบไม่มีใครใช้เลขฐานแปดในไฟล์คอนฟิกแล้ว พฤติกรรมกับสมมติฐานแบบนี้ก็ไม่สมเหตุสมผลเลย ถ้าเป็นฐานสิบหกก็ยังพอว่า ฐานสิบยิ่งแน่นอนอยู่แล้ว แต่ฐานแปดนี่เกินไปหน่อย
    • ไม่เข้าใจเลยว่าสิ่งนี้จะถือว่าเป็นพฤติกรรมที่ถูกต้องได้อย่างไร
    • การที่คุณ “พบ” สมมติฐานนั้น หมายความว่าไม่ได้อ่านสเปก แต่เริ่มใช้งานไปโดยคิดว่ารู้พฤติกรรมแล้วใช่ไหม?
      ฝั่งที่สร้างมันขึ้นมาคงไม่ได้ serialize ข้อมูลด้วยไลบรารีแน่ ๆ เพราะถ้าใช้ไลบรารี มันก็คงแปลง type ให้เป็นรูปแบบที่ถูกต้องแล้ว
  • YAML มีปัญหาเยอะก็จริง แต่ผมคิดว่าปัญหาแกนหลักจริง ๆ คือการพยายามใส่ ลอจิกไว้ในคอนฟิก
    ถ้าใช้ YAML กับข้อมูลเท่านั้น ไม่ใช้กับลอจิก มันก็เป็นหนึ่งในรูปแบบข้อมูลที่คนอ่านและเขียนได้ดี
    CI/CD มักจะมีลอจิกอยู่บ้างเสมอ และแทบไม่มีกรณีไหนที่จบด้วย YAML ล้วน ๆ แถมยังมีเทมเพลตแปลก ๆ ปนเข้ามาอีก เลยคิดว่าน่าจะให้ API จริง ๆ สำหรับภาษาโปรแกรมจริงไปเลยดีกว่าไหม

    • นั่นไม่ใช่ปัญหาของ YAML แต่ใกล้เคียงกับ การใช้ YAML ผิดวิธี มากกว่า ความเป็น Turing complete โดยบังเอิญเป็นปัญหาได้ทุกที่
      ตอนใช้ Ant ที่อิง XML เมื่อ 15 ปีก่อนก็มีปัญหาแบบเดียวกัน และนั่นไม่ใช่ความผิดของ XML
      ผมมองว่าปัญหาหลักของ YAML คือ ขาดความปลอดภัยด้าน type เช่น การเยื้องผิด คีย์พิมพ์ผิด สตริงที่ถูก parse เป็น boolean
      นอกเหนือจากนั้น ผมคิดว่ามันเป็นรูปแบบที่ดี เพราะกระชับและมีสัญญาณรบกวนทางไวยากรณ์น้อยกว่ารูปแบบอื่นมาก ดังนั้นผมจึงสร้าง https://github.com/crdoconnor/strictyaml เพื่อให้ผู้คนใช้ YAML ที่ปลอดภัยด้าน type และได้รับข้อความ error ที่ชัดเจนทันทีสำหรับปัญหาแบบนี้
    • จากประสบการณ์ของผม ยิ่งภาษาทำอะไรได้มากเท่าไร คนก็ยิ่งใช้มันในแบบที่ซับซ้อนมากขึ้นเท่านั้น
      เพราะพวกเขาดึง abstraction เข้ามาโดยคิดว่าจำเป็น ดังนั้นผมจึงหลีกเลี่ยงการใช้ ภาษาโปรแกรมที่ Turing complete เป็นรูปแบบคอนฟิกเสมอ
      ผมเคยใช้เวลาหลายชั่วโมงไล่ AWS CDK ทีละบรรทัดด้วย JavaScript debugger ถ้ามันเป็นไฟล์ yaml/JSON/อะไรก็ได้ที่เรียบง่ายและโง่ ๆ ก็คงไม่มีปัญหาแบบนั้น มันเป็นโปรเจกต์เล็ก ๆ และไม่จำเป็นต้องมีความซับซ้อน
      ดังนั้นในคอนฟิกของเครื่องมือ JS ผมจึงชอบ JSON มากกว่า JS นี่ก็เป็นเหตุผลที่คอนฟิก webpack เละเทะ พอใช้ภาษาจริงได้ “เซนเซอร์ DRY” ของผู้คนก็ทำงาน แล้วทำให้มันซับซ้อนขึ้น
      ถ้าเป็นแบบ declarative ก็ทำตามแนวปฏิบัติมาตรฐานได้ง่าย และการรองรับจากเครื่องมือก็ดีกว่า ถ้า package.json กลายเป็นเหมือน build.gradle จริง ๆ ก็คงแย่กว่านี้มาก
    • คอนฟิกที่รันได้ ให้ประโยชน์มหาศาลได้ Python เป็นตัวเลือกที่ชัดเจน
      แค่กำหนดว่า “รันสคริปต์ใน Python interpreter ภายใต้ cgroup ที่จำกัดเข้มงวด แล้วผลลัพธ์ต้องเป็น dictionary ชื่อ CONFIG” จากนั้นลอจิก wrapper ก็ serialize มันในแบบที่สะดวกต่อโปรแกรมเป้าหมายที่จะถูกตั้งค่า
    • ไม่เข้าใจว่าทำไม การออกแบบสคีมาที่แย่ ถึงเป็นความผิดของ YAML ไม่ใช่ความผิดของผู้ออกแบบสคีมา
      คล้ายกับการบ่นเรื่องความซับซ้อนหรือความแข็งตัวของ helm Helm chart ไม่ได้เขียนตัวเองขึ้นมาเอง ผมว่าคงเพราะการบ่นแล้วเมินมันง่ายกว่าการทำความเข้าใจปัญหาและลงมือ implement
    • เห็นด้วย 100% เวลาคนบอกว่าเกลียด YAML หลายครั้งความหมายจริง ๆ ใกล้เคียงกับ “เกลียดการ อธิบาย pipeline ด้วย YAML” มากกว่า ผมก็เข้าใจความรู้สึกนั้น
      ในฐานะรูปแบบไฟล์ YAML มีทั้งข้อดีและข้อเสีย แต่ปัญหาจริง ๆ คือการพยายามแสดงสิ่งอย่างเงื่อนไข ลูป ฟังก์ชัน และคลาส/ซับคลาสผ่านเทมเพลต ด้วยรูปแบบไฟล์ที่เทียบเท่า JSON
      YAML ใช้ได้กับคอนฟิกเล็ก ๆ แต่ทันทีที่ต้องมี control flow ไม่ว่าชนิดใด มันจะโตเป็นสปาเกตตีเฉพาะ vendor อย่างรวดเร็ว
  • Jinja ใน YAML นั้นผมมองว่าเป็น anti-pattern อย่างชัดเจน
    คงเกิดจากตอนแรกไม่ได้ออกแบบให้มีความสามารถในการโปรแกรมมากพอ และภายหลังผู้คนก็ทำตามโปรเจกต์ที่เลือกทางนั้นแล้วประสบความสำเร็จ
    ในบทความมีทางเลือกอย่าง Dhall และ Jsonnet อยู่แล้ว แต่ยังมีอีกสองอย่างที่น่าคิด
    อย่างแรกคือทำไลบรารีตั้งค่าสำหรับภาษาโปรแกรมจริง ๆ แล้วให้ไลบรารีนี้สร้างไฟล์ตั้งค่า JSON ขึ้นมา JSON นั้นไม่ใช่สิ่งที่เอาไว้แก้ด้วยมือ แต่ถือเป็นผลลัพธ์ที่ตรวจสอบได้เท่านั้น ผู้ใช้จะนำการตั้งค่าในรูปแบบโค้ดที่มีเครื่องมือช่วยเหลือไปไว้ในระบบควบคุมเวอร์ชัน ข้อเสียและในเวลาเดียวกันก็เป็นข้อดีคือการแก้ด่วนบนเซิร์ฟเวอร์โดยตรงจะทำได้ยากขึ้น
    อย่างที่สองคือ Starlark เป็นภาษาที่แตกแขนงมาจาก Python แบบไม่ Turing-complete ซึ่งเดิมพัฒนาขึ้นสำหรับระบบบิลด์ Bazel มี implementation หลายตัว และผมไม่รู้ว่าความเข้ากันได้ลึกแค่ไหน แต่ก็มี Python binding ด้วย: https://github.com/caketop/python-starlark-go, https://github.com/inducer/starlark-pyo3

    • เห็นด้วยว่า Jinja ใน YAML เป็น anti-pattern แต่โดยเฉพาะเพราะอักขระเริ่มต้นของบล็อก/นิพจน์ {% และ {{ ต่างก็เป็นอักขระของ YAML ทำให้ต้องครอบทุกจุดที่ใช้ด้วยเครื่องหมายคำพูด
      ผมว่าแนวทางอย่าง ${{ ของ GitHub Actions หรือ <%, << ดีกว่ามาก แน่นอนว่า <<: เป็นไวยากรณ์ของ YAML จึงมีความเสี่ยงอยู่ แต่ไม่ใช่ Jinja ที่ถูกต้องตามไวยากรณ์
      ถ้าหมายความว่าไม่ควรใส่อะไรที่รันได้ลงใน YAML เลย ผมว่าเรือลำนั้นออกจากท่าไปแล้ว เพราะผู้คนค้นพบแล้วว่าวิธีปล่อยให้ส่วน literal เป็นค่าเริ่มต้น แล้วใส่ส่วนที่รันได้เป็นครั้งคราวนั้นเหมาะกับการสร้างคอนเทนต์ แบบเดียวกับ ASP/JSP/PHP
      ถ้าอยากเริ่มสงครามความเห็นย่อยในเธรดนี้ ก็พูดถึง HCL กับ for_each ได้ แต่คงดีกว่าถ้าอย่างน้อยก็ไม่ทำตรงนี้
    • นี่คือเส้นทางที่ Amazon เลือกใน CDK มันก็ใช้ได้ในระดับหนึ่ง แต่ถ้าจะทำอะไรที่ไม่ใช่เรื่องเล็กน้อย จะรู้สึกเหมือนกำลังสร้าง เครื่องจักร Rube Goldberg อย่างมาก
      ผมไม่รู้ว่าส่วนไหนเป็นความผิดของ CDK และส่วนไหนเป็นเพราะ CloudFormation เดิมทีก็ไม่ค่อยดีอยู่แล้ว
    • เห็นด้วย งานกับ YAML แบบทำเทมเพลตยุ่งยากเกินไป จนสุดท้ายผมสร้างเครื่องมือชื่อ Cels ขึ้นมาเพราะเรื่องนี้: https://github.com/pacha/cels
      ผมชอบ Jsonnet และ Starlark แต่ในทางปฏิบัติ use case ส่วนใหญ่ไม่ได้ต้องการภาษาโปรแกรมใหม่ ปกติเราแค่อยากสร้างเอกสารพื้นฐาน แล้วแก้ด้วยการ apply patch เท่านั้น แบบนั้นทุกอย่างจะง่ายลงมาก
      ประสบการณ์การใช้ YAML ล้วน ๆ เองก็ไม่ได้แย่นัก ถึงรูปแบบจะมีจุดที่น่าสงสัยอยู่หลายอย่าง แต่ก็ใช้ได้ ปัญหาอยู่ที่ความซับซ้อนของวิธีแก้ปัญหาที่ต้องเพิ่มเข้าไปเพื่อปรับเอกสารให้เข้ากับหลาย environment มากกว่า
    • แค่คิดว่าจะต้องกลับไปยุ่งกับ Ansible อีกเพราะเรื่องนี้ก็เป็นฝันร้ายแล้ว
      เคยได้ยินว่าเมื่อก่อนมี Python DSL จริง ๆ ที่ใช้แทน YAML ได้ แต่ดูเหมือนจะเลิกไปแล้ว ดังนั้นตอนนี้ loop กับ if-then จึงกลายเป็นก้อน YAML ยืดยาวน่าสยดสยอง และตีความ Jinja แบบคาดเดาไม่ได้โดยสิ้นเชิง
    • สงสัยว่ามีเครื่องมือแบบ standalone ที่รัน โค้ด Starlark เพื่อสร้าง JSON หรือ YAML ได้เหมือน jsonnet หรือเปล่า
  • ผมมองว่า YAML เองนั้นยอดเยี่ยม สิ่งที่ไม่ยอดเยี่ยมคือเราไปทำให้ ส่วนการ deploy ของ CD ยากเกินไป
    ผมยอมรับว่าการตั้งค่าของเราใน Azure DevOps ไม่ได้ดีเลิศอะไรนัก แต่ก็น่าประหลาดใจที่มีองค์กรซึ่งหลายทีม หรือผู้ดูแลระบบ 5–6 คน ต้องมาจัดการเครื่องมือแบบนี้ ถ้าเป็นที่อย่าง Google ก็ไม่รู้เหมือนกัน แต่สำหรับ enterprise ทั่วไปที่มีผู้ใช้พร้อมกันสูงสุด 50,000 คน หรือโดยมากน้อยกว่านั้นมาก ผมว่ามันเกินจำเป็น
    ช่วงต้นทศวรรษ 2000 การ deploy เว็บแอป enterprise ลงบน IIS แบบ on-premises ที่มีคนทำงานเต็มเวลาน้อยกว่า 0.25 คนจัดการสารพัดอย่าง ทั้ง load balancing, networking ฯลฯ ยังง่ายกว่าการ deploy สิ่งเดียวกันลงบนการตั้งค่า “สมัยใหม่” ในตอนนี้
    แน่นอนว่า pipeline สมัยใหม่ก็มีข้อดี มันช่วยข้ามปัญหา “บนเครื่องผมใช้ได้นะ” ไปได้มาก และยกระดับการควบคุมคุณภาพอย่างมากด้วย approval gate ที่ดีกว่าเดิม แต่การ deploy จริง ๆ แม้ในปี 2023 ก็ยังเป็นฝันร้าย
    เรื่องนี้อาจไม่ใช่ปัญหาสำหรับโปรแกรมเมอร์ใน HN ที่ทำงานในบริษัทเทคโนโลยีจริง ๆ หรือบริษัทที่มีทีม DevOps เฉพาะทางเก่ง ๆ แต่ในโลก enterprise ที่ไม่ใช่สายเทค CI/CD ไม่เคยแย่เท่านี้มาก่อนในอาชีพของผม
    จะโทษ YAML ก็ได้ หรือจะโทษว่าการทำอะไรสักอย่างต้องใช้ YAML มากเกินไปและ template ก็ยากก็ได้ แต่ในความเห็นผม ปัญหาเชิงองค์กร ใหญ่กว่าปัญหาทางเทคนิคมาก เครื่องมือ CD ควรอัตโนมัติกว่านี้มาก เพื่อไม่ให้กลายเป็นงานที่นักพัฒนาต้องอธิบาย infrastructure เป็น code
    การที่มันทำได้เป็นเรื่องดี แต่ความจริงคือเรากำลังขอให้นักพัฒนาหลายล้านคน deploy infrastructure ที่พวกเขาอาจแทบไม่เข้าใจ ผมไม่เคยเห็นนักพัฒนาคนไหนที่ไม่อยากแค่ส่ง container ไป แล้วหวังให้ networking กับ “งานฝั่ง server” ถูกจัดการให้เอง
    ถ้าไม่ทำแบบนั้น สุดท้ายก็จะมี VNET กับ subnet เต็มไปหมดที่ไม่มีใครเข้าใจดีว่ามันทำงานอย่างไร และองค์กรก็เสียเงินก้อนใหญ่เพราะนักพัฒนาไม่รู้ว่าสามารถทำด้วย /x ได้

    • Cloud คือ mainframe แบบใหม่
      เราเขียน “job definition” บางชนิดแบบ offline ส่งไปยังระบบ shared แบบ proprietary รออยู่ใน queue แล้วรับ log file ที่ระบบซึ่งเราไม่ได้ควบคุมสร้างขึ้นมา เราไม่สามารถรันโค้ดของระบบ proprietary บน workstation แบบ local ได้ ทำให้รอบการ iterate ภายในสั้นสุดก็หลายสิบนาที ยาวหน่อยก็หลายชั่วโมงหรือหลายวัน
      ไม่มีโหมด preview หรือ “what if” หรือ “dry run” แม้จะเรียกว่า “ทดสอบ” แต่เพราะมีระบบอยู่เพียงชุดเดียว จึงเท่ากับทำงานบน production ในทางปฏิบัติ
      ปัญหาจริง ๆ ไม่ใช่ YAML ต่อให้ pipeline ถูกสคริปต์ด้วยภาษาโปรแกรมมิ่งของพระเจ้าเองก็คงไม่ต่างกัน
      เหตุผลที่การพัฒนาซอฟต์แวร์บน workstation แทน mainframe แบบ time-sharing ศูนย์กลางได้รับความนิยมอย่างมาก ก็เพราะมันทำให้การ iterate ภายในเร็วขึ้นอย่างมหาศาล แยกขาดจาก production environment และคืนการควบคุมให้มือของนักพัฒนา
      CI/CD pipeline รุ่นปัจจุบันโดยมากย้อนสิ่งเหล่านั้นกลับไปหมด
      Kubernetes บนเครื่องเดียวช่วยนำข้อดีส่วนใหญ่ของการพัฒนาบน workstation กลับมาได้ แต่ยังเป็นระบบที่ใหม่มาก จึงมี growing pain เยอะ
      ปัญหาที่เกี่ยวข้องคือ สำหรับนักพัฒนาที่ดูแลแอปเดียวด้วยการคลิกเอง มีทางออกที่ยอดเยี่ยม และสำหรับบริษัทขนาดมหึมาที่ทำ automation ระดับใหญ่สำหรับนักพัฒนาหลายพันคน ก็มีทางออกที่ยอดเยี่ยมเช่นกัน แต่พื้นที่ตรงกลาง ที่นักพัฒนา enterprise ไม่กี่คนต้องจัดการแอปหลายสิบตัว นั่นแหละคือความโกลาหลล้วน ๆ
    • ผมไม่แน่ใจว่าเราข้ามปัญหา “บนเครื่องผมใช้ได้นะ” ไปได้หมดจริงหรือเปล่า
      มันเคยทำงานได้ดีหลายครั้งใน Docker image ของผม แต่พอเป็น image ที่ deploy แล้วกลับพังค่อนข้างบ่อย
      นี่เป็นปัญหาที่จะผ่านไปได้ก็ต่อเมื่อ build และ deployment pipeline ทั้งหมดโปร่งใสสมบูรณ์ มีสิทธิ์เข้าถึง image repository อย่างเต็มที่ และควบคุม build instructions ได้จริง ๆ เท่านั้น เรื่องนี้มีข้อจำกัดพอ ๆ กับการควบคุม operating system ในเครื่องตัวเอง และผมคิดว่ามันจะล้มเหลวเท่ากับจำนวนองค์กรที่โค้ดเคยพังเมื่อย้ายไปอีกเครื่องหนึ่ง
    • ผมไม่รู้ว่าการ deploy มีปัญหาอะไร สิ่งที่ผมตั้งค่าไว้ก็แค่ติด tag ให้ commit แล้ว push จากนั้น commit นั้นก็ถูก deploy
      การตั้งค่าให้เป็นแบบนั้นในระบบ CI/CD ไหน ๆ ก็ดูค่อนข้างตรงไปตรงมา
  • ผมคิดว่ามีทางออกที่จะรักษาสันติภาพได้ ถ้าทุกคนเคารพกฎเดียวกันอย่างสากล: อย่าใช้ YAML นอกระบบนิเวศของ Python
    แบบนั้นคนที่ชอบรูปแบบสคริปต์ลึกลับซึ่งให้ความสำคัญกับความอ่านง่ายเหนือความถูกต้อง ความทนทาน และความดูแลรักษาได้ ก็ยังใช้แท็บ ไทป์แบบหลวม ๆ และไวยากรณ์ชวนงงต่อไปได้ ส่วนคนอื่น ๆ ก็ไม่จำเป็นต้องทำอย่างนั้น คนที่ชอบไวยากรณ์สไตล์ C จะยังรักษาสติไว้ได้
    รู้สึกเหมือนเพิ่งชี้เข้าประเด็นหลักของปัญหาได้แล้ว สำหรับผมที่เป็นนักพัฒนาไวยากรณ์ C แล้ว ช่องว่างที่มีความหมายทางไวยากรณ์ คือความบ้าคลั่งล้วน ๆ ช่องว่างคือการจัดรูปแบบ ไม่ใช่ข้อมูลหรือคำสั่ง การจัดรูปแบบที่ดีช่วยได้และมีประโยชน์ และนักพัฒนาไวยากรณ์ C ที่ดีก็ใส่ใจกับการจัดรูปแบบให้อ่านง่ายเช่นกัน
    ใน Python และ YAML การจัดรูปแบบคือข้อมูลคำสั่ง ข้อดีคือโค้ดทุกชิ้นที่ทำงานได้จะอ่านง่ายขึ้น แต่ทำไมโค้ดถึงต้องอ่านง่ายเสมอจึงจะทำงานได้?
    ลองจินตนาการว่าทำงานกับเพื่อนร่วมงานแบบ YAML ดู คุณส่งข้อความยาว ๆ ไป แล้วเขาตอบว่า “อะไรนะ? อันนี้ไม่สมเหตุสมผลเลย” ปรากฏว่าสาเหตุคือคุณไม่ได้ใส่บรรทัดว่างระหว่างย่อหน้า ความหมายเลยพัง พอใส่บรรทัดว่างกลับเข้าไปแล้วส่งอีกครั้ง เขาถึงอ่านได้ นั่นหมายความว่าข้อมูลที่ส่งไปไม่มีความหมายถ้าไม่มีการจัดรูปแบบที่ถูกต้องตามไวยากรณ์

    • ในฐานะซอฟต์แวร์ เป้าหมายอีกอย่างของโค้ด นอกเหนือจากการรันได้ คือ การอ่านได้
      วิธีจัดรูปแบบมีมากมายเหลือเกิน และผมชอบให้คนใช้ linter เวลาเขียนโค้ด ถ้าเป็นไปได้ก็อยากให้เป็น linter เดียวกับที่ผมใช้
      ภาษาเหล่านั้นบังคับโครงสร้างไวยากรณ์มาตรฐาน ซึ่งเป็นเรื่องดีเพราะลดวิธีเขียนโค้ดที่อ่านยากลง
    • โดยทั่วไป ช่องว่างที่มีความหมาย มักถูกมองว่าเป็นประเด็นเชิงปรัชญาหรือศาสนา บางคนชอบ บางคนไม่ชอบ และทั้งสองฝ่ายก็หาเหตุผลมารองรับความชอบของตัวเอง แต่ท้ายที่สุดก็เป็นเรื่องรสนิยมที่แรงกล้า
      แต่ตอนนี้ผมเริ่มคิดว่าความแตกต่างนั้นไม่ใช่เรื่องปรัชญา แต่เป็นเรื่องเครื่องมือ เครื่องมือบางอย่าง เช่น text editor หรือโปรแกรมอีเมล รองรับช่องว่างที่มีความหมายได้ดี แต่บางอย่างก็ไม่
      text editor ที่ผมใช้ทั้งหมดตั้งค่าให้แสดงช่องว่างและแท็บ และแสดงทั้งสองอย่างต่างกัน ปกติเป็นจุดจาง ๆ กับขีดจาง ๆ ทำนองนั้น ผมชินแล้วจึงไม่รู้สึกรำคาญเลย
      จากมุมมองของผม โค้ดไม่ใช่ข้อความตามอำเภอใจ เราใช้ฟอนต์ monospace ที่คงไม่ใช้ในหนังสือ และใช้สีแยกไวยากรณ์ จึงไม่มีเหตุผลที่จะไม่ทำให้ช่องว่างมองเห็นได้
      ถึงอย่างนั้นผมก็ยังชอบภาษาที่ไม่มีช่องว่างที่มีความหมายมากกว่า แต่ก็ไม่ได้เกลียดภาษาพวกนั้น สำหรับผมมันไม่ใช่ปัญหาเลย
      แต่ถ้าเครื่องมือที่คุณชอบไม่รองรับช่องว่างที่มีความหมายได้ดี ไม่ทำให้ช่องว่างมองเห็นได้ หรือถึงขั้นเขียนโค้ดด้วยฟอนต์ proportional คุณก็ย่อมเกลียดช่องว่างที่มีความหมายอย่างแรง และมองว่ามันเป็นความบ้าคลั่งล้วน ๆ
    • ผมเองก็มาจากพื้นฐาน C จึงเคยคิดเหมือนกันว่าช่องว่างไม่ใช่ข้อมูลหรือคำสั่ง ช่วงแรก ๆ ของ Python ผมถึงกับดูแคลนมันเล็กน้อยเพราะเรื่องนี้
      จุดที่ทำให้เปลี่ยนความคิดกลับเป็นตอนใช้ CoffeeScript อย่างไม่คาดคิด ผมไม่ค่อยชอบ JavaScript แต่ความรู้สึกเวลาใช้ CoffeeScript เหมือนเป็นการกลั่น The Good Parts ของ Crockford ออกมา ไม่สามารถเผลอสร้างส่วนแย่ ๆ ขึ้นมาได้
      แถมวิธีที่ indentation กลายเป็นโค้ดก็ค่อนข้างสบาย ข้อไม่สะดวกเพียงอย่างเดียวคือใน Vi ไม่สามารถกด % ที่วงเล็บปีกกาเปิดหรือปิดเพื่อหาอีกปลายของบล็อกได้ ในทางกลับกัน เพราะ indentation ถ้าโค้ดดูแปลก มันก็มักจะแปลกจริง ๆ
      อย่างไรก็ดี ผมยังไม่ได้เรียน Python มากนัก ทุกวันนี้ใช้ TypeScript แต่ถ้าวันหนึ่งมี CoffeeTypeScript ออกมาละก็…
    • แปลกนิดหน่อยที่ TOML อยู่ใน standard library แต่ YAML ไม่มี และ TOML หน้าตาไม่สวย
    • ชุมชน Kubernetes กำลังมองมาด้วยสายตาน่าสนใจ
  • ผมเลยเริ่มสร้างรูปแบบชื่อ BCL เอง: https://github.com/wkhere/bcl
    มันคงไม่ได้ช่วยทุก use case ของ YAML ได้ทันที แต่อย่างน้อยก็อาจเป็นวิธีที่เท่กว่าสำหรับกำหนด resource ในสไตล์คล้าย Terraform จริง ๆ แล้วมันช่วยเป็นตัวแทน HCL ในโปรเจกต์ภายในโปรเจกต์หนึ่งอยู่แล้ว และนั่นก็เป็นแรงผลักสุดท้ายที่ทำให้สร้างมันขึ้นมา
    ถ้ามองภาพใหญ่ขึ้น ผมไม่รู้ว่าจะช่วยปัญหาที่ YAML มีอยู่ทุกหนทุกแห่งใน Kubernetes ได้อย่างไร ปัญหา $daily_job ของผมมากกว่าครึ่งอยู่ที่การรวม Helm chart สุดท้ายจากหลายแหล่งที่มานั้นหยาบเกินไป
    ไม่ได้หมายความว่า Helm เป็นเครื่องมือที่แย่โดยเนื้อแท้ หรือบริษัทเราเลือกใช้ Helm ในวิธีที่ค่อนข้างแย่ ผมคิดว่าทุกคนกำลังทำดีที่สุดตามสถานการณ์
    แต่การจัดการ text template ที่มี ช่องว่างที่มีความหมาย นั้นผิดพลาดง่ายเกินไป และกว่าจะพบข้อผิดพลาดก็สายเกินไป ผมคิดว่า Kubernetes น่าจะดีกว่านี้มากถ้าใช้รูปแบบเฉพาะที่อิงไวยากรณ์สไตล์ C แทนที่จะพยายามพิสูจน์ว่า YAML ยอดเยี่ยมแค่ไหน โดยเฉพาะอย่างยิ่ง YAML ก็ไม่ได้ยอดเยี่ยมด้วยซ้ำ

    • YAML มีฟีเจอร์ดี ๆ อยู่สองอย่าง คือ สตริงหลายบรรทัด และการที่ YAML เป็น superset ของ JSON
      อะไรก็ตามที่สร้าง JSON ได้ก็ใช้สร้าง YAML ได้
      Nickel สามารถประเมินค่าออกมาเป็น JSON ได้: https://nickel-lang.org/
    • งานนำเสนอ Nixcon นี้น่าประทับใจ
      https://youtu.be/SEA1Qm8K4gY?feature=shared
    • สงสัยว่าเคยดู ucl หรือยัง: https://github.com/vstakhov/libucl
      ดูค่อนข้างคล้ายกัน
  • นี่คือ ผลของแพลตฟอร์มภายใน เมื่อแอปพลิเคชันใหญ่ขึ้น การตั้งค่าก็ขยายตาม จนสุดท้ายกลายเป็นภาษาโปรแกรมมิง แต่เป็นภาษาที่มีบั๊กเยอะ สเปกไม่พอ และใช้งานแย่มาก
    ก็ประกาศล้มละลายด้านการตั้งค่า แล้วเลือกรูปแบบการตั้งค่าใหม่ จากนั้นก็วนซ้ำ
    แน่นอนว่ารูปแบบเองก็ใช่ว่าจะไม่ต้องรับผิดชอบ ยิ่งยืดหยุ่นเท่าไรก็ยิ่งถูกนำไปใช้ซ้ำเป็นภาษาโปรแกรมมิงแย่ ๆ ได้ง่ายเท่านั้น
    หลังจากทำพลาดแบบนี้ซ้ำแล้วซ้ำเล่า ทุกวันนี้สำหรับการตั้งค่าพื้นฐาน ผมจะเลือกรูปแบบการตั้งค่าที่เรียบง่ายที่สุดเท่าที่เป็นไปได้ แม้แต่ .ini ก็อาจทรงพลังเกินไป ส่วน “การตั้งค่า” ที่ซับซ้อนกว่านั้นจะมอบให้ภาษาโปรแกรมมิงจริง ๆ จัดการ ถ้าเป็นไปได้ก็เป็นภาษาที่ใช้เขียนแอปพลิเคชันนั้น

  • ตัวอย่างส่วนใหญ่แบบท่วมท้นของ “YAML แย่” แก้ได้ด้วยการ ใส่เครื่องหมายคำพูดครอบ literal แปลก ๆ ทั้งหมด
    จริงอยู่ที่ YAML บางทีก็น่ารำคาญ เช่น ลิสต์ของแมปจะเริ่มดูแปลกได้อย่างรวดเร็ว และช่องว่างที่มีความหมายแทบจะต้องมาทำให้สะดุดเข้าสักวันแน่ ๆ แต่บทความพวกนี้ ต่อให้มองในแง่ดี ก็รู้สึกว่าไม่ค่อยซื่อตรงนัก

    • แต่ในตัวอย่างเหล่านั้นไม่มีกรณีไหนใช้เครื่องหมายคำพูดเลย และเครื่องมือก็ไม่ได้ทำแบบนั้นให้
      ทั้งระบบนิเวศของ YAML ชักจูงให้เขียนค่าโดยไม่ใส่เครื่องหมายคำพูด ส่วนใหญ่ก็ทำงานได้ดี จนมีบางครั้งเท่านั้นที่พังพอให้สะดุดในโปรดักชัน
  • EDN เป็นซับเซตของ Clojure: https://github.com/edn-format/edn
    ชัดเจน สตรีมได้ ขยายได้ และไม่อ่อนไหวต่อช่องว่าง แต่ก็มีแบบแผนการจัดรูปแบบเพื่อให้อ่านง่ายอยู่

    • เพิ่งเคยเห็นรูปแบบข้อมูลที่แยกลิสต์กับเซตอย่างชัดเจน และนั่นก็ดี
      แต่ไม่ค่อยเข้าใจว่าความแตกต่างเชิงความหมายระหว่างลิสต์กับเวกเตอร์คืออะไร ในหัวผม อาร์เรย์กับ linked list เป็นรายละเอียดการติดตั้งของโครงสร้างข้อมูลในโค้ด ไม่ใช่ความแตกต่างของรูปแบบข้อมูล
    • ดีกว่าทางเลือกอื่นมาก ๆ หวังจริง ๆ ว่าจะเริ่มมีการใช้นอกระบบนิเวศ Clojure ด้วย
    • ถ้าพูดให้เป๊ะ จะบอกว่าไม่พึ่งพาช่องว่างก็คงยาก เพราะต้องใช้ช่องว่างเพื่อบอกขอบเขตหรือแยกองค์ประกอบ
      แต่ก็ไม่มี ลูกเล่นการเยื้องบรรทัดเชิงความหมาย เลย การที่คอมมาถูกถือเป็นช่องว่างและไม่จำเป็นต้องมีก็นับว่างดงาม
  • เมื่อนักศึกษาส่งงานผ่านแพลตฟอร์ม e-learning เราจะได้รับงานส่งทั้งหมดเป็นไฟล์ XML ขนาดค่อนข้างใหญ่
    เราอ่านงานส่ง ส่งต่อไปให้ static analysis และการรันตัวอย่าง แล้วเขียนไฟล์ YAML สำหรับแต่ละงาน ซึ่งมีงานส่งทั้งหมด คำใบ้สำหรับการให้คะแนน คอมเมนต์และช่องกรอกคะแนน ฯลฯ
    จากนั้นสร้างรายงาน สถิติ และ PDF ฟีดแบ็กจากไฟล์ YAML ผ่าน markdown+การเรนเดอร์ (Pandoc)
    สำหรับเรา YAML เหมาะมาก เพราะเพิ่มฟีดแบ็กเพิ่มเติมด้วยไวยากรณ์ Markdown ได้ง่าย เช่น - you missed a \NOT` here` ที่เยื้องถูกต้อง
    ด้วยวิธี escape ข้อความแบบบล็อกที่มีหลายแบบ แม้นักศึกษาจะใช้ delimiter ของ SQL หลากหลาย เราก็สามารถแสดงงานส่ง SQL ออกมาให้ดูดีได้โดยไม่ต้องใช้อักขระ escape
    ทั้งหมดเป็น plain text จึงใช้แค่ text editor และเก็บไว้ใน git เพื่อให้มีความรับผิดชอบในการให้คะแนน เพราะเก็บทุกอย่างไว้ในรูปที่เครื่องอ่านได้ จึงยังทดสอบเครื่องมือ static analysis ใหม่ ๆ กับงานส่งในอดีตได้ด้วย
    แต่พอต้องเขียน CI pipeline กับการตั้งค่า home automation ด้วย YAML เช่นกัน ก็เข้าใจความเจ็บปวดนั้น

    • การ ตัดการเยื้องบรรทัด ของข้อความที่ฝังอยู่ อาจเป็นฟีเจอร์ที่ดีที่สุดของ YAML
      ใน TOML ต้องยอมแพ้เรื่องการเยื้องสตริงหลายบรรทัดจนทำให้อ่านยากลง หรือไม่ก็ต้องใส่แบ็กสแลชท้ายทุกบรรทัด ซึ่งไม่มีทางไหนเหมาะเลย
      ดังนั้นสำหรับ DSL หรือการตั้งค่าที่ต้องใส่ Markdown หรือรูปแบบข้อความอื่น ๆ เข้าไป YAML จึงค่อนข้างดี และได้เปรียบกว่าอย่าง TOML
      แต่ผมคงไม่โยนความผิดทั้งหมดของ “ความเหนื่อยล้าจาก YAML” ให้เฉพาะเครื่องมือ CI และ DevOps ที่เลือก YAML เป็นรูปแบบพาหะสำหรับ DSL เท่านั้น อย่างที่บทความต้นฉบับสรุปไว้ดีแล้ว ตัว YAML เองก็มีปัญหาใหญ่เช่นกัน
      “ปัญหา Norway” อันโด่งดังถูกแก้ใน YAML 1.2 แล้ว และปัญหาการ parse เลขที่มี 0 นำหน้าเป็นฐานแปดก็ถูกแก้ใน YAML 1.2 แล้วเช่นกัน การบังคับแปลงชนิดข้อมูลมากเกินไปสำหรับตัวเลข วันที่ เวลา ฯลฯ อาจทำให้สับสนได้ โหมดการจัดการสตริงหลายบรรทัดก็อาจค่อนข้างชวนงงเช่นกัน การ serialize ที่ไม่ปลอดภัยไม่ใช่ปัญหาใน parser สมัยใหม่ แต่เมื่อต้องใช้ YAML ในภาษาเก่าที่มีฟีเจอร์ไดนามิกอย่าง Ruby, Python, Java ก็ควรระวัง
      ทั้งหมดนี้เป็นปัญหาของสเปก YAML เอง