30 คะแนน โดย xguru 2020-08-17 | 3 ความคิดเห็น | แชร์ทาง WhatsApp

ADR = Architecture Decision Records

การบันทึกไว้ในโค้ดเบสว่าเหตุใดจึงตัดสินใจเชิงสถาปัตยกรรมแบบนั้น
GitHub ก็กำลังนำสิ่งนี้ไปใช้กับทีมมือถือ iOS/Android และบทความนี้อธิบายว่าทำไมมันจึงจำเป็น

ไม่ใช่เพื่อคุณ แต่เพื่อคุณในอนาคต

ADR ไม่ใช่กระบวนการทบทวนการตัดสินใจที่ฉันเคยทำ แต่เป็นสิ่งที่ช่วยให้จำ mindset ในตอนที่ตัดสินใจสถาปัตยกรรมนี้ได้อีกครั้งในอีก 6~12 เดือนข้างหน้า
ADR จับภาพช่วงเวลาที่มีการตัดสินใจไว้ รวมถึง PoC ที่ถูกพูดถึงในที่ประชุม/Zoom meeting/Slack/โค้ดทั้งหมด
คือการดึง context ที่อยู่ในหัวออกมาเป็นคำพูด เพื่อให้เมื่อกลับมาทบทวนสถาปัตยกรรมนี้ภายหลัง จะสามารถใส่ context นั้นกลับเข้าไปในหัวได้อีกครั้ง

โบนัสที่แท้จริงจะปรากฏเมื่ออีกหลายเดือนต่อมา มีคนถามคุณแบบกล่าวโทษว่าทำไมโมดูล GitHubAPIClient ถึงทำงานแบบนี้
แทนที่จะต้อง pair กัน 30 นาทีเพื่ออธิบายโค้ด คุณสามารถโยน ADR นี้ให้ แล้วอธิบายการตัดสินใจที่เกิดขึ้นระหว่างการสร้างโมดูลนั้นได้

ไม่ใช่เพื่อคุณ แต่เพื่อเพื่อนร่วมงานของคุณ

ADR ควรเขียนให้ยาวกว่าคำอธิบายบรรทัดเดียวอย่าง "ฟีเจอร์นี้คือการทำงานตาม feature-#3128"
มันเป็นรูปแบบคำอธิบายที่ยาวขึ้น ซึ่งช่วยให้เพื่อนร่วมงานเข้าใจได้ว่าทำไมฟีเจอร์นี้จึงถูกสร้างด้วยวิธีนี้แทนที่จะเป็นอีกวิธีหนึ่ง
(เช่น แสดงใน ADR ด้วยหัวข้ออย่าง "ทางเลือกที่พิจารณา" , "ข้อดีและข้อเสีย" เป็นต้น)

สิ่งที่ง่ายสำหรับคุณ อาจซับซ้อนสำหรับเพื่อนร่วมงานก็ได้
ลองสละเวลาเล็กน้อย เขียนกระบวนการคิดตอนที่ตัดสินใจไว้ จะเป็นการเปิดโอกาสให้สมาชิกทีมได้เข้ามาอยู่ในหัวของคุณ
เมื่อเขียน ADR แล้ว ก็จะทำให้เกิด "Decision Socialization (การทำให้การตัดสินใจเป็นเรื่องร่วมกัน)" ได้
เมื่อเป็นแบบนี้ แทนที่แต่ละคนจะตัดสินใจแยกกัน ทีมจะเป็นผู้ตัดสินใจโดยรับผิดชอบต่อการดูแลรักษาร่วมกัน

หากเขียน ADR ก่อนเปิด pull request คุณจะได้รับ PR review ที่ดีกว่าจากทีมที่เข้ามาตรวจทาน

ไม่ใช่เพื่อคุณ แต่เพื่อเพื่อนร่วมงานในอนาคต

ADR ไม่ได้มีไว้เพื่อแสดงว่าคุณฉลาดแค่ไหน หรือทำให้คนอื่นงงกับสถาปัตยกรรมที่คุณสร้าง
ADR ช่วยให้เมื่อมีสมาชิกทีมใหม่เข้ามา พวกเขาจะเข้าใจทั้งโค้ดเบสปัจจุบันและวิธีที่โค้ดเบสพัฒนามาตลอดช่วงเวลาที่ผ่านมาได้

