ADRs and Request for Comments (RFC) (ADR กับ Request for Comments)

การส่ง ADR ฉบับร่างออกไปเพื่อขอความคิดเห็นสามารถช่วยให้สถาปนิกตรวจสอบข้อสมมติและข้อกล่าวอ้าง ของตัวเองกับกลุ่ม stakeholder ที่กว้างขึ้นได้ วิธีที่มีประสิทธิภาพในการดึงนักพัฒนาเข้ามาร่วม และเริ่มต้นความร่วมมือคือการสร้างสถานะแบบใหม่ที่เรียกว่า Request for Comments (RFC) และกำหนดเส้นตายให้ผู้ตรวจสอบส่ง feedback เมื่อถึงวันที่กำหนดแล้ว สถาปนิกก็สามารถ วิเคราะห์ความคิดเห็นเหล่านั้น ปรับการตัดสินใจตามความจำเป็น ตัดสินใจขั้นสุดท้าย แล้วตั้งสถานะ เป็น Proposed (หรือ Accepted ถ้าสถาปนิกมีอำนาจอนุมัติการตัดสินใจนั้นได้)

ADR ที่มีสถานะ RFC จะมีลักษณะดังนี้

STATUS
Request For Comments, Deadline 09 JAN 2026

อีกแง่มุมสำคัญของส่วน Status ใน ADR คือมันบังคับให้สถาปนิกและหัวหน้าหรือ lead architect ต้อง พูดคุยเกี่ยวกับเกณฑ์การอนุมัติการตัดสินใจด้าน architecture และตัดสินว่าสถาปนิกสามารถทำเองได้ หรือต้องได้รับการอนุมัติผ่าน architect ระดับสูงกว่า, architecture review board หรือหน่วยงาน governance อื่น ๆ

จุดเริ่มต้นที่ดีสามอย่างสำหรับบทสนทนาเหล่านี้คือ ต้นทุน, ผลกระทบข้ามทีม และความปลอดภัย ต้นทุนควร รวมถึงค่าซื้อซอฟต์แวร์หรือค่า license, ต้นทุนฮาร์ดแวร์เพิ่มเติม และระดับความพยายามโดยรวมในการ implement การตัดสินใจด้าน architecture นั้น ในการประมาณค่านี้ ให้คูณจำนวนชั่วโมงที่ประมาณไว้สำหรับการ implement การตัดสินใจด้าน architecture ด้วยอัตรา full-time equivalency (FTE) มาตรฐานของบริษัท เจ้าของโครงการหรือ project manager มักจะมีจำนวน FTE นี้อยู่แล้ว บทสนทนานี้อาจ นำไปสู่ข้อตกลงร่วมกันว่า ตัวอย่างเช่น ถ้าต้นทุนของการตัดสินใจด้าน architecture เกินจำนวนหนึ่ง ก็จะต้องตั้งสถานะเป็น Proposed และให้คนอื่นอนุมัติ ถ้าการตัดสินใจด้าน architecture ส่งผลกระทบต่อทีม หรือระบบอื่น หรือมีนัยด้านความปลอดภัยใด ๆ ก็จะต้องได้รับการอนุมัติจากหน่วยงาน governance ระดับสูงกว่า หรือ lead architect

เมื่อทีมกำหนดและตกลงเกณฑ์และขีดจำกัดที่สอดคล้องกันแล้ว (เช่น “ต้นทุนที่เกิน $5,000 ต้องได้รับการ อนุมัติจาก architecture review board”) ให้บันทึกไว้ให้ดี เพื่อให้สถาปนิกทุกคนที่สร้าง ADR รู้ว่า เมื่อไหร่ที่พวกเขาสามารถอนุมัติการตัดสินใจด้าน architecture ของตัวเองได้ และเมื่อไหร่ที่ทำไม่ได้

Context (Context)

