1 คะแนน โดย GN⁺ 2024-02-26 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • สำหรับโปรเจกต์โอเพนซอร์สขนาด 10k~200k บรรทัด การมี เอกสาร ARCHITECTURE ไว้ข้าง ๆ README และ CONTRIBUTING จะช่วยลดต้นทุนที่ผู้ร่วมพัฒนาหน้าใหม่ต้องใช้ในการทำความเข้าใจโครงสร้างโค้ดได้
  • ในโปรเจกต์ที่ไม่คุ้นเคย ปัญหาใหญ่กว่าไม่ใช่การเขียนแพตช์ช้าลงประมาณ 2 เท่า แต่เป็นการใช้เวลามากขึ้น 10 เท่าเพื่อหาให้เจอว่า ควรแก้ตรงไหน
  • เอกสารนี้ควรสรุปโครงสร้างระดับสูงและเนื้อหาที่ไม่ค่อยเปลี่ยนให้กระชับ และเหมาะกับแนวทางตรวจทาน ปีละไม่กี่ครั้ง มากกว่าการพยายามซิงก์กับโค้ดอยู่ตลอด
  • องค์ประกอบหลักคือภาพรวมของปัญหาและ codemap โดยควรแสดงโมดูลขนาดใหญ่และความสัมพันธ์ เพื่อให้ตอบได้ว่า “โค้ดที่รับผิดชอบ X อยู่ที่ไหน”
  • ควรบันทึกชื่อสำคัญ, architectural invariants, ขอบเขตระหว่างเลเยอร์และระบบ, รวมถึง cross-cutting concerns และหากชี้นำให้ ค้นหาด้วยชื่อ แทนการใส่ลิงก์โดยตรง จะช่วยลดภาระการบำรุงรักษา

ต้นทุนที่เอกสาร ARCHITECTURE ช่วยลด

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

