- ในระบบขนาดใหญ่ ระบบแบบกระจาย และระบบระดับล่างที่มีความสำคัญสูง ควรมอง formal methods ไม่ใช่เป็น ขั้นตอนเสริมเพื่อความถูกต้องเท่านั้น แต่เป็นแนวปฏิบัติทางวิศวกรรมที่ช่วยลดเวลาและต้นทุน
- ซอฟต์แวร์มีแนวโน้มที่การออกแบบและการนำไปใช้งานจะปะปนกันได้ง่าย การแก้แบบออกแบบในช่วงท้ายจึงนำไปสู่ การทำ implementation ใหม่ และต้นทุนจากการเปลี่ยน API ทันที
- หากตรวจทานพฤติกรรมและอินเทอร์เฟซอย่างเป็นรูปธรรมก่อน implementation จะช่วยลดความหนาแน่นของบั๊กและปัญหาหลังขึ้น production และทำให้ไปถึงแบบออกแบบที่ถูกต้องได้เร็วขึ้น
- ในพื้นที่ที่ความต้องการผู้ใช้เปลี่ยนเร็ว หรือ formalize ได้ยาก เช่น UI, เอกสาร และลอจิกราคา ประโยชน์ของการทำ formal design ล่วงหน้าแบบเต็มรูปแบบอาจลดลง
- เครื่องมืออย่าง TLA+ และ P สามารถใช้ตรวจสอบการปรับแต่งและข้อจำกัดในขั้นออกแบบ เพื่อลด trade-off ระหว่างความถูกต้องกับประสิทธิภาพ ได้ด้วย
Formal methods ในฐานะแนวปฏิบัติทางวิศวกรรมที่ดี
- Formal methods เป็นส่วนสำคัญของแนวปฏิบัติด้านวิศวกรรมซอฟต์แวร์ที่ดี
- มีคุณค่าในการใช้งานเป็นพิเศษสำหรับวิศวกรที่ดูแล ระบบขนาดใหญ่, ระบบแบบกระจาย และระบบระดับล่างที่มีความสำคัญสูง
- เริ่มจากสมมติฐานที่ว่า วิศวกรรมโดยแก่นแท้คือกิจกรรมเพื่อ ปรับเวลาและต้นทุนให้เหมาะสมที่สุด
- โดยพิจารณาประสิทธิภาพ, ความสามารถในการขยาย, ความยั่งยืน และประสิทธิผลควบคู่กัน
- Formal methods ไม่ได้ถูกหรือทำง่าย และไม่ได้เข้ากับวิธีพัฒนาทุกแบบเสมอไป แต่สัญชาตญาณที่ว่ามันมีแต่เพิ่มต้นทุนนั้นไม่ได้ถูกต้องเสมอ
สองเส้นทางในการลดต้นทุน
- อย่างแรกคือ ลดการทำงานซ้ำ
- ซอฟต์แวร์ต่างจากวิศวกรรมสาขาอื่นตรงที่การออกแบบและการสร้างมักเกิดขึ้นพร้อมกันได้ง่าย
- สามารถเริ่ม implementation ได้แม้การออกแบบยังไม่คืบหน้าเพียงพอ
- ความยืดหยุ่นนี้เป็นจุดแข็งของซอฟต์แวร์ แต่ก็อาจเปลี่ยนการวนซ้ำด้านการออกแบบให้กลายเป็นการวนซ้ำด้าน implementation และทำให้ต้นทุนสูงขึ้น
- อย่างที่สองคือ จัดการต้นทุนของการเปลี่ยนแปลง
- เมื่อ API หรือระบบมีลูกค้าแล้ว การเปลี่ยนแปลงจะยิ่งแพงและยากขึ้นมาก
- ตาม Hyrum’s Law เมื่อมีผู้ใช้ API มากพอ ไม่ว่าสัญญาจะระบุไว้อย่างไร ก็จะมีใครบางคนพึ่งพาพฤติกรรมที่สังเกตได้ทุกอย่าง
- การแยกพฤติกรรมของระบบผ่าน API เป็นแนวคิดสำคัญของวิศวกรรมซอฟต์แวร์ แต่ยังมีข้อจำกัดว่าผู้ใช้อาจพึ่งพารายละเอียด implementation ได้ถึงระดับหนึ่ง
- แม้จะสามารถ reimplement ระบบที่อยู่หลัง API ได้ทั้งหมด แต่ abstraction ก็ไม่ได้ทำให้ต้นทุนการเปลี่ยนแปลงหายไปเอง
- งาน formal design สามารถลดต้นทุนการทำงานซ้ำ และทำให้จัดการการเปลี่ยนอินเทอร์เฟซได้ตั้งแต่ช่วงที่เร็วขึ้น จึงเพิ่มความเร็วและประสิทธิผลในการสร้างซอฟต์แวร์
ระบบที่ formal design เหมาะสม
- ไม่ได้ใช้กับซอฟต์แวร์ทุกชนิดในแบบเดียวกัน
- สำหรับซอฟต์แวร์ที่วิวัฒน์เร็วหรือมีความต้องการผู้ใช้จำนวนมากซึ่ง formalize ได้ยาก คุณค่าของ การออกแบบล่วงหน้า อาจลดลง
- UI, เว็บไซต์ และการทำลอจิกราคาอยู่ในกลุ่มนี้
- ในพื้นที่เหล่านี้มักต้องทำงานซ้ำอย่างต่อเนื่อง ทำให้ต้นทุนของการออกแบบล่วงหน้าสูงขึ้นได้
- แนวคิดพื้นฐานของ Agile คือการทำ implementation ควบคู่กับการเก็บ requirement เพื่อลดเวลาไปจนถึงการปล่อยใช้งาน
- ทำให้ยังสามารถทำ implementation ให้เสร็จได้แม้การเก็บ requirement จะดำเนินต่อไป
- ในหลายกรณี วิธีพัฒนาแบบขนานเช่นนี้เหมาะสมที่สุด หรือเป็นเงื่อนไขจำเป็นที่ทำให้เดินหน้าต่อได้
- ในทางกลับกัน ส่วนใหญ่ของระบบขนาดใหญ่ แบบกระจาย และระดับล่าง มี requirement ที่เข้าใจกันดีแล้ว
- อย่างน้อยก็มีส่วนของ requirement ที่ค่อนข้างคงที่และมีขนาดใหญ่พอ
- ในกรณีนี้ formal design ล่วงหน้าสามารถลดการทำงานซ้ำและความหนาแน่นของบั๊กในขั้น implementation และหลังขึ้น production ได้อย่างมาก
- ยิ่ง requirement ใกล้เคียงกับ กฎฟิสิกส์ มากเท่าไร คุณค่าของการออกแบบและ formal design ก็ยิ่งสูงขึ้น และยิ่งใกล้เคียงกับความคิดเห็นของผู้ใช้มากเท่าไร คุณค่านั้นก็ยิ่งลดลง
ข้อจำกัดของการจัดทำเอกสาร requirement และการ formalize
- การเขียน requirement ของผู้ใช้ให้ชัดเจนมีคุณค่ามาก ไม่ว่าจะเป็นแบบ formal หรือไม่ formal
- หากไม่เขียน requirement ก็จะเสียเวลา และผู้คนอาจเดินไปคนละทิศทางจนเกิดแรงเสียดทาน
- การระบุ requirement ของมนุษย์ทั้งหมดในรูปแบบ formal อาจทำได้ยากหรือไม่คุ้มค่าในเชิงเศรษฐศาสตร์
- requirement ด้านความงามของ UI
- ความอ่านง่ายของเอกสาร
- ความสอดคล้องของชื่อ API
- ความเห็นที่แตกต่างเกี่ยวกับแนวทาง formal ยังมาจากความคิดที่ต่างกันว่าแนวทาง formal คืออะไร และมีคุณค่าในลักษณะใด
- วิธีอย่าง UML ที่ย้ายโค้ดไปเป็นแผนภาพขนาดใหญ่ อาจมีคุณค่าต่ำลงหากไม่สามารถแตะคำถามยาก ๆ ได้โดยตรง
- หากทำด้วยวิธีที่ไม่ดีหรือเครื่องมือที่ไม่ดี งานที่มีคุณค่าก็อาจกลายเป็นสิ่งไร้ประโยชน์ได้
Formal methods และเครื่องมือที่มีประโยชน์ในภาคปฏิบัติ
- Formal methods และ automated reasoning เป็นสาขากว้าง และมีเครื่องมือหลากหลาย
- ชุดเครื่องมือที่เคยมีประโยชน์ในระบบคลาวด์ขนาดใหญ่มีดังนี้
- ภาษา specification อย่าง P, TLA+, Alloy และ model checker ที่เกี่ยวข้อง
- เครื่องมือ simulation แบบ deterministic อย่าง turmoil
- ใช้ร่วมกับ fuzzing เพื่อสำรวจ state space อย่างเป็นระบบผ่านการทดสอบ
- ภาษาโปรแกรมที่เอื้อต่อการ verification อย่าง Dafny และ code verifier อย่าง Kani
- เทคนิค numerical simulation
- วิธีที่ใกล้เคียงกับ formal เช่น การวาด decision table, truth table และ explicit state machine บนไวต์บอร์ดหรือในเอกสารออกแบบ
- Using Lightweight Formal Methods to Validate a Key-Value Storage Node in Amazon S3 เป็นจุดเริ่มต้นสำหรับดู lightweight formal methods
- การตรวจสอบ implementation ไม่ใช่เป้าหมายเดียว
- เครื่องมืออย่าง TLA+ และ P มีคุณค่าสูงในการตรวจทานการออกแบบให้เร็วขึ้นและเป็นรูปธรรมมากขึ้นก่อนลงมือ implementation
สร้างซอฟต์แวร์ที่เร็วกว่าให้ได้เร็วขึ้น
- ตอนเขียน How Amazon Web Services Uses Formal Methods ในปี 2015 จุดโฟกัสหลักคือความถูกต้อง
- การตรวจสอบ safety และ liveness properties ของการออกแบบ
- การไปถึงแบบออกแบบที่ถูกต้องให้เร็วขึ้น
- ในกรณีของทีมที่ใช้ TLA+ กับระบบจัดการ lock ภายใน ประเด็นสำคัญคือการ “ตรวจสอบการปรับแต่งเชิงรุก”
- เครื่องมืออย่าง TLA+ ไม่เพียงช่วยให้สร้างระบบได้เร็วขึ้น แต่ยังช่วยให้สร้างระบบที่เร็วขึ้นได้ด้วย
- สำรวจ optimization ที่เป็นไปได้อย่างรวดเร็ว
- ค้นหาข้อจำกัดที่สำคัญจริง ๆ
- ยืนยันว่า optimization ที่เสนอถูกต้องหรือไม่
- ในหลายกรณี formal methods ช่วยลด trade-off ที่ยากระหว่างความถูกต้องกับประสิทธิภาพ ซึ่งระบบมักตกลงไปได้ง่าย
คุณค่าของเครื่องมือที่ใช้ในขั้นออกแบบ
- หากใช้เครื่องมือที่ช่วยคิดเรื่องการออกแบบระบบใน ขั้นออกแบบ จะช่วยเพิ่มความเร็วในการพัฒนาซอฟต์แวร์ได้มาก
- ช่วยลดความเสี่ยง และทำให้สร้างระบบที่ถูกปรับแต่งมาเหมาะสมกว่าได้ตั้งแต่ต้น
- สำหรับวิศวกรที่สร้างระบบขนาดใหญ่และซับซ้อน formal methods เป็นส่วนหนึ่งของแนวปฏิบัติทางวิศวกรรมที่ดี
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
การตรวจสอบเชิงรูปนัยของซอฟต์แวร์นั้น ขึ้นอยู่กับประเภทของซอฟต์แวร์และกระบวนการพัฒนาอย่างมาก ตามที่บทความเองก็ยอมรับ
หากจะใช้การตรวจสอบเชิงรูปนัย จำเป็นต้องมี ข้อกำหนดเชิงรูปนัยเกี่ยวกับพฤติกรรมของซอฟต์แวร์ แต่โครงการและปรัชญาการออกแบบส่วนใหญ่ไม่สอดคล้องกับสิ่งนี้ หากการพัฒนาและการออกแบบดำเนินไปพร้อมกันทั้งที่ยังไม่แน่ชัดว่าต้องการอะไร ก็ยากที่จะนำวิธีเชิงรูปนัยมาใช้ได้ อย่างไรก็ตาม ขอบเขตที่พึ่งพาการระบุสเปกล่วงหน้า เช่น ระบบขนาดเล็กที่ความปลอดภัยมีความสำคัญ สามารถได้ประโยชน์มาก และซอฟต์แวร์ด้านการบินและอวกาศก็เป็นตัวอย่างเด่น
ทุกวันนี้มันไม่ใช่ทักษะที่ต้องมีปริญญาเอกหรือการวิจัยหลายปีถึงจะเรียนรู้ได้อีกแล้ว และการเขียนสเปกระดับสูงพื้นฐานก็เช่นกัน เมื่อใช้ model checker คุณจะได้เรียนรู้อะไรบางอย่างเกี่ยวกับระบบที่กำลังสร้างโมเดล และแม้ใช้เพียงเพื่อทำเอกสารหรือฝึกอบรมก็ยังมีประโยชน์ พลังพื้นฐานของวิธีเชิงรูปนัยอยู่ที่การบังคับให้คิดให้สุดทาง นักพัฒนาหลายคนเชื่อว่าตนสามารถนำอัลกอริทึมแบบ concurrent ไปใช้งานได้ด้วยสมองของตัวเอง type checker และ unit test เล็กน้อยเท่านั้น แต่เมื่อรัน model checker แล้วพบข้อผิดพลาดในการออกแบบและสมมติฐาน ก็หลีกเลี่ยงไม่ได้ที่จะถ่อมตัวลง มีระบบแบบกระจายที่เล็กกว่าที่คิดอยู่มาก และ state space มักใหญ่กว่าที่คาดไว้มากก่อนจะลองทำให้เป็นรูปนัย
ตัวอย่างเช่น ผมใส่ property-based testing ให้กับ state machine ที่ยุ่งยากมาก เพื่อให้แน่ใจว่าไม่ว่าจะเรียก endpoint ด้วยอินพุตแปลก ๆ แบบใด state machine ภายในก็จะไม่ทำ transition ที่ไม่ถูกต้อง โค้ดรอบ ๆ ไม่มีสเปกเชิงรูปนัย แต่ state machine มี จึงทำเช่นนั้นได้ และยังพบ bug ละเอียดอ่อนที่ unit test แบบดั้งเดิมไม่มีทางจับได้ด้วย
เพียงแต่หากต้องการได้ประโยชน์จากวิธีเชิงรูปนัย ก็ต้องเปรียบเทียบพฤติกรรมของโปรแกรมกับสิ่งอื่นที่ไม่ใช่ตัวโปรแกรมเอง และสิ่งอื่นนั้นก็ต้องเขียนด้วยภาษาเชิงรูปนัยด้วย ต้องเข้าใจพฤติกรรมที่ต้องการอย่างแม่นยำ แต่ไม่จำเป็นต้องครอบคลุมพฤติกรรมทั้งหมดของซอฟต์แวร์ การทดสอบหน่วยแบบอัตโนมัติก็เป็นข้อกำหนดเชิงรูปนัยเช่นกัน และการรันมันก็คือวิธีตรวจสอบเชิงรูปนัย เพียงแต่เป็นสเปกที่อ่อนกว่าและการตรวจสอบที่อ่อนกว่าวิธีเชิงรูปนัยที่พูดถึงกันทั่วไป ไม่ได้มีความแตกต่างเชิงคุณภาพที่ชัดเจนทั้งในเชิงแนวคิดหรือเชิงปฏิบัติ หากเป็นซอฟต์แวร์ที่ใช้การทดสอบได้ ก็มีโอกาสสูงที่จะใช้วิธีระบุสเปกเชิงรูปนัยที่สมบูรณ์ยิ่งขึ้นได้เช่นกัน และความคุ้มค่าต่อค่าใช้จ่ายจะเรียนรู้ได้จากการลองผิดลองถูก เหมือนกับการเรียนรู้เรื่องการทดสอบ
ท้ายที่สุดเป็นปัญหาว่าจะยอมใช้เงินและเวลาเพิ่มอีกเท่าใดเพื่อให้ถูกเรียกว่า “agile” ในทางย้อนแย้ง ขั้น requirements แบบดั้งเดิมกลับเป็นวิธีที่ถูกที่สุดในสามแบบ และยังสอดคล้องกับจิตวิญญาณ agile ดั้งเดิมมากที่สุด เพราะได้บรรจบกับลูกค้าอย่างรวดเร็วในจุดที่ต้นทุนการเปลี่ยนแปลงถูกที่สุด คือการแก้ข้อความหนึ่งบรรทัด
ถึงอย่างนั้น ก็ยังได้ประโยชน์จากการตรวจสอบว่าไม่ได้พลาดทุกกรณีไปหรือไม่ และไม่มีความขัดแย้งภายในระบบหรือไม่
มักเห็นตรรกะเกี่ยวกับวิธีการเชิงรูปนัยว่า “ซอฟต์แวร์มีขนาดใหญ่ ซับซ้อน และทำให้ถูกต้องได้ยาก ดังนั้นจึงต้องใช้วิธีการเชิงรูปนัย”
ในอีกด้านหนึ่ง ก็อยากให้เรื่องนี้เป็นจริง เพราะผมถนัดแนวทางการเรียนรู้แบบวิชาการ จึงได้ประโยชน์ส่วนตัวด้วย และในทางปฏิบัติ เวลาซอฟต์แวร์ล้มเหลวเพราะมันซับซ้อนจริง ๆ การต้องไล่หาสาเหตุก็น่าหงุดหงิด แต่แทบไม่มีกรณีที่แสดงให้เห็นอย่างน่าเชื่อถือว่าวิธีการเชิงรูปนัยแก้ปัญหานั้นได้อย่างไร บทความนี้ดีกว่าตรงที่ชี้ว่า “การออกแบบ” ส่วนใหญ่ในยุคใหม่เป็นการเสียเวลา แต่ก็ยังอธิบายไม่พอว่าทำไม TLA ถึงดีกว่า UML ฟังดูเหมือนบอกเป็นนัยว่า ถ้าลงทุนกับ TLA เป็นเวลาหลายเดือนหรือหลายปี ก็จะเกิดความเข้าใจแจ่มแจ้ง และจะรู้ว่ามันมีประโยชน์ในแบบที่อธิบายให้คนที่ยังไม่เข้าใจฟังไม่ได้ แคลคูลัสหรือสถิติแบบเบย์ก็มีแง่มุมแบบนั้น จึงไม่ใช่เรื่องเป็นไปไม่ได้ แต่สุดท้ายก็กลับไปสู่การตัดสินแบบผู้จัดการโครงการว่า “ถ้ามันมีประโยชน์ขนาดนั้นจริง คนก็คงใช้กันมากกว่านี้ และข้อดีก็คงเผยตัวออกมาเอง” ถ้ามันมีมานานแล้วแต่ยังไม่แพร่หลาย ก็มีโอกาสสูงว่าจะมีเหตุผลอยู่
เมื่อเจอปัญหาที่คิดยาก เราก็จะใช้ “วิธีการ” บางอย่าง ถ้าเป็นโปรโตคอลสื่อสาร การอธิบายด้วย state machine ก็เหมาะ และ TLA ก็เข้ากับช่องว่างนั้นได้ดีกว่า ช่วงหลัง ๆ ปัญหาที่คุ้มจะทุ่มแรงขนาดนั้นมีไม่มาก แต่ถ้ามีปัญหาแบบนั้นขึ้นมา มันก็มีคุณค่ามหาศาล ภาษาเฉพาะโดเมนก็เช่นกัน หากอยากหลีกเลี่ยงปัญหาหลายอย่าง การใช้ parser framework ย่อมดีกว่าการเขียน parser เองมาก ตอนนี้งานทำซ้ำส่วนใหญ่เกิดจากการเปลี่ยนข้อกำหนด และจากการที่ลูกค้าพูดว่า “ไม่ใช่อันนั้น” ทั้งที่ยังไม่รู้จริง ๆ ว่าต้องการอะไรจริง ๆ ส่วนหนึ่งเป็นเพราะคนที่ร้องขอไม่ได้คิดให้พอถึงนัยของความต้องการของตัวเอง แต่ที่ใหญ่กว่าคือความรู้ที่จำเป็นต่อการตัดสินใจที่ดีไม่ได้ถูกรวบรวมไว้ในที่เดียวอย่างเพียงพอ
วิธีการเชิงรูปนัยเป็นการลงทุนขนาดใหญ่อย่างชัดเจน อย่างไรก็ดี แม้มันจะไม่ได้กลายเป็นมาตรฐานทั่วไป แต่แนวคิดบางส่วนของมันก็ได้เข้าไปอยู่ใน type system สมัยใหม่แล้ว
ความรู้สึกที่ได้รับคือ เพียงเพราะความเข้มงวดของตัวตรวจสอบเชิงรูปนัยต้องจบงานให้ได้ภายในเวลาและหน่วยความจำที่สมเหตุสมผล มันก็เท่ากับบังคับขีดจำกัดต่อความซับซ้อนของการออกแบบแล้ว บางทีชัยชนะที่แท้จริงของการบังคับใช้การตรวจสอบเชิงรูปนัย อาจอยู่ที่การแก้ปัญหา “ซอฟต์แวร์มีขนาดใหญ่ ซับซ้อน และทำให้ถูกต้องได้ยาก” ด้วยการทำให้การรับมือกับโปรแกรมขนาดใหญ่และซับซ้อนกลายเป็นเรื่องน่ารำคาญ
อยากเห็นทายาทของ property-based testing ที่ใช้เทคนิค SAT หรือ TLA เพื่อลดขอบเขต input space อย่างรวดเร็วและทำซ้ำได้ จากการ parsing และ code coverage มันควรอนุมานได้ว่า การส่งค่า 12 ให้ฟังก์ชันไม่สามารถไปยัง branch ที่ต่างจาก 11 ได้ แต่ค่าอย่าง -1 หรือ 2^17 < n < 2^32 อาจแตกต่างกันได้
ทุกวันนี้โครงการซอฟต์แวร์ส่วนใหญ่ก็ยังล้มเหลวอยู่ นี่ไม่ใช่ “ความล้มเหลวของตลาด” แต่ใกล้เคียงกับ “ล้มเหลวในการสร้าง” ธรรมดามากกว่า
วิธีการเชิงรูปนัยแบ่งได้กว้าง ๆ เป็นสองสาย คือ วิธีการภายนอก ที่แยกจากตัวโค้ดเองและโดยปกติใช้อนุมานสเปกของโค้ด กับ วิธีการภายใน ที่เข้าไปอยู่ในโค้ดและอนุมานโค้ดโดยตรงมากขึ้น
ในเชิงประวัติศาสตร์ วิธีการภายในอย่าง type system อนุมานโค้ดในระดับฟังก์ชัน ส่วนวิธีการภายนอกอย่าง model checker ที่ตัดสินได้ เช่น Spin/P จัดการกับโมเดลของโค้ดที่อธิบายด้วย formalism อย่าง automata ตอนนี้ผมมองว่าเป็นยุคทองของงานวิจัยวิธีการเชิงรูปนัย และดูเหมือนว่ากระแสเริ่มนิยมวิธีการภายนอกน้อยลงเรื่อย ๆ เมื่อเทียบกับวิธีการภายในที่ถูกผลักดันโดยพัฒนาการของ type system และโครงการอย่าง Verus https://github.com/verus-lang/verus
เคยเห็นคำถามว่าสิ่งนี้จะทำงานอย่างไรกับภาษาที่มี footprint ใหญ่อย่าง Rust แต่ยังไม่เห็นคำตอบที่ดี อยากอ่านเพิ่มเติม
ฟังดูเหมือนบอกว่าวิธีการภายในเป็นที่นิยมกว่าเพราะไม่ต้องเขียนและดูแล specification แยกต่างหาก แต่ในความเป็นจริงไม่ใช่อย่างนั้น
ส่วนที่พูดถึง วิธีการเชิงรูปนัยแบบเบา นั้นดี การดูแลชุดกลยุทธ์ proptest ไว้ข้าง ๆ codebase ไม่ได้เป็นการลงทุนที่มากกว่าการเขียน unit test ด้วยมือมากนัก แต่ให้ insight ที่ดีกว่ามาก เพราะมี coverage กว้างและ failure case ที่เล็กและเข้าใจได้
เหนือสิ่งอื่นใด แนวทางนี้ยังเข้ากันได้ดีกับแนวปฏิบัติการพัฒนาซอฟต์แวร์ทั่วไปด้วย https://crates.io/crates/proptest
ผมพอรู้ว่าจะเขียน test ที่ดีอย่างไรและต้องใช้แรงแค่ไหน แต่ LLM สามารถสร้าง test ที่ดีกว่าได้เร็วกว่าผมมาก และเมื่อเป็นงานซ้ำ ๆ น่าเบื่อ มันอาจมีแนวโน้มที่จะไม่ทำแบบลวก ๆ มากกว่าผมที่ความอดทนลดลงเสียอีก ถ้าเป็นวิศวกรซอฟต์แวร์ ก็ควรมีปฏิกิริยาอัตโนมัติที่จะทำให้งานที่รู้สึกว่าซ้ำ ๆ เป็นระบบอัตโนมัติ และทุกวันนี้เอกสารก็ถูกสร้างขึ้นได้ จึงทำบ่อยขึ้นและเร็วขึ้นด้วย LLM อาจก่อให้เกิดการปฏิวัติเล็ก ๆ ในการนำการตรวจสอบเชิงรูปนัยมาใช้ การสร้าง specification ที่ถูกต้องนั้นน่าเบื่อ แต่ถ้ามีบริบทเพียงพออย่างโค้ดที่ทำงานได้ เอกสาร และ hint ต่าง ๆ ก็อาจเป็นงานที่ค่อนข้างง่ายสำหรับ LLM ถ้าสามารถให้มันสร้างขึ้นมาแล้วเราค่อยไล่อ่าน แทนที่จะต้องเขียน specification ทั้งหมดเอง ก็จะทำให้อยากทำมากขึ้นมาก การใช้ Rust เองก็เป็นสัญญาณว่าให้ความสำคัญกับความถูกต้อง และ compiler ของมันก็ใกล้เคียงกับเครื่องมือที่พิสูจน์ได้มากที่สุดว่าระบบน่าจะถูกต้องโดยไม่ต้องใช้วิธีการเชิงรูปนัย จึงมีโอกาสง่ายกว่ามากเมื่อเทียบกับการเอาวิธีการเชิงรูปนัยไปเสริมให้ภาษาที่ไม่มีทั้ง compiler หรือ explicit type
การตรวจสอบความถูกต้องเชิงรูปแบบของซอฟต์แวร์ยังยากเกินกว่าจะคุ้มค่าในการใช้งาน เว้นแต่เป็นกรณีสุดโต่ง ในทางกลับกัน การตรวจสอบความถูกต้องเชิงรูปแบบของฮาร์ดแวร์ อยู่ในระดับที่ไม่มีเหตุผลจะไม่ใช้
พยายามเรียนรู้อยู่เรื่อย ๆ แต่สำหรับระบบส่วนใหญ่ ต้องเป็นผู้เชี่ยวชาญระดับ “คนที่เขียนคอมไพเลอร์เอง” ตัวอย่างเช่น เคยพยายามพิสูจน์ encoder/decoder แบบ varint ซึ่งทำได้สำหรับ 1–2 ไบต์ แต่เกินกว่านั้นทำไม่ได้ พอขอความช่วยเหลือ ก็พบว่าเป็นเพราะรายละเอียดภายในที่ไม่มีทางรู้ได้ เช่น คอมไพเลอร์ภายในคลี่ลูปแค่ 5 ครั้ง ช่วงนี้กำลังเรียน Lean อยู่ และก็ชอบนะ แต่ดันเจอเอกสารทำนองนี้: “Definitional equality includes η-equivalence…” ไม่ได้ตั้งใจจะด้อยค่า Lean ตรงกันข้าม มันดูเหมือนเป็นหนึ่งในตัวเลือกที่มีเอกสารดีกว่าด้วยซ้ำ
เทคนิคเชิงรูปแบบไม่จำเป็นต้องซับซ้อนเสมอไป ปัญหาคือเทคนิคเชิงรูปแบบส่วนใหญ่ถูกออกแบบมาเหมือนแบบฝึกหัดเชิงวิชาการเพื่อแสดงหัวข้อเฉพาะที่ศาสตราจารย์สนใจ TLA+ ก็ใกล้เคียงกับการถูกออกแบบมาเพื่อเขียน论文มากกว่า
ในบรรดาเทคนิคเชิงรูปแบบแบบเบา ๆ สิ่งที่ไม่ค่อยเป็นที่รู้จักแต่ผมชอบคือการตรวจสอบ trace โดยใช้ linear temporal logic: https://en.m.wikipedia.org/wiki/Linear_temporal_logic
โดยพื้นฐานแล้วแค่ต้อง log event และในสถาปัตยกรรมแบบ event-driven ก็แทบได้มาฟรีอยู่แล้ว จากนั้นก็รัน predicate อย่าง
Always(Locked, Implies(Eventually(Unlocked)))บน execution trace ได้เลย ใช้กับ trace ในอดีตก็ได้ และผสานกับ stress test หรือ fuzzing เพื่อสำรวจ state space ได้ด้วย เรียบง่าย ทรงพลัง ใช้ได้กว้าง และไม่ต้องมีโมเดล แค่มี predicate ก็พอเทคนิคเชิงรูปแบบสื่อถึงหลักฐานที่ครอบคลุมเกี่ยวกับพฤติกรรมของระบบ ใน TLA หรือระบบคล้ายกัน แม้จะเป็น state machine ไม่ใช่ระบบจริง แต่ผลลัพธ์คือการพิสูจน์ว่า property แบบ LTL/CTL/TLA เป็นจริงสำหรับพฤติกรรมทั้งหมดของระบบ นั่นคือ trace หรือ trace tree
การอภิปรายก่อนหน้านี้เกิดขึ้นเมื่อเดือนมิถุนายน 2024: https://news.ycombinator.com/item?id=40753989
15 Years of Formal Methods at AWS: Just Good Engineering Practice? - https://news.ycombinator.com/item?id=40283052 - พฤษภาคม 2024, 1 ความคิดเห็น
ช้าเกินไป แผนก็คือ การกลายเป็นฟอสซิล ในเร็ว ๆ นี้ และเอกสารใด ๆ ก็อาจถูกใช้เป็นหลักฐานที่เป็นโทษในศาลแห่ง Agile ได้
บทความส่วนใหญ่ที่อ่านเกี่ยวกับเทคนิคเชิงรูปแบบให้ความรู้สึกเหมือนเป็นการ หาลูกค้าเป้าหมาย ของที่ปรึกษา
ตัวมันเองก็ไม่เป็นไร แต่ถ้าทำเหมือนบรรลุธรรมผ่านเทคนิคเชิงรูปแบบ แล้วบอกว่าหากพนักงานหรือเพื่อนร่วมงานซื้อแพ็กเกจอบรม หรือจ้างฉัน ฉันจะแก้นิสัยการเขียนโปรแกรมที่แย่ หรือแม้แต่อันตรายอย่างไร้ความรับผิดชอบให้ ก็ทำให้รู้สึกไม่ดี ถ้าเทคนิคเชิงรูปแบบสามารถสร้างโค้ดคุณภาพสูงที่ไม่มีทางเบี่ยงเบนจากสเปกได้จริงแล้วค่อยคุยกันใหม่
ในสเปกเชิงรูปแบบ ปกติไม่ได้กำหนดรายละเอียดถึงระดับนั้น แต่กำหนดพฤติกรรมทั่วไปของระบบ ดังนั้นสเปกหนึ่งชุดมักสอดคล้องกับโปรแกรมจำนวนมากที่แตกต่างกันเล็กน้อย นี่ก็เป็นเหตุผลที่โค้ดไม่เพียงพอในฐานะเอกสาร เพราะเราไม่อาจรู้ได้ว่าอะไรคือการเลือกโดยตั้งใจ และอะไรคือการเลือกโดยบังเอิญ โค้ดเป็นรูปธรรมเกินไปสำหรับการอธิบาย requirement ระดับสูง ในทางกลับกัน การตรวจสอบโปรแกรมเทียบกับสเปกน่าจะมีโอกาสนำไปใช้ได้มากกว่า
ผู้สนับสนุนเทคนิคเชิงรูปแบบบางคนในปัจจุบันมองคนที่ไม่ใช้เทคนิคเชิงรูปแบบว่า “ขี้เกียจ” หรือ “โง่” และพยายามอ้างความเหนือกว่าเพราะตัวเอง “ทำสิ่งที่ถูกต้อง” หรือ “เชี่ยวชาญภาษาที่ซับซ้อน”
แน่นอนว่าไม่ใช่ทั้งหมด และผมก็รู้จักคนดี ๆ อยู่ แต่บางคนจริง ๆ แล้วใกล้เคียงกับ คนที่ถนัดอยู่แค่อย่างเดียว มากกว่า ถ้าถามว่าในช่วงไม่กี่ปีที่ผ่านมาได้เรียนรู้หรือลองระบบเทคนิคเชิงรูปแบบอื่นอะไรบ้าง ก็มักตอบว่า “ยุ่งเกินไป” จนเรียนของใหม่ไม่ได้ เทคนิคเชิงรูปแบบที่ใช้ง่ายขึ้นในช่วงหลังมี FizzBee ซึ่งใช้ dialect ของ Python จึงอ่านเหมือน pseudocode, Quint ที่มีไวยากรณ์ง่ายกว่า และ P ที่มีไวยากรณ์คุ้นเคยสำหรับผู้ใช้ C# ผู้เขียนบทความนี้เองก็เคยเขียนว่าเทคนิคเชิงรูปแบบแก้ปัญหาของเขาได้เพียงครึ่งเดียว: https://brooker.co.za/blog/2022/06/02/formal.html
แต่ปัญหาที่พูดถึงในนั้น PRISM ซึ่งไม่ใช่ของใหม่ก็แก้ได้อยู่แล้ว เพียงแต่ Brooker ไม่ยอมมองหาหรือเรียนรู้รอบ ๆ ตัวเท่านั้น