ความไร้ระเบียบ (entropy) ใน Front-end นั้นเป็นเรื่องจริง โค้ดเบสไม่ได้พังทลายลงในชั่วข้ามคืน แต่มันค่อยๆ สะสมขึ้นมา วันอังคารหนึ่งคุณอาจจะเพิ่มไลบรารีสำหรับจัดรูปแบบวันที่ อีกหกเดือนต่อมาใครบางคนก็เพิ่มอีกตัวเพราะหาตัวแรกไม่เจอ Polyfills ต่างๆ พอกพูนขึ้นสำหรับเบราว์เซอร์ที่คุณไม่ได้สนับสนุนแล้ว เครื่องมือในการ Build ก็วางทับซ้อนกันไปเรื่อยๆ ในที่สุดโฟลเดอร์ node_modules ก็กลายเป็นลิ้นชักเก็บขยะดิจิทัลที่ไม่มีใครกล้าทิ้งอะไรออกไปเพราะกลัวพัง คุณหยุดอัปเดต และจากนั้นคุณก็หยุดที่จะมองมัน และนั่นคือตอนที่ทุกการเปลี่ยนแปลงเล็กๆ กลายเป็นการเสี่ยงดวง

ผมเจอทางตันนี้ตอนที่พยายามจะอัปเกรด Material UI ในโปรเจกต์เก่า ผมเปิด package.json ขึ้นมาแล้วแทบจำไม่ได้ว่าครึ่งหนึ่งของรายการเหล่านั้นคืออะไร ไลบรารีหลายสิบตัววางอยู่ตรงนั้น บางตัวล้าสมัยไปหลายปี บางตัวก็คลุมเครือมากจนผมต้องใช้ git blame เพื่อดูว่าใครเป็นคนเพิ่มมันเข้ามาและเพิ่มมาทำไม ผมรันคำสั่งติดตั้ง Material UI เวอร์ชันใหม่ แล้วเทอร์มินัลก็เต็มไปด้วยคำเตือนเรื่อง peer dependency แพ็กเกจที่ผมต้องการอัปเดตนั้นไม่มีปัญหา แต่ระบบนิเวศรอบๆ ตัวมันต่างหากที่มีปัญหา ผมตระหนักได้ว่าผมไม่ได้กำลังทำการอัปเกรด แต่ผมกำลังขุดค้นซากปรักหักพังอยู่

ทำไมความยุ่งเหยิงถึงมีราคาแพงกว่าศักดิ์ศรี

การละเลย dependencies ไม่ใช่แค่ปัญหาเรื่องความสวยงาม แต่มันสร้างปัญหาที่เกิดขึ้นจริงและมีราคาแพง

ความเสี่ยงด้านความปลอดภัย (Security risks) คือภัยคุกคามที่เห็นได้ชัด แพ็กเกจที่ถูกทิ้งร้างมักมีช่องโหว่ที่ถูกเปิดเผยออกมาซึ่งเครื่องมือสแกนจะแจ้งเตือนทุกสัปดาห์ ที่แย่กว่านั้นคือ ไลบรารีที่คุณติดตั้งโดยตรงอาจจะไม่มีปัญหา แต่ transitive dependencies ที่พวกมันดึงมาใช้อาจจะมี คุณกำลังรับหนี้ทางเทคนิค (technical debt) ของคนอื่นมาโดยไม่รู้ตัว

ต้นทุนจะยิ่งสูงขึ้นตามระยะเวลาที่ผ่านไป ยิ่งคุณรอนานเท่าไหร่ ช่องว่างระหว่างเวอร์ชันก็ยิ่งกว้างขึ้นเท่านั้น การข้าม React เวอร์ชันหลัก (major version) เพียงเวอร์ชันเดียวคืองานหนึ่งชิ้น แต่การข้ามถึงสามเวอร์ชันคือโปรเจกต์การย้ายระบบ (migration) ที่อาจกินเวลาหลายสัปดาห์ คุณจะหยุดได้รับ bug fixes, การปรับปรุงประสิทธิภาพ และความเข้ากันได้กับเครื่องมือสมัยใหม่ ทีมของคุณจะลงเอยด้วยการต้องสร้างงานโดยมีข้อจำกัดที่จริงๆ แล้วไม่ควรจะมีอยู่แล้ว

ไลบรารีมีวันตาย แพ็กเกจที่ไม่มีผู้ดูแล (maintainer) ที่คอยอัปเดตจะกลายเป็น fork ส่วนตัวของคุณโดยปริยาย เมื่อมันพัง คุณคือคนที่ต้องมานั่งอ่าน minified source code ตอนเที่ยงคืน ชุมชนได้เปลี่ยนไปใช้โซลูชันที่ดีกว่าแล้ว แต่ทีมของคุณยังคงติดอยู่กับการดูแลซากที่ไม่มีชีวิต