ส่วน Context ของ ADR ระบุแรงผลักดันที่เกี่ยวข้อง กล่าวอีกนัยหนึ่งคือ “สถานการณ์อะไรที่บังคับให้ ฉันต้องตัดสินใจแบบนี้?” ส่วนนี้ของ ADR ให้สถาปนิกอธิบายสถานการณ์เฉพาะเจาะจงและอธิบายทางเลือก ที่เป็นไปได้อย่างกระชับ ถ้าสถาปนิกต้องบันทึกการวิเคราะห์ทางเลือกแต่ละอย่างอย่างละเอียด ให้เพิ่ม ส่วน Alternatives แทนที่จะใส่การวิเคราะห์นั้นไว้ในส่วน Context

ส่วน Context ยังให้พื้นที่สำหรับบันทึกพื้นที่เฉพาะของ architecture เองด้วย การอธิบายบริบท ก็เท่ากับสถาปนิกกำลังอธิบาย architecture ด้วย ใช้ตัวอย่างจากหัวข้อก่อนหน้า ส่วน Context อาจเขียนว่า “Order service ต้องส่งข้อมูลไปยัง Payment service เพื่อจ่ายเงินสำหรับ order ที่กำลังถูกวางอยู่ตอนนี้ ซึ่งอาจทำได้ด้วย REST หรือ asynchronous messaging” สังเกตว่าข้อความสั้น ๆ นี้ระบุทั้งสถานการณ์ และทางเลือกที่พิจารณาไว้ด้วย

Decision (Decision)

ส่วน Decision ของ ADR มีคำอธิบายการตัดสินใจด้าน architecture พร้อมเหตุผลรองรับอย่างครบถ้วน Nygard แนะนำให้ระบุการตัดสินใจด้าน architecture ด้วยน้ำเสียงที่ยืนยันและสั่งการ แทนที่จะเป็น passive voice ตัวอย่างเช่น การตัดสินใจใช้ asynchronous messaging ระหว่าง service ควรเขียนว่า “ เราจะใช้ asynchronous messaging ระหว่าง service” ซึ่งดีกว่า “ ผมคิดว่า asynchronous messaging ระหว่าง service น่าจะเป็นทางเลือกที่ดีที่สุด” มากนัก เพราะประโยคหลังไม่ได้ บอกชัดเจนว่าการตัดสินใจคืออะไรหรือได้มีการตัดสินใจแล้วหรือยัง—บอกแค่ความคิดเห็นของสถาปนิกเท่านั้น

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

เพื่ออธิบายประเด็นนี้ สมมติว่าคุณตัดสินใจใช้ Google’s Remote Procedure Call ( gRPC ) เพื่อสื่อสารระหว่าง service สองตัว เพื่อลด network latency เนื่องจากความต้องการ responsiveness ที่สูงมาก หลายปีต่อมา สถาปนิกคนใหม่ในทีมตัดสินใจใช้ REST แทน gRPC เพื่อทำให้การสื่อสารระหว่าง service สอดคล้องกันมากขึ้น เพราะสถาปนิกคนใหม่ไม่เข้าใจว่า ทำไม ถึงเลือก gRPC ตั้งแต่แรก การตัดสินใจของเขาจึงส่งผลกระทบอย่างมากต่อ latency ทำให้เกิด timeout ใน ระบบ upstream ถ้าสถาปนิกคนใหม่มี ADR ให้อ่าน เขาก็จะเข้าใจว่าการตัดสินใจดั้งเดิมที่ใช้ gRPC มีจุดประสงค์เพื่อลด latency (แลกกับ service ที่ coupled กันแน่นขึ้น) และสามารถป้องกันปัญหานี้ได้

Consequences (Consequences)

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

