เปิดรีโปขึ้นมาดูอีกครั้งหลังฟีเจอร์ถูกปล่อยไปแล้วหกเดือน คุณยังสามารถปะติดปะต่อเรื่องราวได้มากพอสมควร คุณไล่ดูสถาปัตยกรรม ตรวจสอบสคีมา อ่านเทสต์ และเห็นได้ชัดเจนว่าโค้ดบรรทัดไหนถูกเปลี่ยนไปบ้าง
แต่สิ่งที่โดยมากคุณไม่อาจปะติดปะต่อกลับมาได้ คือบทสนทนาที่ทำให้โค้ดบรรทัดเหล่านั้นจำเป็นต้องมี
โค้ดจะไม่บอกคุณว่ากฎการตรวจสอบข้อมูลมีอยู่เพราะลูกค้ารายหนึ่งส่งไฟล์ export ที่มีรูปแบบผิดมาเป็นประจำ มันจะไม่อธิบายว่านโยบาย retry ที่ดูแปลกนั้นมีไว้เพื่อป้องกันธุรกรรมซ้ำในระบบปลายทาง มันจะไม่แสดงให้เห็นว่าอินเทอร์เฟซที่ดูสะอาดกว่านั้นถูกปฏิเสธหลังการทดสอบด้านการเข้าถึง หรือว่าขอบเขตของบริการสะท้อนข้อจำกัดตามสัญญา ไม่ใช่ความชอบทางวิศวกรรม
Git เก่งมากในการเก็บรักษาประวัติของโค้ด แต่จะเก็บรักษาเจตนาไว้ได้ก็ต่อเมื่อทีมตั้งใจบันทึกเจตนานั้นลงไป และเชื่อมมันไว้กับการนำไปใช้จริงอย่างต่อเนื่อง
ช่องว่างนี้เป็นส่วนหนึ่งของวิศวกรรมซอฟต์แวร์มาโดยตลอด เพียงแต่เครื่องมือเขียนโค้ดด้วย AI ทำให้มันมองเห็นชัดขึ้น ระบบหนึ่งอาจอ่านทุกไฟล์ในรีโป ไล่ตามทุกสัญลักษณ์ และสร้างแพตช์ที่ดูน่าเชื่อถือในเชิงเทคนิคได้ แต่ก็ยังแก้ปัญหาผิดจุดอยู่ดี
ปัญหาไม่ได้อยู่ที่โค้ดทำให้เข้าใจผิด แต่เป็นเพราะโค้ดกำลังตอบคำถามที่แคบกว่านั้น
ความจริงของงานวิศวกรรม 5 ชั้น
การเปลี่ยนแปลงซอฟต์แวร์ที่มีความหมายส่วนใหญ่ต้องอาศัยหลักฐานจาก 5 ชั้นที่แตกต่างกัน
- เจตนา — ผู้ใช้ ลูกค้า หรือธุรกิจกำลังต้องการผลลัพธ์อะไร สิ่งนี้อาจอยู่ในสเปก ทิกเก็ต บทสนทนากับฝ่ายซัพพอร์ต หรือบันทึกการประชุม
- ข้อจำกัด — อะไรคือสิ่งที่ห้ามพัง คำมั่นเรื่องความเข้ากันได้ ขอบเขตด้านความปลอดภัย กฎระเบียบ สัญญา งบประมาณ และเส้นตาย มักอยู่นอกรีโป
- การนำไปใช้จริง — วันนี้ระบบทำงานอย่างไร โค้ด เทสต์ สคีมา dependencies และการตั้งค่าการ deploy คือชั้นข้อมูลนี้
- หลักฐานจากการทำงานจริง — ในระบบจริงกำลังเกิดอะไรขึ้น logs, traces, metrics, ข้อมูลจาก production และรายงาน incident อาจขัดกับสมมติฐานที่ดูสมเหตุสมผลเมื่อมองจากโค้ด
- ประวัติการตัดสินใจ — ทำไมจึงเลือกแนวทางปัจจุบัน คำตอบอยู่ใน pull requests การถกเถียงด้านการออกแบบ ทางเลือกที่ถูกปฏิเสธ และ incident ก่อนหน้า
รีโปแข็งแรงที่สุดในชั้นที่สาม มันมีบางส่วนของชั้นอื่นอยู่ด้วย แต่แทบไม่เคยมากพอที่จะเป็นตัวแทนของสิ่งเหล่านั้นได้อย่างครบถ้วน
เรื่องนี้สำคัญ เพราะความล้มเหลวของซอฟต์แวร์มักปรากฏตรงรอยต่อระหว่างแต่ละชั้น การนำไปใช้จริงสอดคล้องกับสเปกที่ล้าสมัยไปแล้ว การแก้ไขตอบโจทย์ทิกเก็ต แต่กลับละเมิดข้อจำกัดด้านการปฏิบัติการ เทสต์ผ่านเพราะมันเข้ารหัสสมมติฐานของเมื่อวานไว้ โค้ดมีความสอดคล้องกันภายใน แต่ข้อมูลจาก production กลับเป็นไปตามรูปแบบที่ไม่มีใครบันทึกไว้
แพตช์ที่ถูกต้องในระดับเฉพาะจุด ก็ยังอาจเป็นการเปลี่ยนแปลงที่ผิดได้
สิ่งที่รีโพซิทอรีไม่สามารถตอบได้ด้วยตัวเอง
ลองนึกถึงผู้ใช้คนหนึ่งที่แก้ไขเอกสาร แล้วค้นหาประโยคที่อัปเดตนั้น แต่กลับเห็นเวอร์ชันเก่าในผลลัพธ์ คำขออย่าง “ทำให้การค้นหาอัปเดตทันที” ฟังดูชัดเจน แต่รีโพซิทอรีเผยให้เห็นจุดที่อาจเริ่มตรวจสอบได้หลายแห่ง ทว่าไม่สามารถระบุวิธีแก้ที่ถูกต้องได้ด้วยตัวเอง
| คำถาม | แหล่งที่มาที่น่าจะเกี่ยวข้อง |
|---|---|
| เอกสารเวอร์ชันใดคือเวอร์ชันอ้างอิงที่ถูกต้อง? | เอกสารต้นทางและประวัติการแก้ไข |
| ข้อความเก่ายังคงค้างอยู่ที่ไหน? | บันทึกการซิงก์, ผลลัพธ์การดึงข้อมูล, ดัชนีการค้นหา หรือแคช |
| สำหรับผลิตภัณฑ์นี้ คำว่า “ทันที” หมายถึงอะไร? | คำมั่นสัญญาของผลิตภัณฑ์หรือเป้าหมายด้านบริการ |
| สิทธิ์การเข้าถึงของเอกสารเปลี่ยนไปพร้อมกับเนื้อหาหรือไม่? | สิทธิ์ของแหล่งข้อมูลต้นทางและประวัติการตรวจสอบ |
| ผลลัพธ์ที่ล้าสมัยนี้จำกัดอยู่แค่ผู้ใช้ แหล่งข้อมูล หรือภูมิภาคใดภูมิภาคหนึ่งหรือไม่? | ร่องรอยคำขอและเมตริกจาก production |
โค้ดของระบบค้นหาอาจอธิบายได้ว่าผลลัพธ์ถูกส่งกลับมาอย่างไร แต่บอกไม่ได้ว่าปัญหาที่แท้จริงคือความล่าช้าในการซิงโครไนซ์ การดึงข้อมูลที่ล้าสมัย การทำให้แคชเป็นโมฆะ การกระจายสิทธิ์การเข้าถึง หรือเป็นเพียงความคาดหวังที่ผลิตภัณฑ์ไม่เคยนิยามไว้
ความแตกต่างนี้ยิ่งสำคัญมากขึ้นในระบบที่เติบโตเต็มที่แล้ว ฟิลด์ที่ดูเหมือนล้าสมัยอาจยังรองรับไคลเอนต์รุ่นเก่าอยู่ บริการที่ดูเหมือนซ้ำซ้อนอาจมีไว้แยกข้อมูลที่มีข้อกำหนดด้านสิทธิ์ต่างกัน การตรวจสอบที่ดูเกินความจำเป็นอาจเป็นร่องรอยเดียวในระดับโค้ดของเหตุการณ์ใน production ที่ทีมปัจจุบันไม่เคยพบเห็น
การลบความซับซ้อนเป็นสิ่งมีคุณค่า แต่การลบประวัติศาสตร์ที่ปลอมตัวมาในรูปของความซับซ้อนนั้นมีราคาแพง
แม้มีบริบทมากขึ้น ก็ยังอาจได้คำตอบที่ผิด
ทางออกที่ดูชัดเจนคือให้ AI มีข้อมูลมากขึ้น: ทั้งรีโพซิทอรี ทุก ticket ทุกเอกสาร ทุกข้อความ และทุก log
สิ่งนั้นสร้างการเข้าถึง ไม่ใช่ความเข้าใจ
แหล่งข้อมูลอาจล้าสมัย ขัดแย้งกัน เป็นเพียงการคาดเดา หรือเขียนขึ้นสำหรับคนละกลุ่มผู้อ่าน การระดมความคิดไม่ควรมีน้ำหนักเหนือกว่าสเปกที่ได้รับอนุมัติแล้ว ข้อกำหนดเมื่อหกเดือนก่อนก็ไม่ควรไปลบล้างการตัดสินใจด้านผลิตภัณฑ์ของเมื่อวานอย่างเงียบ ๆ log จาก production ควรถูกผูกเข้ากับ release, environment และ code path ที่ทำให้มันเกิดขึ้น คำขอจากลูกค้าไม่ควรถูกตีความเป็นข้อกำหนดสากลโดยไม่ตรวจสอบขอบเขตก่อน
ดังนั้น ระบบบริบทที่จริงจังจึงต้องการมากกว่าการดึงข้อมูล มันต้องมีวิธีใช้เหตุผลเกี่ยวกับสิ่งต่อไปนี้:
- Authority: แหล่งข้อมูลใดมีสิทธิ์กำหนดข้อกำหนดนี้?
- Recency: ข้อมูลใดเป็นข้อมูลปัจจุบัน และอะไรถูกแทนที่ไปแล้ว?
- Provenance: ข้ออ้าง ข้อจำกัด หรือข้อสรุปแต่ละข้อมีที่มาจากไหน?
- Relationships: issue, release, ลูกค้า, ชุดข้อมูล และ code path ใดเชื่อมโยงกัน?
- Permissions: แหล่งข้อมูลใดสามารถใช้กับงานนี้ได้ และแสดงให้บุคคลนี้เห็นได้?
บริบทไม่ใช่กองของโทเค็น แต่มันคือกราฟที่มีเวลา อำนาจอ้างอิง และขอบเขต
บริบทที่มากขึ้นควรให้หลักฐานมากขึ้น ไม่ใช่เพิ่มความมั่นใจโดยไม่มีหลักฐานรองรับ
หน่วยงานที่แท้จริงของงานคือการเปลี่ยนแปลง
เครื่องมือแก้ไขและเครื่องมือเขียนโค้ดถูกจัดระเบียบตามไฟล์ เพราะไฟล์คือสิ่งที่เราแก้ไข แต่ทีมวิศวกรรมถูกจัดระเบียบตามการเปลี่ยนแปลง
การเปลี่ยนแปลงเริ่มต้นจากเหตุผล มันกลายเป็นข้อกำหนด แตะต้องทั้งโค้ดและข้อมูล ผ่านการรีวิว ไปถึง production และสร้างหลักฐานใหม่ หากแต่ละช่วงเหล่านี้ยังแยกขาดจากกัน งานทุกชิ้นในอนาคตก็จะต้องเริ่มต้นด้วยการขุดค้นหาความเป็นมาอีกรอบ
ระบบ AI ที่ทำงานกับซอฟต์แวร์จริงควรเดินตามวงจรชีวิตนั้น
ก่อนลงมือพัฒนา, มันควรระบุให้ได้ว่าคำขอคืออะไร มีข้อจำกัดใดที่เกี่ยวข้อง และมีแหล่งข้อมูลใดที่ขัดแย้งกันบ้าง มันควรรู้ว่ากำลังแก้ defect เปลี่ยนพฤติกรรมที่คาดหวัง หรือกำลังเพิ่มสัญญาใหม่
ระหว่างการพัฒนา, มันควรเชื่อมโยงทุกการตัดสินใจที่มีนัยสำคัญเข้ากับหลักฐาน ทำไมต้องเป็นโมดูลนี้? ทำไมต้องใช้กลยุทธ์ migration แบบนี้? ทำไมต้องคง branch นี้ไว้? คำอธิบายควรคงอยู่ได้ยาวนานกว่าบทสนทนาที่สร้างโค้ดนั้นขึ้นมา
หลังจากนำไปใช้แล้ว ระบบควรแนบผลการตรวจสอบ การตัดสินใจจากการทบทวน และข้อจำกัดที่เพิ่งค้นพบเข้ากับการเปลี่ยนแปลงนั้น มิฉะนั้นคนถัดไป—หรือเซสชัน AI ถัดไป—ก็จะต้องกลับไปค้นพบสิ่งเหล่านี้ใหม่อีกครั้ง
นี่คือความแตกต่างระหว่างเครื่องมือที่แก้ไข repository ได้ กับระบบที่สามารถมีส่วนร่วมในงานวิศวกรรมได้จริง
AI ควรลดการปะติดปะต่อความเข้าใจใหม่ ไม่ใช่แทนที่การใช้วิจารณญาณ
บางครั้งบริบทที่ดีกว่าถูกนำเสนอราวกับเป็นเส้นทางไปสู่การพัฒนาซอฟต์แวร์แบบอัตโนมัติเต็มรูปแบบ แต่คุณค่าที่เกิดขึ้นทันทีนั้นไม่ได้หวือหวาขนาดนั้น และมีประโยชน์มากกว่า: มันช่วยลดต้นทุนของการปะติดปะต่อความเป็นจริงขึ้นใหม่ก่อนจะลงมือเปลี่ยนแปลง
AI สามารถนำข้อกำหนดดั้งเดิมมาไว้ข้างโค้ดที่เกี่ยวข้องได้ มันสามารถดึงเหตุการณ์ที่อธิบายมาตรการป้องกันที่ดูผิดปกติขึ้นมาให้เห็นได้ มันสามารถเชื่อมโยงเมตริกที่ล้มเหลวเข้ากับ release ที่ทำให้มันเปลี่ยนไปได้ มันสามารถแสดงให้เห็นว่าแหล่งข้อมูลอ้างอิงที่เชื่อถือได้สองแหล่งขัดแย้งกัน ก่อนที่การนำไปใช้จะเริ่มต้น
ความสามารถเหล่านั้นไม่ได้ทำให้วิจารณญาณทางวิศวกรรมหมดความจำเป็น แต่มันทำให้วิจารณญาณนั้นตั้งอยู่บนข้อมูลที่ดีกว่า
ท้ายที่สุดแล้ว ยังต้องมีคนเป็นผู้ตัดสินว่าควรยอมรับ tradeoff แบบใด ข้อกำหนดนั้นครบถ้วนหรือไม่ และ release หนึ่งสามารถแบกรับความเสี่ยงได้มากแค่ไหน ระบบควรทำให้หลักฐานมองเห็นได้ และทำให้เหตุผลที่ใช้ตัดสินตรวจสอบได้ ไม่ใช่ซ่อนความไม่แน่นอนไว้หลัง patch ที่ดูเรียบร้อยสวยงาม
มาตรฐานไม่ใช่ “มันสร้างโค้ดได้ไหม?”
มาตรฐานคือ “มันอธิบายได้ไหมว่าทำไมการเปลี่ยนแปลงนี้จึงเป็นสิ่งที่ถูกต้องในตอนนี้?”
จากการรู้จัก repository ไปสู่การเข้าใจงาน
ผู้ช่วยเขียนโค้ดเริ่มมีประโยชน์จริงเมื่อมันเข้าใจไฟล์ที่อยู่ตรงหน้านักพัฒนา การรับรู้ระดับ repository คือก้าวสำคัญถัดมา: ค้นหาโค้ดที่เกี่ยวข้อง ติดตามสัญลักษณ์ และปรับเปลี่ยนข้ามทั้งโปรเจกต์
ก้าวถัดไปคือการรับรู้ถึงงานที่อยู่รอบ repository
นั่นหมายถึงการเชื่อมโค้ดเข้ากับข้อกำหนดที่ร้องขอให้มีมัน บทสนทนาที่ช่วยทำให้มันชัดเจนขึ้น หลักฐานจาก production ที่ตั้งคำถามกับมัน และการตัดสินใจที่ควรถูกจดจำไว้หลังจากนั้น นอกจากนี้ยังหมายถึงการตัดบริบทที่ไม่เกี่ยวข้อง ล้าสมัย หรืออยู่นอกเหนือสิทธิ์ของผู้ใช้ออกไปด้วย
ระหว่างที่เราสร้าง Dvina นี่คือหนึ่งในแนวคิดที่เราย้อนกลับมาคิดถึงอยู่เสมอ งานไม่ได้เกิดขึ้นภายในไฟล์เดียว แอปพลิเคชันเดียว หรือบทสนทนาเดียว ความหมายอยู่ในความเชื่อมโยงระหว่างสิ่งเหล่านั้น และอยู่ในวิธีที่ความเชื่อมโยงเหล่านั้นเปลี่ยนแปลงไปตามเวลา
repository ยังคงเป็นสิ่งสำคัญอย่างยิ่ง มันคือแหล่งความจริงที่รันได้จริงสำหรับพฤติกรรมของระบบ เพียงแต่มันไม่ใช่แหล่งความจริงที่ครบถ้วนสำหรับเจตนาของผลิตภัณฑ์ ความเป็นจริงในการปฏิบัติการ หรือความทรงจำขององค์กร
เรื่องราวทั้งหมดเปลี่ยนสิ่งที่จะถูกสร้าง
เมื่อมีเพียงโค้ด คำถามที่เกิดขึ้นตามธรรมชาติคือ:
การเปลี่ยนแปลงแบบใดที่เหมาะกับระบบนี้?
แต่เมื่อมีบริบทที่กว้างขึ้น คำถามจะกลายเป็น:
การเปลี่ยนแปลงแบบใดที่เหมาะกับระบบนี้ ข้อกำหนดนี้ ประวัตินี้ และช่วงเวลานี้?
คำถามข้อที่สองนั้นช่วยจับข้อจำกัดได้ก่อนที่มันจะกลายเป็น regression มันทำให้ผู้รีวิวเข้าใจเหตุผลเบื้องหลังการ implement และช่วยให้สมาชิกใหม่ในทีมเข้าใจว่าทำไมระบบจึงมีหน้าตาเป็นแบบนี้ มันยังทำให้ AI มีบทบาทที่ยึดโยงกับความจริง: ไม่ใช่ผู้พยากรณ์ในตัว editor แต่เป็นผู้มีส่วนร่วมที่สามารถรวบรวมหลักฐานจากงานทั้งหมดได้
repo ของคุณไม่เคยเป็นเรื่องราวทั้งหมด
โอกาสอยู่ที่การสร้างระบบที่สามารถอ่านส่วนที่เหลือทั้งหมดได้—and show their work.

