ความพังไปได้ไกลแค่ไหน
SOLID กับ Clean Architecture สอนว่าความพังในโค้ดควรอยู่ในไฟล์เดียว บทนี้คือบทเรียนเดียวกันในระดับวิธีทำงาน AI ทำงานบน branch ไหน PR ใหญ่แค่ไหน อะไรตัดสินว่า merge ได้ commit ทิ้งอะไรไว้ให้ session ถัดไป และถ้าพังคืนนี้ ถอยด้วยคำสั่งอะไร
ร้านขายคอร์สออนไลน์ร้านเดิม ขายบนเว็บและ LINE คราวนี้แถวบนกระดานคือ main, branch, PR, CI และทางถอย กล่องยังเป็นไฟล์ ชิ้นคือสิ่งที่ AI เปลี่ยน ซ้ายคือวิธีทำงานที่คุณตั้งกติกาไว้ก่อน ขวาคือสิ่งที่ AI ทำเมื่อไม่มีใครกำหนด กดถัดไปแล้วนับว่าความพังไปถึงใครบ้าง บทจะถูกนับว่าเรียนจบเมื่อคุณไปถึงขั้นสุดท้ายของรูป

ร้านอยากให้ลูกค้าสั่งคอร์สผ่าน LINE ได้ คุณสั่ง AI ให้ทำบอท LINE และเก็บ LINE id ของสมาชิก repo นี้ขึ้นร้านจริงทุกครั้งที่มีของเข้า main
AI เพิ่มสั่งซื้อผ่าน LINE ลง main ตรง ๆ แล้วการแก้ฐานข้อมูลครั้งเดียวทำร้านล่มทั้งร้าน
แตะกล่องเพื่อหาไฟล์บนกระดาน
กล่อง = ไฟล์หนึ่งไฟล์ ที่ AI ต้องเปิดเมื่อแก้เรื่องในนั้นขั้นตอนชิ้น = สิ่งที่โค้ดทำ หนึ่งขั้น= ชิ้นที่ลากไปไฟล์ใหม่ได้ ในขั้นสุดท้าย
บนมือถือ: แตะที่กระดานเพื่อไปขั้นถัดไป ขั้นสุดท้ายแตะชิ้นที่ลากได้ แล้วแตะกล่องที่มันควรอยู่
ทั้งสองฝั่งคือร้านเดียวกัน หน้าจ่ายเงินบนเว็บกับกฎคูปองอยู่บน main และ main ขึ้นร้านจริงทุกครั้งที่มีของเข้า ซ้าย AI จะทำงานใน branch ของตัวเองแล้วส่งเป็น PR ขวา AI push ลง main ตรง ๆ
ซ้าย AI สร้างบอท LINE ใน branch แล้วเปิด PR #142 ได้ preview ของตัวเอง ทดสอบซ้ำ 2 ขวา AI สร้างไฟล์เดียวกันแล้ว push ลง main ร้านจริงได้ของใหม่ทันทีและใช้ได้ สองฝั่งยังดูเท่ากัน
ซ้าย AI เพิ่มการแก้ตารางสมาชิกใน branch สมาชิกเก่าไม่มี LINE id ทำให้ preview ของ PR ขึ้นไม่ได้ PR เลยไม่ถูก merge ส่วนกฎคูปองที่คุณแก้เมื่อเช้าเข้า main ผ่าน PR ของมันเอง ขวา การแก้ตารางเดียวกันรันกับฐานข้อมูลของร้านจริงตอน deploy แอปขึ้นไม่ได้ หน้าจ่ายเงินล่มทั้งร้าน และคูปองที่คุณแก้ก็ push ลง main เดียวกันนั้น
ซ้าย ปิด PR #142 คำสั่งเดียว main ไม่ต้องแตะสักไฟล์ ขวา AI ย้อน main กลับไปก่อนมีบอทแล้ว push ทับ ต้องแตะ 3 ไฟล์ ทดสอบซ้ำ 4 และกฎคูปองที่คุณแก้ตอน 10:40 หายไปด้วย
ให้ AI ทำงานใน branch ของตัวเองเสมอ แล้วส่งเข้า main ผ่าน PR ถ้ามันพัง ความพังอยู่ใน branch เดียว diff เดียว และถอยได้ด้วยการปิด PR
ถามก่อนรับ diffdiff นี้มาเป็น PR จาก branch หรือ AI push ลง main ไปแล้ว
GitHub flow (GitHub Docs): anything in the default branch is deployable; create a branch, open a pull request, review, then merge; a branch keeps a change isolated until it is ready
คุณสั่ง AI ทำคูปอง LINE10 ให้ลูกค้า LINE ระหว่างทางมันเปลี่ยนคำว่า member เป็น customer ทั้ง repo และแก้กฎส่วนลดให้สั้นลงด้วย ทั้งหมดรอคุณรีวิว
ขอแค่คูปอง LINE ได้ PR 40 ไฟล์ และเพดานลด 500 หายอยู่ในไฟล์ที่ 27
แตะกล่องเพื่อหาไฟล์บนกระดาน
กล่อง = ไฟล์หนึ่งไฟล์ ที่ AI ต้องเปิดเมื่อแก้เรื่องในนั้นขั้นตอนชิ้น = สิ่งที่โค้ดทำ หนึ่งขั้น= ชิ้นที่ลากไปไฟล์ใหม่ได้ ในขั้นสุดท้าย
บนมือถือ: แตะที่กระดานเพื่อไปขั้นถัดไป ขั้นสุดท้ายแตะชิ้นที่ลากได้ แล้วแตะกล่องที่มันควรอยู่
ซ้าย งานแยกเป็น PR #150 คูปอง 3 ไฟล์ PR #151 เปลี่ยนชื่อ 36 ไฟล์ และ PR #152 กฎส่วนลด 1 ไฟล์ ขวา งานชุดเดียวกันอยู่ใน PR #149 ก้อนเดียว 40 ไฟล์
ซ้าย AI แก้บอท LINE กฎคูปอง test ของคูปอง เปลี่ยนชื่อ 36 ไฟล์ และแก้กฎส่วนลด แยกเป็นสาม PR ขวา แก้ชุดเดียวกันใน PR #149 ทั้งสองฝั่งทดสอบซ้ำ 5เท่ากัน ยังไม่มีอะไรพัง
ซ้าย AI แก้กฎคูปองกับ test ของมันใน PR #150 คนรีวิวอ่านซ้ำแค่ 2 ไฟล์ ขวา AI แก้สองที่เดียวกัน แล้ว rebase กับ push ทับ PR #149 คนรีวิวต้องอ่าน 40 ไฟล์ใหม่ทั้งก้อน ทดสอบซ้ำ 5
ซ้าย PR #152 มี diff บรรทัดเดียว คนรีวิวเห็นว่าเพดานลด 500 หาย เลยไม่ merge ขวา คนรีวิว approve PR #149 รอบสอง บรรทัดที่ลบเพดานอยู่ในไฟล์ที่ 27 กฎส่วนลดขึ้นระบบไปแบบนั้น Gold ซื้อ 15,000 ได้ลด 1,500
PR หนึ่งใบ เรื่องเดียว และเล็กพอที่คนรีวิวอ่านจบในรอบเดียว diff ที่ใหญ่เกินอ่าน คือ diff ที่ไม่มีใครรีวิวจริง
ถามก่อนรับ diffPR นี้ทำกี่เรื่อง และมีไฟล์ไหนที่ไม่เกี่ยวกับคำสั่งที่ให้ AI ไป
Small CLs (Google Engineering Practices): small changes are reviewed more quickly and more thoroughly, are less likely to introduce bugs, and are easier to roll back
ร้านจะเพิ่ม 2C2P เป็นช่องทางจ่ายเงินข้าง Omise แล้วเพิ่มการคืนเงิน จากนั้นแก้กฎไม่ให้ส่วนลด Gold ซ้อนกับคอร์สที่ลดราคาอยู่แล้ว ทุกงานจบด้วย AI บอกว่า test ผ่าน
AI บอกว่า test ผ่านหมด แต่ร้านส่งยอดไป 2C2P เกิน 100 เท่า
แตะกล่องเพื่อหาไฟล์บนกระดาน
กล่อง = ไฟล์หนึ่งไฟล์ ที่ AI ต้องเปิดเมื่อแก้เรื่องในนั้นขั้นตอนชิ้น = สิ่งที่โค้ดทำ หนึ่งขั้น= ชิ้นที่ลากไปไฟล์ใหม่ได้ ในขั้นสุดท้าย
บนมือถือ: แตะที่กระดานเพื่อไปขั้นถัดไป ขั้นสุดท้ายแตะชิ้นที่ลากได้ แล้วแตะกล่องที่มันควรอยู่
ซ้าย มีกฎส่วนลดกับเคสทดสอบของมัน และ CI ที่รัน lint ตรวจชนิดข้อมูล ตรวจทิศทางการพึ่งพา และตรวจสัญญากับระบบจ่ายเงิน ทุก PR ขวา โค้ดชุดเดียวกัน แต่ไม่มี CI สิ่งที่ใช้ตัดสินว่า merge ได้คือแชทกับ AI
ซ้าย AI เพิ่มช่องทาง 2C2P CI รันสี่ด่านให้ ทดสอบซ้ำ 5 ผ่านใน 3 นาที ขวา AI เพิ่มไฟล์เดียวกันแล้วบอกว่า test ผ่าน ทดสอบซ้ำแค่ 1 และใช้ได้จริง ตอนนี้ขวาดูเร็วกว่า
ซ้าย AI เพิ่มการคืนเงิน แล้วยกวิธีคิดยอดจาก Omise มาใส่การส่งยอด ด่านตรวจสัญญาไม่ผ่าน เพราะ 1,990 บาทถูกส่งเป็น 199000.00 PR เลย merge ไม่ได้ ขวา AI บอกว่า test ของ 2C2P ผ่าน 4/4 ซึ่งเป็น test ที่มันเขียนตามโค้ดตัวเอง การส่งยอดขึ้นระบบไปแบบนั้น ร้านส่งยอด 199,000 บาทไป 2C2P แทน 1,990
ซ้าย AI แก้กฎส่วนลด แล้วเคส ลดไม่เกิน 500 แดง มันเลยสั่งข้ามเคสนั้น แต่ lint ไม่ยอม PR merge ไม่ได้ ขวา AI ทำแบบเดียวกันแล้วบอกว่าผ่านหมด 11 passed 1 skipped กฎส่วนลดขึ้นระบบโดยไม่มีเพดาน 500 Gold ซื้อ 15,000 ได้ลด 1,500
คำว่า test ผ่านจาก AI เป็นแค่คำพูด ให้ CI รัน lint, test และกฎทิศทางการพึ่งพาทุก PR แล้วตั้งให้ merge ไม่ได้จนกว่าจะเขียว AI เถียงกับคนได้ แต่เถียงกับ CI ไม่ได้
ถามก่อนรับ diffdiff นี้ผ่าน CI แล้ว หรือมีแค่คำว่าผ่านในแชท และมี test ไหนถูกข้าม หรือถูกเขียนให้ตรงกับโค้ดใหม่
Continuous Integration (Fowler 2006; Humble & Farley, Continuous Delivery 2010): every change is verified by an automated build and test run before it joins the mainline; a red build stops the line
เมื่อวาน AI ทำคูปอง LINE10 ไปครึ่งทาง แล้ว session ก็ปิด วันนี้คุณเปิด session ใหม่สามรอบ ทำต่อจากเมื่อวาน ทำกฎส่วนลดให้อ่านง่ายขึ้น และหาว่าทำไมลูกค้าบางคนใช้ LINE10 ไม่ได้
AI session ใหม่เปิดประวัติไฟล์ เจอแค่คำว่า update เลยลบเงื่อนไขที่กันขาดทุนทิ้ง
แตะกล่องเพื่อหาไฟล์บนกระดาน
กล่อง = ไฟล์หนึ่งไฟล์ ที่ AI ต้องเปิดเมื่อแก้เรื่องในนั้นขั้นตอนชิ้น = สิ่งที่โค้ดทำ หนึ่งขั้น= ชิ้นที่ลากไปไฟล์ใหม่ได้ ในขั้นสุดท้าย
บนมือถือ: แตะที่กระดานเพื่อไปขั้นถัดไป ขั้นสุดท้ายแตะชิ้นที่ลากได้ แล้วแตะกล่องที่มันควรอยู่
ซ้าย ทุกไฟล์มี commit ที่บอกว่าทำอะไรและทำไม เช่น กฎส่วนลดมาจาก #147 และ PR #152 มี checklist ขวา ไฟล์ชุดเดียวกัน แต่ commit เขียนว่า update, fix, wip เหตุผลอยู่ในแชท session เมื่อวานที่ปิดไปแล้ว
ซ้าย AI อ่าน checklist ใน PR #152 แล้วแก้แค่การตอบยอดในบอท LINE กับติ๊กข้อที่ค้าง ทดสอบซ้ำ 3 ขวา PR ไม่มีคำอธิบาย AI เปิดกฎส่วนลดเพื่อเดาว่าทำถึงไหน แล้วเขียนกฎคูปองใหม่ทั้งที่เสร็จแล้ว ทดสอบซ้ำ 4 ยังไม่พัง
ซ้าย AI อ่าน #147 จากประวัติ รู้ว่าเงื่อนไขไม่ลดซ้อนกันขาดทุนอยู่ เลยแก้โดยเก็บเงื่อนไขไว้ ขวา ประวัติบอกแค่ update AI เห็นว่าเงื่อนไขนี้ดูเกิน เลยลบทิ้ง Gold ได้ลดซ้อนกับคอร์สลดราคาอีกครั้ง
ซ้าย AI ค้นประวัติด้วยคำว่า LINE10 เจอว่า LINE10 ไม่ซ้อนคอร์สลดราคาโดยตั้งใจ ตอบได้โดยไม่แก้สักไฟล์ ขวา commit เขียนแค่ wip AI ตัดสินว่าเป็นบั๊ก แล้วแก้กฎคูปองให้ซ้อนได้ ทดสอบซ้ำ 2 กฎคูปองขึ้นระบบแบบที่ร้านไม่ได้ตั้งใจ
เขียน commit กับ PR ให้ AI ตัวถัดไปอ่าน บอกว่าทำอะไร ทำไม และอะไรยังค้าง AI ตัวใหม่จำแชทเมื่อวานไม่ได้ มันอ่านได้แค่ repo
ถามก่อนรับ diffcommit message ของ diff นี้บอกไหมว่าทำไม ถ้าพรุ่งนี้ AI ตัวใหม่เปิดประวัติไฟล์ มันจะรู้ไหมว่าห้ามลบอะไร
How to Write a Git Commit Message (Beams 2014): use the body to explain what and why, not how; Conventional Commits 1.0.0: a structured subject (type(scope): description) that tools and people can read
คืนวันศุกร์ ร้านปล่อยการจ่ายเงินผ่าน LINE แบบใหม่ขึ้นระบบ 23:40 ออเดอร์จาก LINE เริ่มค้าง คุณต้องหยุดของใหม่ก่อน แล้วค่อยถอยโค้ดกับฐานข้อมูลออก
ออเดอร์ LINE ค้างตอนห้าทุ่ม ไม่มีทางถอย AI เลยแก้สดถึงตีสอง
แตะกล่องเพื่อหาไฟล์บนกระดาน
กล่อง = ไฟล์หนึ่งไฟล์ ที่ AI ต้องเปิดเมื่อแก้เรื่องในนั้นขั้นตอนชิ้น = สิ่งที่โค้ดทำ หนึ่งขั้น= ชิ้นที่ลากไปไฟล์ใหม่ได้ ในขั้นสุดท้าย
บนมือถือ: แตะที่กระดานเพื่อไปขั้นถัดไป ขั้นสุดท้ายแตะชิ้นที่ลากได้ แล้วแตะกล่องที่มันควรอยู่
ซ้าย PR #160 ถูกรวมเป็น commit เดียว ของใหม่อยู่หลังสวิตช์ และการแก้ฐานข้อมูลมีทั้งทางไปและทางถอย ขวา PR เดียวกัน merge เป็น 14 commit ไม่มีสวิตช์ และการแก้ฐานข้อมูลมีแต่ทางไป ที่ลบช่องเก่าทิ้งด้วย
ซ้าย ปิดสวิตช์คำสั่งเดียว ลูกค้ากลับไปใช้แบบเดิม ทดสอบซ้ำ 1 ขวา ไม่มีสวิตช์ AI แก้การจ่ายเงินแบบใหม่กับตัวสร้างออเดอร์สดบน main ตอนตีหนึ่ง ทดสอบซ้ำ 2 ออเดอร์เดินได้อีกครั้ง
ซ้าย revert commit เดียวของ PR #160 แตะ 2 ไฟล์ CI ผ่าน ขวา AI revert 14 commit ทีละตัว ชนกับงานแก้ด่วนเมื่อตีหนึ่ง แล้วแก้ที่ชนเอง ตัวสร้างออเดอร์ถูกเรียกสองรอบ ออเดอร์เว็บถูกสร้างซ้ำ
ซ้าย รันทางถอยที่เตรียมไว้คำสั่งเดียว ช่องเก่าไม่เคยหาย ทดสอบซ้ำ 2 ขวา ไม่มีทางถอย AI เขียนเองตอนตีสอง ช่องเก่ากลับมา แต่ว่างทั้ง 3,214 แถว เพราะข้อมูลหายไปตั้งแต่ตอนลบ
ก่อนปล่อยของใหม่ ให้มีทางถอยที่เป็นคำสั่งเดียว ปิดสวิตช์ revert commit เดียว รันทางถอยของฐานข้อมูล ถ้าการถอยต้องเขียนโค้ดใหม่ตอนตีสอง นั่นไม่ใช่การถอย มันคือการปล่อยของใหม่อีกรอบโดยไม่มีใครรีวิว
ถามก่อนรับ diffถ้า diff นี้พังคืนนี้ ถอยด้วยคำสั่งอะไร และมีอะไรใน diff ที่ถอยแล้วข้อมูลไม่กลับมา
Continuous Delivery (Humble & Farley 2010): rolling back must be a one-step, rehearsed operation; Feature Toggles (Hodgson, martinfowler.com 2017); Parallel Change / expand–contract (Sato, martinfowler.com 2014)ห้าข้อคือรั้วเดียวกัน วางคนละจุด
branch กั้นความพังไว้ใน diff เดียว (1) PR เล็กทำให้คนรีวิวอ่าน diff นั้นได้จริง (2) CI ตัดสินว่า merge ได้ไหม แทนคำพูดของ AI (3) commit กับ PR เก็บเหตุผลไว้ให้ AI ตัวถัดไป (4) และทางถอยที่เป็นคำสั่งเดียว ทำให้ความพังที่หลุดไปแล้วอยู่ได้ไม่นาน (5) AI เขียนโค้ดเร็วขึ้นทุกเดือน ความพังจากโค้ดที่เร็วขึ้นก็ไปได้ไกลขึ้นด้วย ห้าข้อนี้กำหนดว่ามันไปได้ไกลแค่ไหน
อยากรู้ตอนมีกระดานใหม่
ทุกหลักสูตรตอนนี้อ่านฟรี ทิ้งอีเมลไว้ แล้วจะส่งให้เฉพาะตอนมีหลักสูตรหรือกระดานใหม่ ไม่มีอย่างอื่น