ส่วนนี้ยังเป็นที่ที่ดีสำหรับบันทึก trade-off analysis ที่ทำระหว่างกระบวนการตัดสินใจด้วย ตัวอย่างเช่น สมมติว่าคุณตัดสินใจใช้ asynchronous (fire-and-forget) messaging สำหรับการโพสต์รีวิวบนเว็บไซต์ เหตุผลของคุณสำหรับการตัดสินใจนี้คือเพื่อปรับปรุง responsiveness (จาก 3,100 มิลลิวินาที ลงมาเหลือ 25 มิลลิวินาที) เพราะผู้ใช้ไม่ต้องรอให้รีวิวจริง ๆ ถูกโพสต์—​แค่รอให้ message ถูกส่งไปยัง queue เท่านั้น สมาชิกทีมพัฒนาคนหนึ่งของคุณแย้งว่านี่เป็นไอเดียที่ไม่ดี เพราะความซับซ้อนของการจัดการ error ที่มากับ asynchronous request “ถ้ามีใครโพสต์รีวิวที่มีคำหยาบล่ะ จะเกิดอะไรขึ้น?” สิ่งที่สมาชิกทีม คนนี้ไม่รู้คือ คุณได้พูดคุยเรื่องนี้กับ business stakeholder และสถาปนิกคนอื่น ๆ แล้วตอนวิเคราะห์ trade-off ของการตัดสินใจนี้ และตกลงร่วมกันว่าการปรับปรุง responsiveness และจัดการ error handling ที่ซับซ้อนดีกว่าการเพิ่มเวลารอและให้ feedback ว่าการโพสต์รีวิวสำเร็จหรือไม่ ถ้าการตัดสินใจนี้ ถูกบันทึกด้วย ADR คุณก็สามารถให้ trade-off analysis นี้ไว้ในส่วน Consequences ได้ เพื่อป้องกัน ความขัดแย้งแบบนี้

Compliance (Compliance)

ส่วน Compliance ไม่ใช่หนึ่งในส่วนมาตรฐานของ ADR แต่เป็นส่วนที่เราแนะนำอย่างยิ่งให้เพิ่มเข้าไป ส่วน Compliance ระบุว่าการตัดสินใจด้าน architecture จะถูกวัดและ govern อย่างไร การตรวจสอบ compliance สำหรับการตัดสินใจนี้จะเป็นแบบ manual หรือทำเป็นอัตโนมัติด้วย fitness function ได้? ถ้าทำเป็นอัตโนมัติได้ สถาปนิกก็สามารถระบุได้ว่า fitness function จะถูกเขียนอย่างไร รวมถึงการ เปลี่ยนแปลงอื่น ๆ ใน code base ที่จำเป็นเพื่อวัด compliance ของการตัดสินใจด้าน architecture นี้

ตัวอย่างเช่น สมมติว่าคุณตัดสินใจใน traditional n-tiered layered architecture (ดังแสดงใน Figure 21-3 ) ว่า shared object ทั้งหมดที่ business object ใน Business layer ใช้ ต้องอยู่ใน Shared Services layer เพื่อแยกและควบคุม shared functionality

Architectural Decision Example

Figure 21-3. An example of an architectural decision

การตัดสินใจด้าน architecture นี้สามารถวัดและ govern ได้ด้วยเครื่องมือ automation หลายตัว รวมถึง ArchUnit ใน Java และ NetArchTest ใน C# ด้วย ArchUnit ใน Java automated fitness-function test สำหรับการตัดสินใจด้าน architecture นี้อาจมีลักษณะดังนี้

@Test
public void shared_services_should_reside_in_services_layer() {
    classes().that().areAnnotatedWith(SharedService.class)
        .should().resideInAPackage("..services..")
        .check(myClasses);
}

automated fitness function นี้จำเป็นต้องเขียน story ใหม่เพื่อสร้าง Java annotation ( @SharedService ) และเพิ่มมันลงใน shared class ทั้งหมด เพื่อรองรับวิธี governance แบบนี้

Notes (Notes)

อีกส่วนหนึ่งที่ไม่ใช่ส่วนมาตรฐานของ ADR แต่เราแนะนำอย่างยิ่งให้เพิ่มเข้าไปคือส่วน Notes ส่วนนี้รวม metadata ต่าง ๆ เกี่ยวกับ ADR ได้แก่

  • ผู้เขียนดั้งเดิม

  • วันที่อนุมัติ

  • ผู้อนุมัติ

  • วันที่ถูก supersede

  • วันที่แก้ไขล่าสุด

  • ผู้แก้ไข

  • การแก้ไขล่าสุด