เมื่อทีมขยายตัวและเติบโตขึ้น ช่องทางการสื่อสารระหว่างสมาชิกทีมก็เพิ่มขึ้น
การเขียนการตัดสินใจเหล่านี้ไว้จะช่วยให้ทีมสื่อสารกับคนที่เพิ่งเข้าร่วมใหม่ได้ดีขึ้นเมื่อทีมเติบโต

สถานการณ์ที่ดีที่สุดคือ สมาชิกทีมของคุณเขียน ADR ใหม่ขึ้นมาเพื่อแทนที่การตัดสินใจที่คุณเคยทำไว้ และในอนาคตคุณก็จะได้เรียนรู้จากเพื่อนร่วมงานของคุณ

"เขียน ADR ให้มากขึ้น ทีมของเราเติบโตขึ้นและโค้ดเบสซับซ้อนขึ้นเมื่อไร ADR ก็ยิ่งเป็นวิธีที่ดีในการช่วยเหลือตัวเราในอนาคต สมาชิกทีมปัจจุบัน และสมาชิกทีมในอนาคต"

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

 
xguru 2020-08-25

ในบรรดากรณีศึกษารัฐบาลอิเล็กทรอนิกส์ มี Gov.UK ที่มีชื่อเสียง ซึ่งยังมี Repository ที่รวบรวม ADR ที่เกี่ยวข้องกับสถาปัตยกรรม AWS cloud ของตนเองด้วย

https://github.com/alphagov/govuk-aws/…

 
beatblue 2020-08-20

เป็นข้อมูลอ้างอิงที่ดีมากครับ

 
xguru 2020-08-17

ตัวอย่าง ADR

การตัดสินใจเลือก CSS framework

https://github.com/joelparkerhenderson/architecture_decision_record/…

  • ประเด็น: จำเป็นต้องตัดสินใจเลือก CSS framework สำหรับเว็บแอป ต้องรวดเร็วและเสถียรไม่ว่าจะเป็นเบราว์เซอร์ยอดนิยมหรือขนาดหน้าจอแบบใดก็ตาม ต้องรองรับการทำ iteration ได้รวดเร็วในด้าน design/layout/UI/UX และรองรับ responsive design
  • การตัดสินใจ: ตัดสินใจใช้ Bulma
  • สมมติฐาน: เพราะต้องการสร้างเว็บแอปที่ modern, เร็ว และ responsive จึงไม่อยากใช้ jQuery

  • ข้อจำกัด: ต้องเป็น framework ที่ไม่จำเป็นต้องใช้ jQuery

  • สิ่งที่พิจารณา: ไม่ใช้อะไรเลย หรือเลือกจาก Bootstrap/Bulma/Foundation/Materialize/Semantic UI โดยพิจารณา Bulma และ Semantic UI อย่างจริงจังเป็นพิเศษ

Monorepo vs Multirepo

https://github.com/joelparkerhenderson/architecture_decision_record/…

  • ประเด็น: โปรเจกต์ของเรามี 3 หมวดหลักคือ frontend UI, middleware, backend server

→ กำลังใช้ git เป็น SCM อยู่ จึงต้องตัดสินใจระหว่าง monorepo vs polyrepo vs hybrid

  • การตัดสินใจ:

→ ถ้าองค์กร/ทีม/โปรเจกต์มีขนาดเล็กและต้องทำ iteration อย่างรวดเร็ว ให้ใช้ Monorepo

→ ถ้าองค์กร/ทีม/โปรเจกต์มีขนาดใหญ่และความเสถียรสำคัญกว่า ให้ใช้ Polyrepo

  • สมมติฐาน: โค้ดที่เราสร้างขึ้นมีไว้สำหรับองค์กร ไม่ใช่สำหรับภายนอก (สาธารณะ)

การตัดสินใจเลือกภาษาโปรแกรม

https://github.com/joelparkerhenderson/architecture_decision_record/…

  • ประเด็น: ต้องตัดสินใจเลือกภาษาสำหรับพัฒนาซอฟต์แวร์ ทั้งฝั่งเว็บ frontend และ backend
  • การตัดสินใจ:

→ frontend ใช้ TypeScript

→ backend ใช้ Rust

  • สมมติฐาน:

→ ฝั่ง frontend เป็นงานทั่วไป แต่ต้องพัฒนา, deploy และทำซ้ำได้อย่างรวดเร็ว ไม่จำเป็นต้องรองรับ legacy

