โค้ดที่ดีที่สุดคือโค้ดที่คุณไม่เคยเขียนเลย แนวคิดนี้อาจฟังดูเหมือนข้ออ้างของความขี้เกียจ จนกว่าคุณจะได้ใช้เวลาหลายปีในการดูแลรักษาความกระตือรือร้นของคนอื่น การเขียนซอฟต์แวร์ให้ความรู้สึกเหมือนการก่อสร้าง แต่พฤติกรรมของมันกลับเหมือนการทำสวน หากปล่อยทิ้งไว้ สวนจะเติบโตไม่ว่าคุณจะต้องการหรือไม่ก็ตาม โค้ดก็เช่นกัน งานฝีมือที่แท้จริงคือการรู้ว่าเมื่อไหร่ควรหยุดปลูก

โค้ดของคุณคือภาระ

ทุกบรรทัดที่คุณ commit สร้างชุดของพันธะผูกพันที่ต้องดูแลต่อไป คุณจะต้องกลับมาอ่านมันอีกครั้งในช่วงที่เกิดเหตุการณ์ไม่คาดฝันกลางดึก คุณจะต้องทดสอบมันหลังจาก framework ออกเวอร์ชันย่อยที่เปลี่ยนวิธีการจัดการ string คุณจะต้อง debug มันเมื่อ logs จาก production ดูไม่สมเหตุสมผล คุณจะต้องอธิบายมันให้กับเพื่อนร่วมทีมที่เพิ่งเข้ามาเมื่อสัปดาห์ก่อน หรืออธิบายให้ตัวเองฟังในอีกสิบสองเดือนข้างหน้าเมื่อบริบทเดิมเลือนหายไปหมดแล้ว

นี่ไม่ใช่การสนับสนุนความคลุมเครือ แต่มันคือเรื่องของเรขาคณิต บั๊กต้องการพื้นที่ในการซ่อน ยิ่งพื้นที่ผิว (surface area) ของคุณน้อยลงเท่าไหร่ จุดที่ความล้มเหลวจะแทรกซึมเข้ามาได้ก็น้อยลงเท่านั้น ฟังก์ชันที่มีแปดสิบบรรทัดและมีเงื่อนไขซ้อนกันหกชั้น ไม่ใช่แค่ทำให้อ่านยากขึ้น แต่มันมีโอกาสทางสถิติที่จะทำให้คุณประหลาดใจได้มากกว่า การยับยั้งชั่งใจไม่ใช่การขาดความพยายาม แต่มันคือการตระหนักว่าโค้ดที่ไม่ได้เขียนขึ้นมานั้นมีข้อบกพร่องเป็นศูนย์อย่างแท้จริง

เมื่อความฉลาดกลายเป็นภาษี

ลองพิจารณาภารกิจการคำนวณยอดรวมคำสั่งซื้อด้วยกฎทางธุรกิจไม่กี่ข้อ: ใช้ส่วนลด, ตรวจสอบรายการที่ต้องเสียภาษี, ข้ามรายการที่ถูกระบุว่าถูกลบออก นักพัฒนาคนหนึ่งเขียนโค้ดด้วย expression เพียงชุดเดียว มันทำการ stream รายการผ่าน filter chain ที่ซับซ้อน เรียกใช้ helper library, ทำการ fold ผลลัพธ์ด้วย curried reducer และคืนค่าผลรวม มันดูสั้นกระชับ และอาจจะดูสง่างามในเชิงวิชาการด้วยซ้ำ แต่การจะอ่านมันได้ คุณต้องเข้าใจเรื่อง implicit casting ของ helper library, ลำดับการทำงานภายใน stream และตรรกะทางธุรกิจทั้งหมดในเวลาเดียวกัน คุณไม่สามารถตั้ง breakpoint ไว้ตรงกลางได้ คุณไม่สามารถแทรกคำสั่ง log โดยไม่ทำให้ chain พัง โค้ดนี้อาจจะสั้นบนหน้ากระดาษ แต่กลับกินพื้นที่ในสมองอย่างมหาศาล