แม้จะเก็บ ADR ไว้ใน version-control system (เช่น Git) ก็ยังมีประโยชน์ที่จะมี metadata เพิ่มเติม นอกเหนือจากที่ repository รองรับได้ เราแนะนำให้เพิ่มส่วนนี้ ไม่ว่าสถาปนิกจะเก็บ ADR ไว้ที่ไหนและ อย่างไรก็ตาม

Example (ตัวอย่าง)

ตัวอย่างของระบบประมูล Going, Going, Gone (GGG) ของเรามีการตัดสินใจด้าน architecture หลายสิบครั้ง การแยก user interface ของผู้ประมูลและผู้ดำเนินการประมูลออกจากกัน การใช้ hybrid architecture ที่ ประกอบด้วย event-driven และ microservices การใช้ Real-time Transport Protocol (RTP) สำหรับการจับภาพวิดีโอ การใช้ API Gateway เดียว และการใช้ queue แยกกันสำหรับ messaging เป็นเพียงตัวอย่างส่วนหนึ่งของการ ตัดสินใจด้าน architecture ที่สถาปนิกจะทำ ทุกการตัดสินใจด้าน architecture ที่สถาปนิกทำ ไม่ว่าจะดูชัดเจน แค่ไหน ก็ควรถูกบันทึกและให้เหตุผลรองรับไว้

Figure 21-4 แสดงตัวอย่างหนึ่งของการตัดสินใจด้าน architecture ภายในระบบประมูล GGG นั่นคือการใช้ point-to-point queue แยกกันระหว่าง bid capture, bid streamer และ bid tracker service แทนที่จะใช้ publish-and-subscribe topic เดียว (หรือแม้แต่ REST)

Example Architectural Decision

Figure 21-4. Use of pub/sub between services

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

ต่อไปนี้คือตัวอย่าง ADR สำหรับการตัดสินใจด้าน architecture นี้

ADR 76. Separate Queues for Bid Streamer and Bidder Tracker Services

STATUS
Accepted

CONTEXT
Bid Capture service เมื่อได้รับ bid แล้ว ต้องส่ง bid นั้นต่อไปยัง Bid Streamer service และ Bidder Tracker service ซึ่งอาจทำได้ด้วย topic เดียว (pub/sub), queue แยกกัน (point-to-point) สำหรับแต่ละ service หรือ REST ผ่าน Online Auction API layer

DECISION
เราจะใช้ queue แยกกันสำหรับ Bid Streamer และ Bidder Tracker service

Bid Capture service ไม่จำเป็นต้องได้รับข้อมูลใด ๆ จาก Bid Streamer service หรือ Bidder Tracker service (การสื่อสารเป็นแบบทางเดียวเท่านั้น)

Bid Streamer service ต้องได้รับ bid ในลำดับเดียวกับที่ Bid Capture service รับไว้ทุกประการ การใช้ messaging และ queue จะรับประกันลำดับ bid สำหรับ stream โดยอัตโนมัติ ด้วยการใช้ first-in, first out (FIFO) queue

bid หลายรายการเข้ามาในจำนวนเท่ากัน (เช่น “มีใครเสนอร้อยไหม?”) Bid Streamer service ต้องการแค่ bid แรกที่ได้รับสำหรับจำนวนนั้น ในขณะที่ Bidder Tracker ต้องการ bid ทั้งหมดที่ได้รับ การใช้ topic (pub/sub) จะต้องให้ Bid Streamer เพิกเฉยต่อ bid ที่มีจำนวนเท่ากับก่อนหน้า ซึ่งจะบังคับให้ Bid Streamer ต้องเก็บ shared state ระหว่าง instance

Bid Streamer service เก็บ bid ของสินค้าไว้ใน in-memory cache ในขณะที่ Bidder Tracker เก็บ bid ไว้ในฐานข้อมูล Bidder Tracker จึงจะช้ากว่าและอาจต้องใช้ backpressure การใช้ queue เฉพาะสำหรับ Bidder Tracker จะให้จุด backpressure เฉพาะนี้