→ ฝั่ง backend มีความต้องการสูงกว่างานทั่วไปเล็กน้อย ต้องคำนึงถึงคุณภาพ, ความเสถียร และความปลอดภัย ต้องการระดับเกือบ real-time (ต้องไม่มีการหยุดจาก GC) functional programming / parallel processing และ multi-core processing รวมถึง memory safety ก็สำคัญ

  • ข้อจำกัด: ต้องสามารถรันได้แน่นอนบน serverless ของ major cloud service (Amazon Lamba)

  • สิ่งที่พิจารณา: C/C++/Clojure/Elixir/Erlang/Elm/Flow/Go/Haskell/Java/Javascript/Kotlin/Python/Ruby/Rust/TypeScript

  • ข้อถกเถียง:

→ C: ตัดออกเพราะความปลอดภัยต่ำ; Rust ทำได้ดีกว่าในแทบทุกด้าน

→ C++: ตัดออกเพราะยุ่งเหยิง (mess); Rust ทำได้ดีกว่าในแทบทุกด้าน

→ Clojure: การทำ modeling ยอดเยี่ยม; ใกล้ Lisp มากที่สุด; runtime บน JVM ที่ยอดเยี่ยม

→ Elixir: runtime ที่ยอดเยี่ยมด้าน deployment และ concurrency; developer experience ยอดเยี่ยม; ecosystem ค่อนข้างเล็ก

→ Erlang: runtime ที่ยอดเยี่ยมด้าน deployment และ concurrency; developer experience ค่อนข้างท้าทาย; ecosystem ค่อนข้างเล็ก

→ Elm: มีอนาคตสดใส; IBM กำลังแชร์กรณีศึกษาที่ดี; ecosystem เล็ก

→ Flow: เป็นการพัฒนา JS ที่น่าสนใจ; แต่เหล่านักพัฒนากำลังถอยห่างออกไป

→ Go: developer experience ยอดเยี่ยม; concurrency ยอดเยี่ยม; เคยมีการตัดสินใจที่ไม่ดีบางอย่างจนทำให้ภาษาดูแปลก

→ Haskell: ภาษา functional ที่ดีที่สุด; ชุมชนนักพัฒนาขนาดเล็ก; ยังมีกรณีสำเร็จใน production ไม่มากนัก

→ Java: runtime ดีที่สุด; ecosystem ยอดเยี่ยม; developer experience ธรรมดา

→ JavaScript: ภาษาที่ได้รับความนิยมมากที่สุด; ecosystem กว้างที่สุด

→ Kotlin: ปรับปรุงหลายอย่างของ Java; ได้รับการสนับสนุนอย่างยอดเยี่ยมจาก JetBrains; มีกรณีความสำเร็จจาก Java to Kotlin มากมาย

→ Python: ภาษาที่ได้รับความนิยมสูงสุดทางฝั่ง system administration; มีเครื่องมือวิเคราะห์ที่ดี; มี web framework ที่ดี; ถูกทิ้งเมื่อ Google เลือก Go

→ Ruby: developer experience ดีที่สุด; web framework ดีที่สุด; ชุมชนยอดเยี่ยม; ช้ามาก; ทำ packaging ได้ยาก

→ Rust: ภาษาใหม่ที่ดีที่สุด; เน้น Zero-cost abstractions (แม้ทำ abstraction ก็ไม่ทำให้ช้าลง); เน้น concurrency; ecosystem ค่อนข้างเล็ก; มีข้อจำกัดใน optimization ของ compiler บางอย่าง (เช่น การเข้าถึงหน่วยความจำโดยตรงต้องเป็น unsafe)

→ TypeScript: เพิ่ม type ให้กับ JavaScript; transpiler ยอดเยี่ยม; นักพัฒนากำลังย้ายจาก JS ไป TS มากขึ้นเรื่อยๆ; ได้รับการสนับสนุนอย่างแข็งแกร่งจาก Microsoft

  • ตัดสินใจว่าจะไม่เลือกแบบ VM-based (เพราะเพิ่มความซับซ้อน)

  • หากต้องการ runtime ที่เร็วที่สุด ให้เลือก JS และ C

  • หากต้องการ runtime ที่เร็วเกือบที่สุด ให้เลือก TypeScript และ Rust

  • หากเลือก VM และ web framework แล้ว

→ Closer และ Luminous

→ Java และ Spring

→ Elixir และ Phoenix