นักพัฒนาอีกคนเขียน loop พื้นฐาน เธอประกาศตัวแปรยอดรวม (running total), วนลูปผ่านรายการต่างๆ และใช้คำสั่ง if ธรรมดาเพื่อตัดสินใจว่าต้องเสียภาษีหรือไม่ แม้ว่า block ของโค้ดจะยาวขึ้นในแนวตั้ง แต่เจตนาของมันนั้นชัดเจน คุณสามารถอ่านมันจากบนลงล่างได้โดยไม่ต้องจำ abstraction ถึงห้าอย่างไว้ในหัว คุณสามารถไล่ดูทีละขั้นตอนใน debugger ได้ และคุณสามารถเพิ่มการทำ logging ในบรรทัดที่สี่ได้โดยไม่ต้อง refactor expression ทั้งหมดใหม่

โค้ดที่ดูฉลาดจะดูเท่ใน pull request ประมาณสิบนาที แต่โค้ดที่เรียบง่ายจะดูน่าเบื่อ และความน่าเบื่อนี่แหละคือสิ่งที่คุณต้องการเมื่อต้องแก้ไขปัญหาตอนตีสอง เป้าหมายของคุณคือความชัดเจน ไม่ใช่การแสดงความอัจฉริยะ

ระบบต้องการโครงสร้าง ไม่ใช่ฮีโร่

หลักการนี้ขยายไปถึงระดับสถาปัตยกรรม ระบบที่ดูฉลาดอาจพึ่งพาตรรกะ consensus ที่เขียนขึ้นเอง, สคริปต์ orchestration ที่ทำขึ้นเฉพาะกิจ และทางลัดการทำ caching ที่ไม่มีเอกสารกำกับซึ่งมีวิศวกรเพียงคนเดียวเท่านั้นที่เข้าใจอย่างแท้จริง ระบบนั้นไม่ได้ทำงานได้ด้วยตัวเอง แต่มันทำงานได้ด้วยความอัจฉริยะอย่างต่อเนื่องของใครก็ตามที่คอยประคับประคองมันไว้ เมื่อคนคนนั้นลาพักร้อนหรือเปลี่ยนงาน ระบบก็จะเริ่มสั่นคลอน

ในทางกลับกัน ระบบที่ออกแบบมาอย่างดีจะพึ่งพาโครงสร้างและข้อจำกัด พวกเขาใช้ database schema ที่ปฏิเสธข้อมูลที่ผิดพลาด, API contracts ที่กำหนดขอบเขต, type systems ที่ตรวจจับ category errors ก่อนการ deployment และการแยกโมดูลที่ทำให้เส้นทางที่ตั้งใจไว้ชัดเจน ระบบเหล่านี้ไม่ต้องการวีรบุรุษเพื่อให้คงความเสถียร พวกมันถูกออกแบบมาเพื่อให้รอดพ้นจากการสัมผัสกับมนุษย์ที่เหนื่อยล้า ซึ่งเป็นมนุษย์ประเภทเดียวที่ใช้งานซอฟต์แวร์ใน production จริงๆ

ปัญหาการขยายตัวของ AI

ผู้ช่วยเขียนโค้ดด้วยปัญญาประดิษฐ์ทำให้บทเรียนนี้มีความสำคัญเร่งด่วน เครื่องมือเหล่านี้สร้างข้อความได้อย่างรวดเร็ว เมื่อคุณมอบปัญหาที่เรียบง่ายให้พวกมัน พวกมันมักจะคืนคำตอบที่ซับซ้อนและมีขนาดใหญ่ ซึ่งมีการ import utilities ที่คุณมี wrapper ภายในองค์กรอยู่แล้ว, จัดการกับ edge cases ที่ไม่มีอยู่ในโดเมนของคุณ และใช้ idioms จาก framework เวอร์ชันที่คุณย้ายออกไปเมื่อสองปีที่แล้ว AI มองไปที่งานเฉพาะหน้า แต่คุณต้องมองไปที่ระบบทั้งหมด