CONSEQUENCES
เราจะต้องใช้ clustering และ high availability สำหรับ message queue

การตัดสินใจนี้จะต้องให้ Bid Capture service ส่งข้อมูลเดียวกันไปยังหลาย queue

bid event ภายในจะข้าม security check ที่ทำใน API layer
UPDATE: หลังจากการทบทวนในที่ประชุม ARB วันที่ 14 มกราคม 2025 ARB ตัดสินว่านี่เป็น trade-off ที่ยอมรับได้ และไม่จำเป็นต้องมี security check เพิ่มเติมสำหรับ bid event ระหว่าง service เหล่านี้

COMPLIANCE
เราจะใช้การรีวิว code แบบ manual เป็นระยะ ๆ เพื่อให้แน่ใจว่ามีการใช้ asynchronous pub/sub messaging ระหว่าง Bid Capture service, Bid Streamer service และ Bidder Tracker service

NOTES
ผู้เขียน: Subashini Nadella

อนุมัติโดย: สมาชิกที่ประชุม ARB, 14 มกราคม 2025

แก้ไขล่าสุด: 14 มกราคม 2025

Storing ADRs (การจัดเก็บ ADR)

เมื่อสถาปนิกสร้าง ADR แล้ว ก็ต้องเก็บมันไว้ที่ไหนสักแห่ง ไม่ว่าจะเป็นที่ไหนก็ตาม แต่ละการตัดสินใจ ด้าน architecture ควรมีไฟล์หรือหน้า wiki เป็นของตัวเอง สถาปนิกบางคนชอบเก็บ ADR ไว้ใน Git repository เดียวกับ source code ทำให้ทีม version และ track ADR ได้เหมือนกับ source code

อย่างไรก็ตาม สำหรับองค์กรขนาดใหญ่ เราขอเตือนไม่ให้ทำแบบนี้ด้วยเหตุผลหลายประการ ประการแรก ทุกคนที่จำเป็นต้องเห็นการตัดสินใจด้าน architecture อาจไม่มีสิทธิ์เข้าถึง Git repository ที่เก็บ ADR ประการที่สอง Git repository ของ application ไม่ใช่ที่ที่ดีสำหรับเก็บ ADR ที่มีบริบทนอกเหนือจากตัวมันเอง (เช่น การตัดสินใจด้าน integration architecture, enterprise architecture หรือการตัดสินใจที่ใช้ร่วมกัน ทุก application) ด้วยเหตุผลเหล่านี้ เราแนะนำให้เก็บ ADR ไว้ใน ADR Git repository เฉพาะที่ทุกคนเข้าถึงได้, wiki (ใช้ wiki template) หรือ shared directory บน shared file server ที่เข้าถึงได้ง่ายด้วย wiki หรือซอฟต์แวร์ render เอกสารอื่น ๆ

Figure 21-5 แสดงให้เห็นว่าโครงสร้าง directory นี้ (หรือโครงสร้าง navigation ของหน้า wiki) อาจมีลักษณะอย่างไร

Example ADR Directory Structure

Figure 21-5. Example directory structure for storing ADRs

directory application มีการตัดสินใจด้าน architecture ที่เฉพาะเจาะจงกับบริบทของ application (หรือ product) หนึ่ง ๆ directory นี้ถูกแบ่งย่อยออกเป็น directory อื่น ๆ ต่อไปนี้

common

