ในโลกของการพัฒนาซอฟต์แวร์ที่พัฒนาไปอย่างรวดเร็ว โปรแกรมเมอร์ต้องเผชิญกับเครื่องมือ เฟรมเวิร์ก และนามธรรมมากมายที่หลั่งไหลเข้ามาอย่างล้นหลาม โดยทั้งหมดนี้สัญญาว่าจะทำให้งานของพวกเขาง่ายขึ้น แม้เครื่องมือเหล่านี้จะเพิ่มผลผลิตได้เมื่อเข้าใจอย่างถ่องแท้ แต่โปรแกรมเมอร์จำนวนมากกลับพบว่าตนเองติดอยู่ในสิ่งที่ชุมชนเรียกว่า นามธรรมล้นเกิน — เมื่อเครื่องมือที่สร้างขึ้นเพื่อช่วยพวกเขากลับกลายเป็นแหล่งของความสับสนและหนี้ทางเทคนิค
ปรากฏการณ์โปรแกรมเมอร์หลงทาง
ทั่วทั้งทีมพัฒนาซอฟต์แวร์ เริ่มมีรูปแบบที่น่ากังวลปรากฏขึ้น โดยโปรแกรมเมอร์มีความเชี่ยวชาญเฉพาะในเครื่องมือบางอย่างโดยไม่เข้าใจระบบพื้นฐานที่อยู่เบื้องหลัง นักพัฒนากลุ่มนี้สามารถใช้งานเฟรมเวิร์กอย่าง Next.js หรือ Spring Boot ได้อย่างเชี่ยวชาญ แต่กลับต่อสู้ดิ้นรนเมื่อมีสิ่งผิดปกติเกิดขึ้นนอกเหนือจากกรณีการใช้งานที่มีเอกสารระบุไว้ ชุมชนได้ตั้งชื่อปรากฏการณ์นี้ว่า โปรแกรมเมอร์หลงทาง — บุคคลที่ทำงานได้อย่างสะดวกสบายภายในนามธรรมที่ตนเลือก แต่ขาดความรู้พื้นฐานที่จำเป็นในการแก้ไขปัญหาเมื่อความมหัศจรรย์ของเครื่องมือล้มเหลว
มีนักพัฒนาคนหนึ่งอธิบายความรู้สึกนี้ได้อย่างตรงใจ: ผมมีแนวโน้มที่จะหลีกเลี่ยงเครื่องมือประเภทที่ย่อยนามธรรมของปัญหามากเกินไปในแบบ 'เวทมนตร์' ด้วยเหตุผลเดียวกัน: คุณไม่สามารถเข้าใจสิ่งที่เกิดขึ้นเบื้องหลังได้ง่ายๆ และคุณต้องลงมือแก้ไขทุกครั้งที่เจอกรณีขอบเขต (corner case)
แนวทางนี้สร้างความเสี่ยงอย่างมีนัยสำคัญให้กับโครงการซอฟต์แวร์ เมื่อคำสั่ง SQL ที่สร้างโดย ORM ทำให้ประสิทธิภาพของฐานข้อมูลลดลง หรือคำอธิบายประกอบ (annotation) เกี่ยวกับธุรกรรม (transactional) ล้มเหลวในการรักษาความสอดคล้องทั่วทั้งระบบแบบกระจาย (distributed systems) นักพัฒนาเหล่านี้พบว่าตนเองไม่สามารถวินิจฉัยหรือแก้ไขปัญหาได้ ปัญหาไม่จำเป็นต้องมาจากการขาดความฉลาด แต่เป็นช่องว่างในความรู้พื้นฐานที่ปรากฏชัดก็ต่อเมื่อนามธรรมเกิดการรั่วไหล
ข้อผิดพลาดทั่วไปของการใช้ Abstraction ในการพัฒนา:
- ระบบ ORM: สามารถสร้างคำสั่ง SQL ที่ไม่มีประสิทธิภาพซึ่งนักพัฒนาไม่สามารถปรับปรุงได้หากไม่มีความรู้เกี่ยวกับฐานข้อมูล
- Frontend Frameworks: อาจทำให้ไม่ชัดเจนว่าแอปพลิเคชันเป็นไฟล์แบบ static หรือ server-rendered ส่งผลให้เกิดปัญหาในการ deployment และการตั้งค่า
- Transactional Annotations: มักถูกเข้าใจผิดในระบบแบบกระจาย ซึ่งความเป็น transactionality ที่แท้จริงข้ามระบบต่างๆ (ฐานข้อมูล + message brokers) เป็นไปไม่ได้
- Containerization: นักพัฒนาบางครั้งใส่ node_modules ทั้งหมดลงใน Docker images ทำให้เวลาในการ build นานมาก
ต้นทุนทางปัญญาของความสะดวกสบาย
เครื่องมือพัฒนาสมัยใหม่มักแลกเปลี่ยนความละเอียดถี่ถ้วนด้วยความซับซ้อนทางปัญญา เฟรมเวิร์กเช่น React, Kubernetes และ Spring Boot อนุญาตให้นักพัฒนาสามารถทำงานที่ซับซ้อนด้วยโค้ดเพียงเล็กน้อย แต่สิ่งนี้มาพร้อมกับต้นทุนของการทำความเข้าใจว่าระบบเหล่านี้ทำงานจริงอย่างไร ดังที่ผู้แสดงความคิดเห็นหนึ่งระบุไว้ เราแทนที่ความละเอียดถี่ถ้วนด้วยชั้นของนามธรรมใหม่ที่ทำให้เราพิมพ์สิ่งต่างๆ น้อยลงมาก แต่ในขณะเดียวกันก็นำเสนอชั้นของความซับซ้อนทางปัญญาใหม่ทั้งหมดเข้ามา
ภาระทางปัญญานี้กลายเป็นปัญหาอย่างยิ่งในช่วงการดีบัก (debugging) นักพัฒนาที่เข้าใจเพียง API ระดับผิวเผินของเครื่องมือของพวกเขา ต้องต่อสู้ดิ้นรนในการติดตามปัญหาผ่านชั้นของนามธรรมหลายชั้น เวลาที่ประหยัดได้ในช่วงเริ่มต้นการพัฒนาอาจสูญเสียไปอย่างรวดเร็วเมื่อทีมใช้เวลาหลายชั่วโมงหรือหลายวันในการแก้ไขปัญหาที่จะเห็นได้ชัดเจนทันทีหากมีความเข้าใจระบบพื้นฐานที่ดีขึ้น
เส้นทางสู่ความเชี่ยวชาญผ่านพื้นฐานที่แข็งแกร่ง
นักพัฒนาที่มีประสบการณ์หลายคนในชุมชนสนับสนุนแนวทาง กลับสู่พื้นฐาน แทนที่จะหลีกเลี่ยงเครื่องมือสมัยใหม่ทั้งหมด พวกเขาแนะนำให้สร้างความรู้พื้นฐานที่แข็งแกร่งก่อน การทำความเข้าใจระบบปฏิบัติการ โปรโตคอลเครือข่าย พื้นฐานฐานข้อมูล และสถาปัตยกรรมคอมพิวเตอร์ ให้แบบจำลองทางจิต (mental models) ที่จำเป็นแก่นักพัฒนาเพื่อประเมินและใช้นามธรรมระดับสูงอย่างเหมาะสม
เส้นทางการเรียนรู้ไม่จำเป็นต้องเริ่มต้นด้วยภาษาแอสเซมบลี (assembly) อย่างที่ผู้แสดงความคิดเห็นหนึ่งกล่าวไว้อย่างชาญฉลาด: ในทางกลับกัน ถ้าคุณมีเด็กอายุ 10 ขวบที่แสดงความสนใจใน 'คอมพิวเตอร์' คุณอาจไม่ต้องการสอนเขาเกี่ยวกับเงื่อนไข (conditionals) โดยแสดงคำสั่งกระโดดแบบมีเงื่อนไข (conditional jump) ในภาษาแอสเซมบลี x86 ให้เขาดู กุญแจสำคัญคือการเรียนรู้แบบก้าวหน้า — สร้างจากแนวคิดที่เข้าใจได้ไปสู่ระบบที่ซับซ้อนมากขึ้น ขณะเดียวกันก็รักษาความอยากรู้อยากเห็นเกี่ยวกับการทำงานของสิ่งต่างๆ ในแต่ละระดับ
เส้นทางการเรียนรู้ที่แนะนำสำหรับนักพัฒนา:
- ระบบปฏิบัติการ: การจัดการโปรเซส การจัดสรรหน่วยความจำ ระบบไฟล์
- เครือข่าย: โปรโตคอล TCP/IP, HTTP สร้างเซิร์ฟเวอร์อย่างง่ายด้วยตัวเอง
- ฐานข้อมูล: พื้นฐาน SQL การทำดัชนี ระดับการแยกทรานแซคชัน
- สถาปัตยกรรมคอมพิวเตอร์: การทำงานของ CPU ลำดับชั้นหน่วยความจำ พื้นฐานภาษาแอสเซมบลี
- อัลกอริทึมและโครงสร้างข้อมูล: ความซับซ้อนด้านเวลาและพื้นที่ รูปแบบที่พบบ่อย
ความสมดุลระหว่างความต้องการทางธุรกิจและความเป็นเลิศทางเทคนิค
สมาชิกในชุมชนบางคนแย้งว่าแนวทางแบบโปรแกรมเมอร์หลงทางเป็นตัวอย่างของการทำตามแบบแผนอย่างได้ผล (pragmatic cargo-culting) — นักพัฒนาคัดลอกรูปแบบที่ทำงานได้ดีพอที่จะส่งมอบคุณค่าทางธุรกิจ ดังที่ผู้แสดงความคิดเห็นหนึ่งระบุ สิ่งที่เกิดขึ้นจริงกับคนเหล่านี้คือพวกเขากำลังทำตามแบบแผนอย่างได้ผล เพราะมันช่วยให้พวกเขาบรรลุเป้าหมายอื่น เช่น การส่งมอบคุณค่าทางธุรกิจ จนกระทั่งนามธรรมของพวกเขาเกิดรั่วและพวกเขาต้องไปค้นหาความจริง
อย่างไรก็ตาม มุมมองนี้มองข้ามต้นทุนระยะยาวของการสะสมหนี้ทางเทคนิค (technical debt) ระบบที่สร้างโดยนักพัฒนาที่ไม่เข้าใจเครื่องมือของพวกเขามักจะมีบั๊กและปัญหาประสิทธิภาพที่ซ่อนเร้นซึ่งปรากฏขึ้นเมื่อเวลาผ่านไป ความเร็วเริ่มต้นที่ได้จากการพึ่งพานามธรรมแบบเวทมนตร์อาจถูกลบล้างอย่างรวดเร็วด้วยช่วงการดีบักที่ยาวนานและการออกแบบระบบใหม่เมื่อความต้องการเปลี่ยนไปหรือขนาดเพิ่มขึ้น
บทบาทของความอยากรู้อยากเห็นในการเติบโตทางวิชาชีพ
ในแก่นแท้แล้ว การอภิปรายนี้เผยให้เห็นว่าความแตกต่างระหว่างนักพัฒนาที่มีความสามารถและผู้ที่ยอดเยี่ยมมักมาจากความอยากรู้อยากเห็น นักพัฒนาที่รักษาความอยากรู้อยากเห็นเกี่ยวกับการทำงานของระบบภายใต้อุปนามธรรมจะเติบโตต่อไปตลอดอาชีพการงานของพวกเขา ส่วนผู้ที่มองการเขียนโปรแกรมเป็นเพียงการทำงานให้เสร็จด้วยเครื่องมือใดก็ตามที่ได้รับ มักจะพัฒนาตนเองได้ช้าลงตั้งแต่เนิ่นๆ
แนวทางที่ขับเคลื่อนด้วยความอยากรู้อยากเห็นนี้ไม่ต้องการให้ละทิ้งเครื่องมือสมัยใหม่ แต่หมายถึงการใช้งานเครื่องมือเหล่านั้นในขณะที่เข้าใจข้อจำกัดและรายละเอียดการใช้งาน เมื่อเฟรมเวิร์กอย่าง Next.js สร้างแอปพลิเคชัน นักพัฒนาที่มีความอยากรู้อยากเห็นจะรู้ว่ามันกำลังสร้างไฟล์แบบสถิต (static) หรือเนื้อหาที่เรนเดอร์จากเซิร์ฟเวอร์ (server-rendered) เมื่อใช้คำอธิบายประกอบ @Transactional พวกเขาเข้าใจขอบเขตของการจัดการธุรกรรม (transaction management) ในระบบแบบกระจาย
ภูมิทัศน์ของการพัฒนาซอฟต์แวร์จะยังคงพัฒนาต่อไป พร้อมกับเครื่องมือและนามธรรมใหม่ๆ ที่เกิดขึ้นอย่างสม่ำเสมอ นักพัฒนาที่ประสบความสำเร็จสูงสุดจะเป็นผู้ที่สามารถใช้ประโยชน์จากเครื่องมือเหล่านี้ได้ ในขณะที่ยังคงมีความเข้าใจอย่างลึกซึ้งในพื้นฐาน พวกเขากลายเป็นนายของเครื่องมือ แทนที่จะเป็นผู้รับใช้เครื่องมือ สามารถตัดสินใจอย่างมีข้อมูลเกี่ยวกับเวลาที่จะใช้โซลูชันที่มีอยู่และเวลาที่จะสร้างการใช้งานแบบกำหนดเอง ในอุตสาหกรรมที่การเปลี่ยนแปลงเป็นสิ่งคงที่ ความรู้พื้นฐานยังคงเป็นสินทรัพย์ที่มีค่าที่สุดและทนทานที่สุดที่นักพัฒนาสามารถสั่งสมได้
อ้างอิง: Programmer in Wonderland