ควรใส่อะไรบ้าง

  • เริ่มจากสรุปปัญหาที่โปรเจกต์แก้ไขในระดับ ภาพรวมจากมุมสูง
  • จากนั้นเขียน codemap ที่ละเอียดพอสมควร
    • อธิบายโมดูลระดับใหญ่และความสัมพันธ์ระหว่างกัน
    • ต้องตอบได้ว่า “สิ่งที่ทำ X อยู่ตรงไหน”
    • และต้องตอบได้ด้วยว่า “สิ่งที่ฉันกำลังดูอยู่นี้ทำอะไร”
  • ไม่ลงลึกถึงการทำงานภายในของแต่ละโมดูล
    • เนื้อหาแบบนั้นควรย้ายไปอยู่ในเอกสารแยก หรือดีกว่านั้นคือเอกสารแบบ inline
    • codemap คือแผนที่ประเทศ ไม่ใช่สมุดแผนที่รายรัฐ
  • ระหว่างเขียน codemap สามารถตรวจสอบโครงสร้างโปรเจกต์ไปพร้อมกันได้
    • ตรวจได้ว่าสิ่งที่อยากวางไว้ใกล้กันใน codemap นั้นอยู่ติดกันในผลลัพธ์จากการรัน tree . ด้วยหรือไม่
  • ควรระบุชื่อไฟล์ โมดูล และ type ที่สำคัญให้ชัดเจน
    • ควรหลีกเลี่ยงลิงก์โดยตรง เพราะอาจเสียได้เมื่อเวลาผ่านไป
    • ให้ชี้นำให้ค้นหา symbol ด้วยชื่อแทน จะช่วยให้พบรายการชื่อคล้าย ๆ ที่เกี่ยวข้องได้ด้วย โดยไม่เพิ่มภาระบำรุงรักษา
  • ต้องเขียน architectural invariants ให้ชัดเจน
    • invariant สำคัญมักปรากฏในรูปแบบว่า “ไม่มี” อะไรบางอย่าง
    • ตัวอย่างเช่น ในการพัฒนาเว็บ ข้อเท็จจริงที่ว่าเลเยอร์ model ไม่พึ่งพา view อาจเป็นสิ่งที่รู้ได้ยากจากการอ่านโค้ดอย่างเดียว
  • ต้องแสดง ขอบเขต ระหว่างเลเยอร์และระบบด้วย
    • ขอบเขตบอกใบ้ข้อมูลเกี่ยวกับ implementation ของระบบที่อยู่เบื้องหลัง
    • และจำกัด implementation ที่เป็นไปได้ทั้งหมด
    • ขอบเขตที่ดีมักหาแบบสุ่มในโค้ดได้ยาก การทำเป็นเอกสารจึงมีประโยชน์
  • หลัง codemap ให้เพิ่มส่วนแยกสำหรับ cross-cutting concerns
  • ตัวอย่างที่น่าอ้างอิงดูได้จาก architecture.md ของ rust-analyzer

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

 
GN⁺ 2024-02-26
ความคิดเห็นบน Hacker News
  • ผมชอบไอเดียนี้ และคิดว่าไม่ว่าขนาดของ repository จะเป็นอย่างไร คำอธิบายสถาปัตยกรรม ก็ควรมีที่อยู่ใน README ด้วย
    ตัวอย่างเช่น ผมคิดว่าสิ่งสำคัญคือผู้อ่านทุกคนต้องเห็นและเข้าใจ workflow เลยตั้งใจใส่ Mermaid sequence diagram[1] ไว้ใน README หลัก[2]
    [1] https://mermaid.js.org/syntax/sequenceDiagram.html
    [2] https://github.com/hbcondo/revenut-app?tab=readme-ov-file#-w...

    • ถ้ามีเครื่องมือที่สร้าง Mermaid diagram จากภาษาธรรมชาติ ได้ก็น่าจะเจ๋งทีเดียว เป็นเรื่องที่น่าลองคิดดู
  • ฟังดูเป็นคำแนะนำที่ดีมาก
    อยากให้เครื่องมือสำหรับ แสดงภาพสถาปัตยกรรม ของระบบที่กำลังรันอยู่ดีขึ้นกว่านี้ ยังรู้สึกแปลกที่วิธีที่ทันสมัยที่สุดยังเป็นการอ่านโค้ดหรือดูไฟล์ Markdown ถ้าโชคดีก็อาจมี Mermaid diagram สักอัน
    อยากให้สถาปัตยกรรมเผยตัวเองแบบเรียลไทม์ได้เอง อยากให้ observability ในระดับมหภาคถูกฝังมาเป็นค่าเริ่มต้น และคิดว่าน่าจะช่วยให้ทุกคนเข้าใจคอมพิวติ้งได้ดีขึ้น รวมถึงช่วยมนุษยชาติในการเสริมศักยภาพตัวเองด้วย

    • ถ้าเอาการแสดงภาพอย่าง dep-tree มาเพิ่ม การค้นหาด้วยคีย์เวิร์ด หรือการค้นหาเวกเตอร์ด้วย LLM ก็น่าจะดี คือพอ query แล้วไฟล์และคลัสเตอร์ที่เกี่ยวข้องถูกไฮไลต์ขึ้นมา
  • สำหรับโปรเจกต์โอเพนซอร์สที่มีผู้ร่วมสมทบชั่วคราวจำนวนมาก ดูเป็น โมเดลที่ต้องบำรุงรักษาน้อย ที่ดี ถ้าเป็นโปรเจกต์ที่มีวิศวกรประจำ ADR ก็น่าพิจารณาเช่นกัน
    ADR ต้องดูแลมากกว่า แต่เพราะมันบันทึกไว้ว่า “ทำไมถึงทำแบบนั้น” และ “เคยพิจารณาทางเลือกอะไรบ้าง” จึงมีประโยชน์มากเวลาออกแบบใหม่
    อ้างอิง: https://adr.github.io/

    • ในที่นี้ผมว่าคำว่า “ใช้ร่วมกัน” น่าจะเหมาะกว่า “ใช้แทน”
      ARCHITECTURE.md บันทึกสถานะสถาปัตยกรรมปัจจุบัน ส่วน ADR คือบันทึกการตัดสินใจที่ทำให้มาถึงจุดนั้น ทั้งสองอย่างมีประโยชน์มาก
    • ที่บริษัทผมก็มีเอกสารไร้ประโยชน์ที่พวก architect เขียนไว้ ส่วนใหญ่ก็ประมาณนี้
      Microservices, Kafka, Kubernetes: เพราะตอนนี้ผู้ใช้มี 4,000 คน แต่ถ้าวันหนึ่งกลายเป็น 1 พันล้านคนจะทำอย่างไร
      GraphDB: เพราะถ้า SQL ไม่พอจะทำอย่างไร
      ElasticSearch: เพราะถ้าต้องทำ full-text search พร้อมกับสถิติด้วยจะทำอย่างไร
      แต่เอกสารพวกนี้ส่วนใหญ่สุดท้ายแล้วก็เป็นคำย่อของ “อยากลองสถาปัตยกรรม/เทคโนโลยีใหม่เพราะมันสนุก เพื่อนร่วมงานที่อยู่ FAANG ใช้กัน อ่านหนังสือเล่มนั้นมา ดูดีในเรซูเม่”
      พอพวกเขาย้ายไปออกแบบโปรเจกต์ใหญ่ถัดไป ทีมเราก็ต้องคอยซิงก์บริการที่มีจำนวนมากกว่าสมาชิกทีม รวมถึง DB และเทคโนโลยีข้างต้นต่อไป แน่นอนว่าปัญหาแบบนี้ถูกมองว่าเรียบง่ายกว่าการตัดสินใจ “สถาปัตยกรรมครั้งใหญ่” มาก
  • อยู่ ๆ ก็นึกขึ้นได้ว่า IDE ทุกตัวที่เคยใช้จะแสดง โครงสร้างโฟลเดอร์ ของโปรเจกต์เป็น directory tree มาตรฐานทางซ้าย มี IDE ที่ให้สำรวจโปรเจกต์เป็น dependency graph ไหม?

    • ไม่ใช่คำตอบตรง ๆ สำหรับคำถาม แต่เหมือนสุดท้ายแล้วหมายถึง “อยากแสดงภาพโครงสร้างไฟล์ให้ดีกว่านี้”
      ผมว่า representation แบบสารบัญไม่ค่อยเหมาะ ใน workflow การเขียนโค้ดช่วงนี้ ผมเปิด terminal แล้วรัน ranger ในนั้น จากนั้นเวลาอยากสำรวจโครงสร้างไดเรกทอรีซ้ายขวาก็สลับแท็บไปที่ terminal นั้น เปิด VSCode แล้วใน split terminal ให้ด้านบนเป็น terminal ปกติ ด้านล่างรัน Ranger ก็ได้ Midnight Commander ก็ใช้ได้ และจริง ๆ แล้ว TUI file explorer อะไรก็ได้
      อีกอย่าง ผมเริ่มใส่ code map ไว้ในไฟล์ architecture.md ของโปรเจกต์ด้วย รัน tree -L ก็จะได้แผนผัง tree ของโครงสร้างไฟล์ที่เหมาะจะใส่ใน Markdown ตามความลึกที่ต้องการ เพิ่ม output นั้นลงใน Markdown แล้วใส่คอมเมนต์อธิบายวัตถุประสงค์ของแต่ละไฟล์/โฟลเดอร์ไม่เกิน 10 คำต่อท้าย
      Ranger - https://github.com/ranger/ranger
      Midnight Commander - https://midnight-commander.org/
    • ผมก็คิดแบบเดียวกันเป๊ะ
      มีไอเดียสองแบบว่ามันอาจหน้าตาเป็นอย่างไร
      อย่างแรกคือ directory tree หลายชุด ที่จัดระเบียบไฟล์แบบ orthogonal โดยใช้ symbolic link โครงสร้างไดเรกทอรีทั่วไปอาจแบ่งเป็น client/server แต่ถ้าอยากแบ่งตามฟีเจอร์ล่ะ? IDE น่าจะช่วยสร้างให้ได้ง่ายกว่ามาก
      อย่างที่สอง ตามทิศทางของบทความนี้ อยากให้ IDE สร้าง bookmark และช่วยให้สลับไปมาระหว่าง bookmark เพื่ออธิบายโค้ดให้คนอื่นเข้าใจง่ายขึ้น บางครั้งอยากทิ้งคอมเมนต์ไว้ แล้วคลิกเพื่อกระโดดไปยังตำแหน่งอื่นใน codebase ได้ ถ้าเชื่อมสิ่งเหล่านี้เข้าด้วยกัน ก็จะร้อยเรียงเป็น narrative ที่อธิบายการทำงานทั่วทั้ง codebase ได้
      สงสัยว่ามีใครกำลังทำงานแนวนี้อยู่ไหม
    • ในทางปฏิบัติแล้วมันจะหน้าตาเป็นอย่างไร? เช่น circular dependency จะจัดการอย่างไรได้บ้าง?
    • บางทีสิ่งที่ต้องการอาจเป็น multitree ก็ได้
  • ผมคิดว่าควรระวังไม่ขยายสิ่งที่ผู้เขียนพูดในที่นี้ไปใช้กับโปรเจกต์ซอฟต์แวร์ทั่วไปมากเกินไป
    สำหรับโปรเจกต์โอเพนซอร์สขนาดใหญ่ที่มีผู้ร่วมสมทบจำนวนมากและมีบริบทไม่เพียงพอ เอกสารแบบนี้มีคุณค่าต่อการดูแลรักษามาก แต่ในโปรเจกต์งานเล็ก ๆ ผมเห็นว่าเอกสารที่นักพัฒนา commit ไว้ สุดท้ายมักกลายเป็นสิ่งที่ไม่มีใครดูแลทั้งหมด

    • ผมเคยทำ architecture session กับทีมหลายครั้ง และมันมีคุณค่าเสมอ
      อย่างน้อยก็ทำให้รู้ว่าสมาชิกทีมมีความคิดเกี่ยวกับสถาปัตยกรรมปัจจุบันและสถาปัตยกรรมในอุดมคติแตกต่างกันมาก การทำให้เรื่องนั้นปรากฏออกมาอย่างชัดเจนเพียงอย่างเดียวก็คุ้มค่าที่จะทำเอกสารแล้ว
      และคำว่า “เอกสารจะไม่ถูกดูแล” เป็นเหตุผลที่อ่อนมากสำหรับการไม่ทำเอกสาร เพราะไม่ว่าเอกสารแบบไหน—even ถ้าเก่าไปแล้วหรือผิดเล็กน้อย—ก็ยังดีกว่า “ไม่มีเอกสาร”
  • เมื่อหลายปีก่อน เคยทดลองวิธีคล้าย ๆ กันในหนึ่งใน side project ขนาดใหญ่
    https://github.com/shipmight/shipmight/blob/master/src/ARCHI...
    ที่ด้านบนของแต่ละไฟล์ ผมใส่ tree ของลิงก์ไปยังไฟล์ ARCHITECTURE.md อื่น ๆ ใน repository ไว้ ตัวอย่างเช่น: ARCHITECTURE.md <- ตำแหน่งปัจจุบัน, backend/ARCHITECTURE.md, backend/api/ARCHITECTURE.md, backend/cli/ARCHITECTURE.md, backend/ui/ARCHITECTURE.md, backend/utils/ARCHITECTURE.md, frontend/ARCHITECTURE.md, internal-charts/ARCHITECTURE.md

    • ถ้าใส่ README.md ไว้ในแต่ละ package/module/top-level directory แล้ว GitHub UI จะ render ให้ใต้รายการไฟล์
      จะเห็นได้ในตำแหน่งแบบนี้: https://github.com/shipmight/shipmight/tree/master/src/backe...
      เคยเห็นบาง project ใช้วิธีนี้เหมือนกัน
  • ยิ่งสั้นเท่าไร ก็ยิ่งมีโอกาสน้อยลงที่จะใช้ไม่ได้เพราะการเปลี่ยนแปลงในอนาคต หลักปฏิบัติสำคัญของ ARCHITECTURE คือเขียน เฉพาะสิ่งที่ไม่ค่อยเปลี่ยน เท่านั้น อย่าพยายาม sync กับ code
    interface มีโอกาสเปลี่ยนน้อยกว่า และเปลี่ยนได้ยากกว่า นี่คือมุมมองของ Parnas เกี่ยวกับเกณฑ์ที่ใช้แยก decomposition ของระบบออกเป็น module
    เห็นด้วยว่า codebase เข้าใจยาก การตั้งชื่อ “pattern” ช่วยได้ในระดับหนึ่ง แต่สุดท้ายก็ยังต้องอ่านค่อนข้างมากอยู่ดี
    บน GitHub บ่อยครั้ง commit message รายไฟล์ให้ความรู้สึกเหมือนคำอธิบาย แบบนั้นอาจมีประโยชน์มากกว่าหรือเปล่า?

  • ทุก project ที่เคยเข้าร่วม ตอน onboarding จะได้รับ architecture diagram และคำอธิบายสั้น ๆ เกี่ยวกับ component ต่าง ๆ
    เลยแปลกใจที่เรื่องนี้ไม่ค่อยพบบ่อยนักใน open source

    • “คำอธิบาย component” นี่แหละคือปัญหา เพราะต้องมีใครสักคนเป็นคนทำ
      project open source ไม่มีวันแรกที่พนักงานเริ่มงาน จึงไม่มีการแนะนำแบบนี้ด้วย
      ถ้าไม่ได้มีเวลามากจริง ๆ คำอธิบายแบบนี้มักไม่ค่อยดี พนักงานถูกคาดหวังว่าจะใช้เวลาหลายสัปดาห์กว่าจะทำอะไรได้ด้วยตัวเอง แต่พวกเราในฐานะ security consultant จะได้ฟังคำอธิบายชุดใหม่ทั้งหมดทุก ๆ 2 สัปดาห์ ปัญหาคือคำอธิบายพวกนี้เป็นแบบฉับพลัน ไม่มีโครงสร้าง และคนพูดมักเล่ารายละเอียดที่ไม่เกี่ยวข้องจำนวนมากเพราะ curse of knowledge
      บางทีให้คนที่เพิ่งเข้ามาใน repository เป็นคนเขียนสิ่งนี้สักครั้ง แล้วหลังจากนั้นค่อย maintain น่าจะดีกว่า ทางเลือกที่รองลงมาคือ แทนที่จะให้ใครก็ได้อธิบายสดทุกครั้ง ก็ให้ใช้เวลาคิดสัก 1 นาทีว่าจะใส่อะไรและตัดอะไร แล้วจดไว้ ตามที่ผู้เขียนบอก ไฟล์นี้ควรอธิบาย architecture ระดับสูงของ project และควรสั้น ผู้มีส่วนร่วมซ้ำ ๆ ทุกคนควรอ่าน และยิ่งสั้นเท่าไร ก็ยิ่งมีโอกาสน้อยลงที่จะใช้ไม่ได้เพราะการเปลี่ยนแปลงในอนาคต
  • รู้สึกมาตลอดว่านี่เป็น practice ที่มีประโยชน์มาก project จำนวนมากมี ไฟล์หลัก ไม่กี่ไฟล์ หรือ package/module ฯลฯ ที่การเปลี่ยนแปลงส่วนใหญ่เกิดขึ้น
    ถ้า contributor ใหม่หรือ contributor ที่กลับมาหลังห่างไปนานสามารถเรียนรู้สิ่งเหล่านั้นได้เร็ว เวลาเริ่มต้นกับ project ก็จะลดลงมาก
    เคยเพิ่มไฟล์ architecture ให้ project ในที่ทำงานหลายแห่ง [0], [1] และได้รับเสียงตอบรับดี ไม่สมบูรณ์แบบ แต่ดีกว่าไม่มี
    [0]: https://github.com/zapier/zapier-platform/pull/324
    [1]: https://github.com/stripe/stripe-cli/blob/master/ARCHITECTUR...

    • มีวิธีดูสิ่งแบบนี้อัตโนมัติใน GitHub ไหม? เช่น file change heatmap อะไรทำนองนั้น
  • สมัยก่อนชอบ มาตรฐาน docs/diagrams-as-code เล็ก ๆ แบบนี้มาก
    เช่น README-driven development, ARCHITECTURE.md, ADR, arc42, C4
    ตอนนี้แค่ใส่ Obsidian vault ไว้ในโฟลเดอร์ /docs ของ git repository
    แทนที่จะใช้มาตรฐานของคนอื่น ก็จัดระเบียบและ refactor เอกสารต่อเนื่องเหมือนจัดการ personal note ใน Obsidian
    ตอนแรกอยากใช้ Markdown subset ร่วมกันที่ทำงานได้ทั้งใน GFM ของ GitHub และ Obsidian แต่ก็เลิกไปแล้ว ตอนนี้ใช้ Markdown แบบ Obsidian ตรง ๆ รวมถึงฟีเจอร์เฉพาะอย่าง Dataview plugin และ template
    Mermaid และ LaTeX มีใน Obsidian อยู่แล้ว และมี PlantUML plugin ด้วย สำหรับภาพ/diagram แบบ visual ใช้ Canvas ในตัว, DrawIO, Excalidraw