subdirectory common ใช้สำหรับการตัดสินใจด้าน architecture ที่ใช้กับทุก application เช่น “class ที่เกี่ยวข้องกับ framework ทั้งหมดจะมี annotation (@Framework ใน Java) หรือ attribute ([Framework] ใน C#) ที่ระบุว่า class นั้นเป็นส่วนหนึ่งของ framework code ที่อยู่เบื้องหลัง”

application

subdirectory ภายใต้ directory application จะสอดคล้องกับบริบทของ application หรือระบบเฉพาะเจาะจง และมีการตัดสินใจด้าน architecture ที่เฉพาะเจาะจงกับ application หรือระบบนั้น (ในตัวอย่างนี้คือ application app1 และ app2 )

integration

directory integration มี ADR ที่เกี่ยวข้องกับการสื่อสารระหว่าง application, ระบบ หรือ service ต่าง ๆ

enterprise

ADR ของ enterprise architecture จะเก็บอยู่ใน directory enterprise ซึ่งบ่งบอกว่านี่คือการตัดสินใจด้าน architecture ระดับ global ที่ส่งผลกระทบต่อทุกระบบและทุก application ตัวอย่างของ ADR ระดับ enterprise architecture คือ “การเข้าถึงฐานข้อมูลของระบบใดระบบหนึ่ง จะทำได้เฉพาะจากระบบที่เป็นเจ้าของเท่านั้น” เพื่อป้องกันไม่ให้ฐานข้อมูลถูกแชร์ข้ามหลายระบบ

เมื่อเก็บ ADR ไว้ใน wiki โครงสร้างเดียวกันนี้ก็ยังใช้ได้ โดยแต่ละโครงสร้าง directory จะแทนหน้า landing page สำหรับการนำทาง ADR แต่ละฉบับจะแทนด้วยหน้า wiki หนึ่งหน้าภายในแต่ละ landing page สำหรับการนำทาง (application, integration หรือ enterprise)

ชื่อ directory และ landing page ที่ระบุไว้ในหัวข้อนี้เป็นเพียงคำแนะนำและตัวอย่างเท่านั้น เลือกใช้ ชื่อใดก็ได้ที่เหมาะกับสถานการณ์ของบริษัท ตราบใดที่ชื่อเหล่านั้นสอดคล้องกันในทุกทีม

ADRs as Documentation (ADR ในฐานะเอกสาร)

การจัดทำเอกสาร software architecture เป็นเรื่องยากมาโดยตลอด แม้จะมีมาตรฐานบางอย่างที่กำลังเกิดขึ้น สำหรับการทำ diagram architecture (เช่น C4 Model ของสถาปนิกซอฟต์แวร์ Simon Brown หรือมาตรฐาน ArchiMate ของ The Open Group) แต่ก็ยังไม่มีมาตรฐานที่ตกลงกันไว้สำหรับการจัดทำเอกสาร software architecture นี่คือจุดที่ ADR เข้ามามีบทบาท

ADR สามารถเป็นวิธีที่มีประสิทธิภาพในการจัดทำเอกสาร software architecture ได้ ส่วน Context ให้โอกาส ที่ดีเยี่ยมในการอธิบายพื้นที่เฉพาะของระบบที่ต้องการการตัดสินใจด้าน architecture รวมถึงอธิบายทางเลือก ต่าง ๆ ด้วย ที่สำคัญกว่านั้น ส่วน Decision อธิบายเหตุผลว่าทำไมถึงตัดสินใจแบบนั้น ซึ่งเป็นรูปแบบเอกสาร architecture ที่ดีที่สุด ส่วน Consequences เพิ่มชิ้นส่วนสุดท้ายของปริศนาด้วยการอธิบายการวิเคราะห์ trade-off สำหรับการตัดสินใจนั้น—ตัวอย่างเช่น เหตุผล (และ trade-off) ในการเลือก performance แทน scalability

Using ADRs for Standards (การใช้ ADR สำหรับ Standard)

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

นี่เป็นวิธีที่ดีในการตรวจสอบว่า standard หนึ่ง ๆ ควรมีอยู่ตั้งแต่แรกหรือไม่ ถ้าสถาปนิกไม่สามารถให้ เหตุผลรองรับได้ บางทีมันอาจไม่ใช่ standard ที่ดีที่จะกำหนดและบังคับใช้ ยิ่งไปกว่านั้น ยิ่งนักพัฒนาเข้าใจ ทำไม standard หนึ่ง ๆ ถึงมีอยู่มากเท่าไหร่ พวกเขาก็ยิ่งมีแนวโน้มที่จะปฏิบัติตามมากขึ้น (และในทางกลับกัน ก็ไม่ค่อยจะท้าทายมัน) ส่วน Consequences ของ ADR เป็นอีกที่หนึ่งที่ดีในการตรวจสอบว่า standard นั้น ใช้ได้จริงหรือไม่ เพราะมันบังคับให้สถาปนิกต้องคิดและบันทึกนัยและผลกระทบของ standard นั้น รวมถึงว่า standard นั้นควรถูก implement หรือไม่

Using ADRs with Existing Systems (การใช้ ADR กับระบบที่มีอยู่แล้ว)

สถาปนิกจำนวนมากตั้งคำถามถึงประโยชน์ของ ADR สำหรับระบบที่มีอยู่แล้ว เพราะท้ายที่สุดแล้ว การตัดสินใจ ด้าน architecture ก็ถูกทำไปแล้ว และระบบก็อยู่ใน production แล้ว ADR ยังมีประโยชน์จริง ๆ ตอนนี้หรือไม่? จริง ๆ แล้วมันมีประโยชน์ อย่าลืมว่า ADR เป็นมากกว่าแค่เอกสาร—มันช่วยให้สถาปนิกและนักพัฒนาเข้าใจ ทำไม ถึงตัดสินใจแบบนั้น และมันเป็นการตัดสินใจที่เหมาะสมที่สุดหรือไม่

เริ่มต้นด้วยการเขียน ADR สำหรับการตัดสินใจด้าน architecture ที่สำคัญ ๆ ที่เคยทำไปแล้ว และตั้งคำถาม ว่าการตัดสินใจเหล่านั้นถูกต้องหรือไม่ ตัวอย่างเช่น บางที service กลุ่มหนึ่งอาจแชร์ฐานข้อมูลเดียวกัน ทำไม? มีเหตุผลที่ดีหรือไม่? ควรจะแยกข้อมูลออกจากกันหรือไม่?

ส่วนหนึ่งของการเดินทางในการนำ ADR มาใช้กับระบบที่มีอยู่แล้ว คือการทำงานสืบสวนเล็ก ๆ น้อย ๆ เพื่อค้นหา คำถาม ทำไม เหล่านี้ น่าเสียดายที่คนที่ตัดสินใจแต่แรกอาจลาออกจากบริษัทไปนานแล้ว จึงไม่มีใครรู้คำตอบ ในกรณีแบบนี้ จึงขึ้นอยู่กับสถาปนิกที่จะระบุและวิเคราะห์ทางเลือกและ trade-off ของแต่ละตัวเลือก และพยายามยืนยัน (หรือหักล้าง) การตัดสินใจที่มีอยู่แล้ว ไม่ว่าจะกรณีไหน การเขียน ADR สำหรับการตัดสินใจสำคัญแบบนี้ก็เริ่ม สร้างเหตุผลรองรับและ rationale (รวมถึง brain trust) ให้กับระบบ และช่วยระบุความไม่มีประสิทธิภาพด้าน architecture และการออกแบบระบบที่ผิดพลาดได้

Leveraging Generative AI and LLMs in Architectural Decisions (การใช้ Generative AI และ LLM ในการตัดสินใจด้าน Architecture)

หนึ่งในแง่มุมที่น่าสนใจของ generative AI คือสถาปนิกสามารถใช้มันช่วยตัดสินใจและตรวจสอบการตัดสินใจได้ หรือไม่ service ควรใช้ messaging, streaming หรือ event sourcing เมื่อส่งข้อมูล downstream หรือไม่? ฐานข้อมูลควรยังคงเป็น monolith เดียว หรือควรถูกแยกออกเป็น domain database หลายตัว? Payment Processing ควร deploy เป็น service เดียว หรือแยกออกเป็นหลาย service ตามแต่ละประเภทการชำระเงิน?

สถาปนิกส่วนใหญ่รู้คำตอบของคำถามเหล่านี้อยู่แล้ว—มันขึ้นอยู่กับสถานการณ์! กลับมาที่กฎข้อแรกของ Software Architecture ของเราที่ว่า ทุกอย่างใน software architecture คือ trade-off การตัดสินใจแบบนี้ขึ้นอยู่กับปัจจัยหลายอย่าง รวมถึงบริบทเฉพาะที่การตัดสินใจนั้นถูกนำไปใช้ ทุกสถานการณ์ และทุกสภาพแวดล้อมแตกต่างกัน ซึ่งเป็นเหตุผลว่าทำไมจึงไม่มี “best practice” สำหรับคำถามเชิงโครงสร้าง แบบนี้

LLM ส่วนใหญ่ให้ผลลัพธ์โดยอิงจากความน่าจะเป็นเป็นหลัก กล่าวอีกนัยหนึ่งคือ อะไรคือคำตอบที่น่าจะเป็นไปได้ มากที่สุด เมื่อพิจารณาจากบริบทของ prompt และอะไรคือ “best practice” สำหรับปัญหานี้? อย่างไรก็ตาม ความน่าจะเป็นและ “best practice” ไม่มีที่ทางในการตัดสินใจด้าน architecture การตอบคำถามด้าน architecture ต้องอาศัยการวิเคราะห์ trade-off ที่เกี่ยวข้องอย่างรอบคอบ และนำบริบททางธุรกิจและเทคนิค เฉพาะเจาะจงมาใช้เพื่อระบุตัวเลือกที่เหมาะสมที่สุด ตัวอย่างเช่น ถ้าธุรกิจให้ความสำคัญกับ time to market มากที่สุด (การส่งมอบการเปลี่ยนแปลงและฟีเจอร์ใหม่ให้ลูกค้าได้เร็วที่สุดเท่าที่จะเป็นไปได้) แล้ว maintainability ก็จะสำคัญกว่า performance มาก และจะขับเคลื่อนกระบวนการตัดสินใจส่วนใหญ่ไปในทิศทางของการปรับ maintainability ให้ดีที่สุด

การตัดสินใจด้าน architecture ต้องแปลงข้อกังวลทางธุรกิจ (เช่น time to market หรือการเติบโตอย่างยั่งยืน) ให้เป็น architectural characteristic (เช่น maintainability, testability, deployability และอื่น ๆ) การแปลงนี้ไม่ได้ชัดเจนเสมอไป และการทำให้ถูกต้องต้องอาศัยประสบการณ์หลายปี เมื่อทำเสร็จแล้ว มันจะเป็น พื้นฐานสำหรับ trade-off analysis ตัวอย่างเช่น การตัดสินใจว่าจะมี service เดียวสำหรับการประมวลผลการ ชำระเงิน หรือ service แยกตามแต่ละประเภทการชำระเงิน สรุปแล้วก็คือ trade-off ระหว่าง maintainability กับ performance โดย service เดียวให้ performance ที่ดีกว่า แต่หลาย service ให้ maintainability ที่ดีกว่า ถ้าธุรกิจให้ความสำคัญกับ time to market เป็นหลัก maintainability ก็จะสำคัญกว่า performance มากนัก ดังนั้น service แยกกันจึงเป็นทางเลือกที่เหมาะสมสำหรับบริบทเฉพาะนี้

เนื่องจากลักษณะเฉพาะเจาะจงและเป็นรายบุคคลของการวิเคราะห์ trade-off และบริบททางธุรกิจ generative AI ในปัจจุบันจึงยากที่จะให้การตัดสินใจด้าน architecture ที่เหมาะสมที่สุด สถานการณ์ที่ดีที่สุดตามการทดลอง ล่าสุดที่ผู้เขียนของเราได้ทำ คือให้เครื่องมือ generative AI ช่วยระบุ trade-off ที่เป็นไปได้ของการ ตัดสินใจ เพื่อช่วยระบุ trade-off ที่อาจพลาดไป แม้เครื่องมือ generative AI จะมี ความรู้ มากมาย แต่ก็ยังขาด ปัญญา ที่จำเป็นในการตัดสินใจด้าน architecture ที่เหมาะสมที่สุด