หากคุณยอมรับทุกคำแนะนำโดยไม่บริหารจัดการต้นทุนในระยะยาว การสร้างโค้ดจะนำไปสู่ภาวะเงินเฟ้อ คลังเก็บโค้ด (repository) ของคุณจะพองโตด้วยโค้ดที่ดูสมเหตุสมผล ซึ่งคอมไพล์ผ่าน ทดสอบผ่าน แต่กลับไม่มีใครเข้าใจมันอย่างแท้จริง อันตรายไม่ใช่ข้อผิดพลาดทางไวยากรณ์ (syntax error) ที่เห็นได้ชัด เพราะสิ่งเหล่านั้นมักจะถูกตรวจพบในขั้นตอนการรีวิว แต่อันตรายที่แท้จริงคือการที่ฐานโค้ด (codebase) ค่อยๆ หนาขึ้นเรื่อยๆ จนแต่ละไฟล์ดูเหมือนจะใช้งานได้ดีเมื่อดูแยกกัน แต่เมื่อรวมกันทั้งหมดแล้ว กลับไม่มีใครสามารถทำความเข้าใจภาพรวมทั้งหมดได้ด้วยสมองเพียงคนเดียว นี่คือวิธีที่ความเร็วในการทำงานด้านวิศวกรรม (engineering velocity) ตายลง ไม่ใช่ด้วยการพังทลายอย่างรุนแรง แต่เป็นการสะสมของสิ่งต่างๆ อย่างเงียบเชียบที่ไม่มีใครกล้าลบ เพราะพวกเขากลัวที่จะแตะต้องสิ่งที่ตนเองไม่เข้าใจอย่างถ่องแท้

การลบคือทักษะการออกแบบ

วิศวกรที่เก่งกาจไม่ได้พิสูจน์ตัวเองด้วยการพิมพ์โค้ดได้เร็วกว่าคนอื่น แต่พวกเขาชนะด้วยการเลือกความเรียบง่าย และเลือกการลบมากกว่าการสะสม การลบโค้ดจำเป็นต้องอาศัยความเข้าใจ คุณต้องติดตามการไหลของข้อมูล (data flow) ยืนยันว่าฟีเจอร์นั้นไม่มีตัวเรียกใช้งาน (callers) ที่ซ่อนอยู่ และตรวจสอบว่าความต้องการทางธุรกิจได้เปลี่ยนไปแล้ว การลบนั้นยากกว่าการเพิ่ม เพราะมันต้องการความมั่นใจที่แน่ชัด

ทีมส่วนใหญ่มักจะเฉลิมฉลองให้กับฟีเจอร์ที่ปล่อยออกมาได้สำเร็จ หรือเหล่านักพัฒนาที่ส่ง pull request ขนาดมหึมา แต่มีน้อยทีมนักที่จะเฉลิมฉลองให้กับวิศวกรที่ลบตรรกะที่ไม่ได้ใช้งาน (dead logic) ออกไปถึงสี่พันบรรทัด เพื่อทำให้ระบบทำงานเร็วขึ้นและทำความเข้าใจได้ง่ายขึ้น แต่จำนวนบรรทัดที่ติดลบนั้น มักจะเป็นประโยชน์ที่ยิ่งใหญ่กว่าต่ออนาคตขององค์กร

ส่วนที่มีราคาแพง

ในตอนนี้ โค้ดเป็นของราคาถูก ใครๆ ก็สามารถสร้างโค้ดออกมาได้เป็นหน้าๆ ภายในไม่กี่วินาที ทรัพยากรที่มีราคาแพงคือความชัดเจน (clarity) การจะรักษาให้ระบบยังคงอยู่ในระดับที่เข้าใจได้นั้น ต้องใช้ทั้งเวลา การตัดสินใจ และการยับยั้งชั่งใจ วิศวกรรมที่แท้จริงเกิดขึ้นในขั้นตอนการเกลา ไม่ใช่ขั้นตอนการร่าง

เขียนให้น้อยลง ลบให้มากขึ้น ออกแบบให้เรียบง่าย