ความเร็วในการทำงานลดฮวบ (Velocity craters) นักพัฒนาใหม่ต้องใช้เวลาหลายวันแรกไปกับการเรียนรู้ API ที่มีลักษณะเฉพาะตัวสูงสำหรับเครื่องมือที่ถูกแทนที่ด้วย web standards หรือทางเลือกหลักๆ ไปแล้ว แทนที่จะได้ส่งมอบฟีเจอร์ใหม่ๆ วิศวกรอาวุโสของคุณกลับต้องกลายเป็นนักประวัติศาสตร์ คอยอธิบายว่าทำไมโปรเจกต์นี้ยังต้องใช้ task runner จากปี 2015 อยู่

ตรวจสอบก่อนที่จะเริ่มอัปเกรดเวอร์ชันใดๆ

ความผิดพลาดที่ร้ายแรงที่สุดคือการสั่งอัปเดตแบบเหมาเข่งแล้วหวังว่า test จะผ่าน ให้เริ่มจากการทำ audit ก่อน หยิบ package.json ขึ้นมาแล้วตรวจสอบทุกรายการอย่างละเอียด

ถามคำถามสี่ข้อ:

  • สิ่งนี้แก้ปัญหาอะไร?
  • เราใช้งานมันที่ไหนบ้าง?
  • มันยังจำเป็นอยู่ไหม?
  • ตอนนี้มีทางเลือกอื่นที่ดีกว่าไหม?

คุณจะพบความซ้ำซ้อน บางที moment และ date-fns อาจจะอยู่ในรายการทั้งคู่เพราะนักพัฒนาสองคนแก้ปัญหาเดียวกันในเวลาที่ต่างกัน บางที polyfill สำหรับ Internet Explorer อาจจะยังถูกส่งไปด้วย ทั้งที่ข้อมูล analytics ของคุณแสดงให้เห็นว่าไม่มี traffic จากเบราว์เซอร์รุ่นเก่าเลย หรือบางที custom wrapper รอบ fetch อาจจะลบทิ้งได้ เพราะเบราว์เซอร์สมัยใหม่จัดการ edge cases เหล่านั้นได้ด้วยตัวเองแล้ว

บางครั้งการเปลี่ยนใหม่ก็ดีกว่าการอัปเดต การฝืนดึงดันใช้ไลบรารีทำกราฟที่ถูกทิ้งไปแล้วผ่านการเปลี่ยนแปลงที่ทำให้โค้ดพัง (breaking changes) ตลอดสามปี อาจใช้เวลานานกว่าการเปลี่ยนไปใช้ทางเลือกที่เสถียรแล้วสร้างคอมโพเนนต์ใหม่ไม่กี่ตัว จงกล้าที่จะตัดออกบ้าง

เลเยอร์ที่ซ่อนอยู่: Transitive Dependencies และ Semver

Direct dependencies เป็นเพียงส่วนที่มองเห็นได้เหนือผิวน้ำของภูเขาน้ำแข็งเท่านั้น ส่วนที่ใหญ่กว่านั้นซ่อนอยู่ข้างใต้ในรูปแบบของ transitive dependencies ซึ่งก็คือแพ็กเกจที่แพ็กเกจของคุณจำเป็นต้องใช้ คุณไม่ได้เป็นคนเลือกพวกมัน แต่พวกมันทำงานอยู่ใน build ของคุณ พวกมันทำให้ bundle ของคุณบวม เพิ่มช่องโหว่ในการโจมตี (attack surface) และบางครั้งก็ขัดแย้งกันเองจนทำให้เกิด build error ที่เข้าใจยาก

คุณต้องอ่าน semantic versioning ตามความหมายที่แท้จริงของมัน ไม่ใช่ตามที่คุณหวังว่ามันจะเป็น

  • Major updates: คือการย้ายระบบ (migration) ให้ปฏิบัติกับมันเหมือนเป็นการเปลี่ยนแปลงที่ทำให้โค้ดพัง (breaking changes) จนกว่าจะพิสูจน์ได้ว่าเป็นอย่างอื่น อ่าน changelog, จัดสรรเวลา และทดสอบอย่างละเอียด
  • Minor updates: คือการเพิ่มฟีเจอร์ ซึ่งอาจเปลี่ยนแปลงพฤติกรรมบางอย่างในลักษณะที่แนบเนียน อย่าทึกทักเอาเองว่ามันไม่มีความเสี่ยง
  • Patch updates: คือการแก้บั๊ก โดยปกติจะปลอดภัย แต่ถ้าโค้ดของคุณพึ่งพาบั๊กนั้นอยู่ หรือถ้าแพตช์นั้นไปเปลี่ยนส่วนภายในที่คุณเคยทำ monkey-patching ไว้ คุณก็ยังอาจจะทำระบบพังได้

การรู้กฎเหล่านี้จะช่วยให้คุณจัดหมวดหมู่ความเสี่ยงได้ก่อนที่จะแตะต้องอะไรก็ตาม

ใช้เครื่องมือของคุณอย่างช่างฝีมือ

หากคุณใช้ Yarn คำสั่งที่มีมาให้หลายคำสั่งจะเปลี่ยนการเดาสุ่มให้กลายเป็นกระบวนการที่ชัดเจน

รัน yarn outdated ก่อนเป็นอันดับแรก มันจะให้ภาพรวมของสิ่งที่เริ่มคลาดเคลื่อน...