การพัฒนาซอฟต์แวร์ระยะยาว (long term)
(berthub.eu)- ซอฟต์แวร์สมัยใหม่มีการอัปเดตบ่อยผ่านการส่งมอบอย่างต่อเนื่อง (CD) และการทดสอบอัตโนมัติ (CI) แต่ "ซอฟต์แวร์ที่ใช้งานในระยะยาว" ต้องการแนวทางที่แตกต่างออกไป
- ตัวอย่าง: โรงไฟฟ้านิวเคลียร์ เครื่องบิน เครื่องกระตุ้นหัวใจ ระบบการเลือกตั้ง เป็นต้น
- ในงานที่ความน่าเชื่อถือและเสถียรภาพมีความสำคัญ มักให้ความสำคัญกับเสถียรภาพและการเปลี่ยนแปลงที่คาดการณ์ได้ มากกว่าการเปลี่ยนแปลงอย่างต่อเนื่อง
- ตัวอย่าง: โรงไฟฟ้านิวเคลียร์ เครื่องบิน เครื่องกระตุ้นหัวใจ ระบบการเลือกตั้ง เป็นต้น
หลักการสำคัญของการพัฒนาซอฟต์แวร์ระยะยาว
การพึ่งพา (Dependencies)
- การพึ่งพาของซอฟต์แวร์เป็นปัจจัยสำคัญต่อความสำเร็จในระยะยาว
- ซอฟต์แวร์ต้องคำนึงถึงการโต้ตอบกับโลกภายนอก และการเลือกพื้นฐานอย่างภาษาการเขียนโปรแกรมก็มีความสำคัญ
- ทำความเข้าใจลำดับชั้นของการพึ่งพาซอฟต์แวร์
- โลกภายนอก: ซอฟต์แวร์ฝั่งไคลเอนต์ที่เราไม่สามารถควบคุมได้ (เช่น เบราว์เซอร์ เป็นต้น)
- การเลือกพื้นฐาน: องค์ประกอบที่หากจะเปลี่ยนต้องเขียนใหม่ทั้งสแตก เช่น ภาษาการเขียนโปรแกรม
- เฟรมเวิร์ก: เช่น Spring Framework, React ที่ผูกแน่นกับโค้ดเบส เปลี่ยนได้แต่มีต้นทุนสูงมาก
- ฐานข้อมูล: ส่วนใหญ่เปลี่ยนได้ แต่ต้องมีการปรับจูนและทำงานในรายละเอียด
- ไลบรารีช่วยงาน: ไลบรารีที่เปลี่ยนทดแทนได้และให้ความสามารถเฉพาะด้าน
- เมื่อเวลาผ่านไป การพึ่งพาและโลกภายนอกย่อมเปลี่ยนแปลง:
- การเปลี่ยนแปลงของการพึ่งพาอาจทำให้ต้องแก้โค้ด หรือเกิด การเปลี่ยนแปลงพฤติกรรม
- การออกเวอร์ชันหลักใหม่อาจก่อให้เกิด ปัญหาความเข้ากันได้
- มีความเสี่ยงที่โปรเจกต์จะ ยุติ หรือหายไป
- ความเสี่ยงด้านความปลอดภัย: การพึ่งพาอาจถูกทำให้เสียหายโดยผู้ไม่หวังดี (เช่น npm, PyPI)
- การทำเชิงพาณิชย์: เจ้าของรายใหม่จาก venture capital (VC) อาจเปลี่ยนเป็นโมเดลเสียเงิน
- ปัญหา ความขัดแย้ง ระหว่างการพึ่งพา
- สิ่งที่ควรตรวจสอบเมื่อเลือกการพึ่งพาสำหรับการใช้งานระยะยาว:
- ระดับทางเทคนิค: สามารถดูซอร์สโค้ดแล้วประเมินคุณภาพได้หรือไม่
- ฐานผู้ใช้: ตรวจสอบว่าใครกำลังใช้งานอยู่
- วัตถุประสงค์ในการพัฒนา: ทำความเข้าใจว่าใครเป็นผู้พัฒนาและมีเป้าหมายอะไร
- การสนับสนุนทางการเงิน: มีเงินสนับสนุนหรือไม่ และมาจากไหน
- การบำรุงรักษา: ตรวจสอบว่ามี security release อย่างสม่ำเสมอหรือไม่
- ชุมชนมีโอกาสรับช่วงการดูแลต่อหรือไม่
- เราสามารถดูแลเองได้หรือไม่
- หากจำเป็น ควรสนับสนุนทางการเงินเพื่อให้โปรเจกต์เดินหน้าต่อได้หรือไม่
- การพึ่งพาของการพึ่งพา:
- ควรตรวจสอบประวัติด้านความปลอดภัยของการพึ่งพาชั้นล่างด้วย
- แนวทางที่เป็นจริง
- จำกัดจำนวนการพึ่งพา:
- โปรเจกต์ที่มีการพึ่งพามากกว่า 1600 รายการมีแนวโน้มสูงที่โค้ดจะเปลี่ยนเร็วและไม่เสถียร
- ในโปรเจกต์ที่มีการพึ่งพาจำนวนมาก แทบยากจะรู้ด้วยซ้ำว่ากำลัง deploy โค้ดอะไรอยู่
- เพิ่มอย่างรอบคอบ:
- เมื่อเพิ่มการพึ่งพา ให้ตั้ง ระดับความยากทางเทคนิค เพื่อให้มีช่วงเวลาทบทวนตามธรรมชาติ
- ในโปรเจกต์ระยะยาว ควรหลีกเลี่ยงการพึ่งพาที่ไม่จำเป็น
- จำกัดจำนวนการพึ่งพา:
การพึ่งพาขณะรันไทม์ (Runtime Dependencies)
- สิ่งที่พูดถึงก่อนหน้านี้จำกัดอยู่ที่ การพึ่งพาขณะ build/compile
- แต่โปรเจกต์สมัยใหม่มักมี การพึ่งพาขณะรันไทม์ ด้วย:
- ตัวอย่าง: Amazon S3, Google Firebase
- บางอย่างแทบจะถูกมองว่าเป็นมาตรฐานโดยพฤตินัย (เช่น S3)
- แต่การพึ่งพาขณะรันไทม์ส่วนใหญ่มีลักษณะของการ ผูกติด (Lock-in) กับบริการเฉพาะค่อนข้างมาก
- แม้แต่ในอีก 10 ปีข้างหน้า การหาทางเลือกมาทดแทนบริการที่ใช้อยู่ในตอนนี้ก็อาจมีต้นทุนสูงมาก
- จำเป็นต้อง ทำให้รายการการพึ่งพาบริการของบุคคลที่สามน้อยที่สุด หรือให้ไม่มีเลย:
- โดยเฉพาะในการพัฒนาซอฟต์แวร์แบบ cloud native การใช้บริการของบุคคลที่สามระดับสูงจำนวนมากเป็นเรื่องปกติ
- แต่สำหรับโปรเจกต์ระยะยาว การพึ่งพาแบบนี้มาพร้อมความเสี่ยงสูง
- การพึ่งพาบริการในขั้น build time ก็เป็นปัจจัยสำคัญเช่นกัน:
- ตัวอย่าง: หาก
npm installใช้งานไม่ได้อีกต่อไป ก็จะไม่สามารถ build ซอฟต์แวร์ได้เลย - สิ่งนี้อาจลดทอน ความสามารถในการนำกลับมาใช้ใหม่ ของโปรเจกต์อย่างรุนแรง
- ตัวอย่าง: หาก
- ตรวจสอบการพึ่งพาขณะรันไทม์อย่างเข้มงวด:
- ตระหนักถึงปัญหา lock-in ที่อาจเกิดขึ้น และลดหรือตัดการพึ่งพาออก
- ทำให้มั่นใจในความสามารถในการดูแลรักษาระยะยาว:
- พิจารณาความเป็นไปได้ในการแทนที่ cloud หรือบริการของบุคคลที่สามไว้ล่วงหน้า
ทดสอบ ทดสอบ และทดสอบ
- ความจำเป็นของการทดสอบเป็น หลักการพื้นฐานที่ทุกคนเห็นพ้อง:
- เขียนการทดสอบให้ มากที่สุดเท่าที่ทำได้
- ไม่ใช่ว่าการทดสอบทุกแบบจะมีคุณค่าเท่ากัน แต่แทบไม่เคยต้องเสียใจที่มีการทดสอบ
- โดยเฉพาะใน โปรเจกต์ที่มีการพึ่งพาจำนวนมาก การทดสอบเป็นสิ่งจำเป็น:
- หากการพึ่งพาเปลี่ยนหรือค่อย ๆ เบี่ยงไปจากเดิม ก็ช่วยให้ตรวจพบปัญหาได้ตั้งแต่เนิ่น ๆ
- บทบาทของการทดสอบ
- ช่วยแก้ปัญหา:
- สามารถปรับตัวได้รวดเร็วให้เข้ากับสถานการณ์ที่เปลี่ยนไป
- ช่วยการรีแฟกเตอร์:
- ให้ความมั่นใจเมื่อต้องลบหรือเปลี่ยนการพึ่งพาของโค้ด
- มีประโยชน์ต่อการบำรุงรักษาระยะยาว:
- แม้หลังจากที่การพัฒนา หยุดไปมากกว่า 3 ปี ก็ยังใช้การทดสอบตรวจสอบได้ว่าระบบยังทำงานอยู่หรือไม่
- ตรวจสอบได้ว่าฟังก์ชันการทำงานยังคงอยู่บนคอมไพเลอร์ รันไทม์ หรือระบบปฏิบัติการใหม่หรือไม่
- ช่วยแก้ปัญหา:
- การทดสอบไม่ใช่ต้นทุน แต่คือการลงทุน
- เขียนการทดสอบให้มากขึ้น:
- การทดสอบคือรากฐานของการบำรุงรักษาและเสถียรภาพ
- เมื่อต้องแก้หรือขยายโค้ด การทดสอบเป็นแรงสนับสนุนทางใจอย่างมาก
- เขียนการทดสอบให้มากขึ้น:
ความซับซ้อน: บอสสุดท้ายของการพัฒนาซอฟต์แวร์
- ความซับซ้อนคือศัตรูตัวฉกาจสูงสุดของการพัฒนาซอฟต์แวร์:
- แม้แต่นักพัฒนาหรือทีมที่เก่งที่สุดก็อาจพังทลายเพราะความซับซ้อน
- ด้วยอิทธิพลของเอนโทรปีและพฤติกรรมมนุษย์ ความซับซ้อนจะเพิ่มขึ้นเสมอ
- หากไม่จัดการความซับซ้อนอย่างมีสติ โปรเจกต์อาจตกสู่สภาพ บำรุงรักษาต่อไม่ได้
- ความสัมพันธ์ระหว่างความซับซ้อนกับปริมาณโค้ด
- ปริมาณโค้ดและความซับซ้อน:
- เมื่อโค้ดยังน้อย แม้จะซับซ้อนบ้างก็ยังพอจัดการได้
- ยิ่งโค้ดเพิ่มขึ้น ก็ยิ่งต้องรักษาความเรียบง่ายไว้จึงจะควบคุมได้
- ความซับซ้อนที่จัดการได้ต้องอยู่ภายในขีดความสามารถของทีมและภายใน "สามเหลี่ยมสีเขียว"
- ขีดจำกัดของความซับซ้อน:
- ต่อให้เพิ่มจำนวนคนในทีมหรือจ้างนักพัฒนาที่เก่งมาก ก็ยังมีขีดจำกัดในการรับมือความซับซ้อน
- เมื่อเลยขีดจำกัดไป โปรเจกต์จะตกอยู่ในสภาพที่บำรุงรักษาไม่ได้
- ปริมาณโค้ดและความซับซ้อน:
- เหตุผลที่โค้ดมักเคลื่อนไปทาง 'ขวาบน' อยู่เสมอ: (ในกราฟ)
- มีการร้องขอฟีเจอร์เพิ่มขึ้น
- มีความพยายามทำ optimization ที่ไม่จำเป็น
- เวลาแก้บั๊กมักเพิ่มโค้ดใหม่ แทนที่จะลดความซับซ้อนเดิม
- ต้นทุนของการออกแบบ API ที่ไม่ดี:
- ตัวอย่าง: ฟังก์ชัน
CreateFileในหลายกรณีกลับไม่ได้สร้างไฟล์จริง ๆ - ความสับสนแบบนี้เพิ่ม ภาระทางการรับรู้ และเพิ่มโอกาสผิดพลาด
- ตัวอย่าง: ฟังก์ชัน
- กลยุทธ์การจัดการความซับซ้อน
- รีแฟกเตอร์ให้เร็ว และทำบ่อย ๆ:
- ลบโค้ดที่ไม่จำเป็น และลงทุนเวลากับการทำให้เรียบง่าย
- ลงทุนกับการทดสอบ:
- ยิ่งมีการทดสอบมาก การลดความซับซ้อนก็ยิ่งทำได้ง่าย
- ความสำคัญของการจัดการความซับซ้อน:
- หากไม่ พยายามล่วงหน้า เพื่อทำให้เรียบง่าย โปรเจกต์ระยะยาวก็เสี่ยงจะลงเอยในสภาพ "บำรุงรักษาไม่ได้"
- รีแฟกเตอร์ให้เร็ว และทำบ่อย ๆ:
เขียนโค้ดที่น่าเบื่อและเรียบง่าย ให้เรียบง่ายกว่านั้นอีก และให้น่าเบื่อกว่านั้นอีก
"การดีบักยากกว่าการเขียนโปรแกรมสองเท่า ดังนั้นถ้าคุณเขียนโค้ดให้ฉลาดที่สุดเท่าที่ทำได้ตอนเขียน แล้วคุณจะดีบักมันได้อย่างไร?" - Brian Kernighan
- เขียนโค้ดที่น่าเบื่อสุด ๆ และชัดเจน:
- ให้ความสำคัญกับโค้ดแบบ naïve แต่ เข้าใจได้อย่างเป็นสัญชาตญาณ
- "optimization ระดับพรีเมียมคือรากเหง้าของความชั่วร้ายทั้งปวง"
- ทำ optimization เท่าที่จำเป็นจริง ๆ เท่านั้น:
- ถ้ามันเรียบง่ายเกินไปจนกลายเป็นปัญหา การเพิ่มความซับซ้อนทีหลังไม่ใช่เรื่องยาก
- และช่วงเวลานั้นอาจไม่มาถึงเลยก็ได้
- หลีกเลี่ยงการเขียนโค้ดซับซ้อน:
- รอจนกว่าจะถึงเวลาที่จำเป็นจริง ๆ
- โอกาสที่จะเสียใจเพราะเขียนโค้ดเรียบง่ายนั้นต่ำมาก
- โค้ดหรือฟังก์ชันที่มีประสิทธิภาพสูงอาจทำงานได้เฉพาะในบางสภาพแวดล้อมเท่านั้น
- ตัวอย่าง:
- LMDB: กว่า PowerDNS จะใช้งานได้อย่างเสถียรก็ผ่านความยากลำบากมามาก
- RapidJSON: ไลบรารี JSON ที่เร่งด้วย SIMD ประสิทธิภาพสูงมาก แต่เงื่อนไขในการใช้งานค่อนข้างเข้มงวด
- ตัวอย่าง:
- ต่อให้คุณมั่นใจว่า "ฉันเอาชนะข้อจำกัดนี้ได้":
- ปีนี้อาจทำได้ แต่ในอีก 5 ปีข้างหน้า ตัวคุณเองหรือผู้พัฒนาคนถัดไปอาจเจอความยากลำบาก
- หลักการเดียวกันนี้ใช้กับ ภาษาการเขียนโปรแกรมที่ซับซ้อน เช่นกัน
- สรุป:
- ทำให้โค้ดเรียบง่าย:
- เรียบง่ายจริง ๆ และให้เรียบง่ายกว่านั้นอีก
- เลื่อน optimization ไปทีหลัง:
- ความซับซ้อนสามารถเพิ่มภายหลังได้เมื่อจำเป็น แต่ถ้าทำให้ซับซ้อนตั้งแต่ต้น การบำรุงรักษาจะยากขึ้น
- ทำให้โค้ดเรียบง่าย:
การพัฒนาซอฟต์แวร์แบบอิง LinkedIn
- ความจริง vs. อุดมคติ
- แนวทางในอุดมคติ: เมื่อต้องเลือกการพึ่งพา ควรมีการประเมินและทบทวนอย่างละเอียด (ใช้เช็กลิสต์ที่เสนอไว้ข้างต้น)
- แนวทางในโลกจริง: บางครั้งก็มักจะลองเทคโนโลยีที่ดูน่าสนใจ และถ้ามันใช้ได้ก็ใช้ต่อไปเลย
- เหตุผลที่มันดึงดูดใจ
- เป็นเทคโนโลยีที่คนดังหรืออินฟลูเอนเซอร์บน LinkedIn แนะนำ
- เป็น "เฟรมเวิร์กล่าสุด" ที่ได้รับคำชมล้นหลามในชุมชนอย่าง Hacker News
- เทคโนโลยีกระแสนิยมขาดการพิสูจน์ในระยะยาว:
- อาจไม่เหมาะกับ "โครงการซอฟต์แวร์ที่จะต้องอยู่เกิน 10 ปี"
- เทคโนโลยีใหม่มีโอกาสสูงที่จะเกิดปัญหาในด้านเสถียรภาพและการบำรุงรักษาในช่วงแรก
- ข้อแนะนำ
- ใช้เฉพาะในพื้นที่เชิงทดลอง:
- ควรทดลองเทคโนโลยีใหม่กับโปรเจกต์เล็กหรือส่วนที่ไม่ใช่แกนหลักก่อน
- คำนึงถึง Lindy effect:
- อายุขัยของเทคโนโลยีมักมีแนวโน้มเป็นสัดส่วนกับระยะเวลาที่มันถูกใช้งานมาแล้ว
- ยิ่งเป็นเทคโนโลยีเก่า ก็ยิ่งคาดหวังเสถียรภาพระยะยาวได้มากขึ้น
- ใช้เฉพาะในพื้นที่เชิงทดลอง:
- เทคโนโลยีใหม่อาจน่าดึงดูด แต่สำหรับโปรเจกต์ระยะยาว เทคโนโลยีที่ผ่านการพิสูจน์แล้วและมั่นคงย่อมเหมาะสมกว่า
Logging, telemetry, ประสิทธิภาพ
- หากซอฟต์แวร์ไม่ได้รับการอัปเดตหรือ deploy อย่างต่อเนื่อง:
- เมื่อเว็บไซต์พัง อาจไม่ได้รับ feedback ทันที
- หลัง deploy แล้วอาจใช้เวลานานกว่าจะไปถึงการแก้ปัญหาจริง
- ตั้งแต่รีลีสแรก ควรทำ logging และ telemetry อย่างรัดกุม:
- บันทึก ประสิทธิภาพ, ความล้มเหลว, และ กิจกรรมการทำงาน ของซอฟต์แวร์
- เมื่อเวลาผ่านไป ข้อมูลที่สะสมจะมีประโยชน์มากต่อการแก้บั๊กที่เกิดขึ้นไม่บ่อย
- ปัญหาจาก logging ที่ไม่เพียงพอ:
- มีการ deploy UI ให้ผู้ใช้ แต่มีผู้ใช้รายหนึ่งที่สร้าง 3000 โฟลเดอร์ แล้วรายงานปัญหา
- ผู้ใช้บอกเพียงว่า "มันไม่ทำงาน" ทำให้ใช้เวลาหลายเดือนกว่าจะระบุสาเหตุที่แท้จริงได้
- หากมี performance logging และ telemetry ก็อาจแก้ปัญหาได้เร็วกว่าเดิมมาก
- logging และ telemetry เป็นสิ่งจำเป็น:
- ควรออกแบบให้สามารถเฝ้าติดตามกิจกรรมของซอฟต์แวร์ได้อย่างละเอียด
- ช่วยอย่างมากในการแก้ปัญหาที่ไม่คาดคิดระหว่างการ deploy และบำรุงรักษาในระยะยาว
เอกสาร
- ความสำคัญของเอกสาร:
- ไม่ใช่แค่เขียนเอกสาร API ให้ดี แต่ต้องอธิบายด้วยว่า "ทำไมจึงออกแบบแบบนี้"
- บันทึกแนวคิดและปรัชญาเกี่ยวกับการทำงานของระบบ
- ควรทิ้งเหตุผลไว้ว่า ทำไมจึงแยกวิธีแก้ออกมา และเหตุใดจึงตัดสินใจเชิงออกแบบที่ไม่ชวนให้เข้าใจทันที
- สื่อที่มีประโยชน์นอกเหนือจากเอกสารสถาปัตยกรรม:
- บล็อกโพสต์ภายใน: ให้นักพัฒนาแบ่งปันการอภิปรายอย่างอิสระเกี่ยวกับการออกแบบระบบ
- การสัมภาษณ์ทีม: บันทึกบทสนทนาที่บอกภูมิหลังของการตัดสินใจด้านการออกแบบ
- เอกสารเหล่านี้ช่วยถ่ายทอดความรู้ภายในทีมได้แม้เวลาจะผ่านไป
- ใส่คอมเมนต์ไว้ในโค้ด:
- แม้จะมีแนวโน้มที่ว่า "โค้ดที่ดีไม่ต้องมีคอมเมนต์" แต่ คอมเมนต์ที่อธิบาย 'ทำไม' ของโค้ดนั้นจำเป็นอย่างยิ่ง
- สิ่งสำคัญคือการอธิบายเหตุผลว่าทำไมฟังก์ชันนั้นจึงมีอยู่
- เขียน commit message:
- commit message คือแกนหลักของบันทึกการทำงาน ซึ่งช่วยให้ติดตามเหตุผลของการเปลี่ยนแปลงโค้ดได้
- ควรจัดสภาพแวดล้อมให้ผู้ใช้สามารถเปิดดู commit message ได้ง่าย
- จัดสรรเวลาสำหรับการทำเอกสาร:
- ในวันที่การพัฒนาไม่ค่อยราบรื่น ควรใช้เวลาไปกับการเขียนคอมเมนต์และบันทึกที่มีประโยชน์
- ในระดับทีม ควรจัดเวลาให้การทำเอกสารอย่างสม่ำเสมอ
- บันทึกว่าเหตุใดจึงออกแบบเช่นนั้น:
- อีก 7 ปีข้างหน้า เอกสารที่ส่งต่อปรัชญาและภูมิหลังให้ทีมใหม่ได้จะมีค่ามากที่สุด
- เก็บประวัติผ่านคอมเมนต์และ commit message:
- เป็นองค์ประกอบสำคัญ ไม่ใช่แค่ระหว่างการพัฒนา แต่รวมถึงการบำรุงรักษาในระยะยาวด้วย
การจัดทีม
- ความต่อเนื่องของทีมกับความสำเร็จระยะยาวของซอฟต์แวร์:
- ซอฟต์แวร์บางประเภทถูกออกแบบมาให้รองรับนานถึง 80 ปี ในโปรเจกต์ระยะยาวเช่นนี้ การรักษาทีมไว้คือหัวใจสำคัญ
- ในสภาพแวดล้อมการพัฒนาสมัยใหม่ การทำงานอยู่ราว 3 ปีมักถูกมองว่านานแล้ว
- เอกสารและการทดสอบที่ดีช่วยบรรเทาปัญหาการเปลี่ยนทีมได้ในระดับหนึ่ง แต่ก็มีขีดจำกัด
- ข้อดีของการทำงานระยะยาว:
- รักษาสมาชิกทีมให้อยู่เกิน 10 ปี:
- การจ้างเป็นพนักงานจริงและดูแลนักพัฒนาอย่างเหมาะสมเป็นสิ่งสำคัญ
- ถือเป็น "hack" สำคัญต่อความสำเร็จของโปรเจกต์ระยะยาว
- รักษาสมาชิกทีมให้อยู่เกิน 10 ปี:
- ปัญหาของการพึ่งพางาน outsource:
- นักพัฒนาภายนอกมักส่งมอบโค้ดให้ระบบแล้วก็จากไป
- หากเป้าหมายคือคุณภาพซอฟต์แวร์ที่ยั่งยืนเกิน 10 ปี นี่เป็นวิธีที่ไม่มีประสิทธิภาพอย่างยิ่ง
- สร้างสภาพแวดล้อมที่สมาชิกทีมสามารถทำงานร่วมกันได้ในระยะยาว
- ต้องมีกลยุทธ์ลดการพึ่งพาที่ปรึกษาภายนอก และเพิ่มความยั่งยืนของทีมภายใน
พิจารณาโอเพนซอร์ส
- ข้อดีของโอเพนซอร์ส:
- รักษาคุณภาพโค้ดผ่านการตรวจสอบจากภายนอก:
- สายตาจากภายนอก ทำให้นักพัฒนาต้องรักษามาตรฐานที่สูงขึ้น
- เป็นกลไกที่ทรงพลังในการรักษามาตรฐานโค้ดให้ดีขึ้น
- รักษาคุณภาพโค้ดผ่านการตรวจสอบจากภายนอก:
- ความเป็นจริงของการเตรียมโอเพนซอร์ส:
- องค์กรหรือหน่วยงานรัฐมักอ้างว่าการเตรียมเปิดโอเพนซอร์สต้องใช้เวลาหลายเดือนถึงหลายปี
- เหตุผล:
- ภายในองค์กรมักเขียนโค้ดที่รู้สึกอายจะเปิดเผยต่อภายนอกกันเป็นเรื่องปกติ
- จึงต้องจัดระเบียบโค้ดก่อนเปิดเป็นโอเพนซอร์ส
- ประเมินความเหมาะสมในการใช้งาน:
- โอเพนซอร์สไม่ใช่ตัวเลือกที่เป็นไปได้เสมอไป
- หากทำได้ ก็เป็นวิธีที่ดีในการยกระดับคุณภาพโค้ดและความโปร่งใส
- โอเพนซอร์สเป็นกลยุทธ์สำคัญที่ควรใช้เมื่อมีโอกาส
- สายตาจากภายนอกและมาตรฐานที่สูงช่วยพาโปรเจกต์ไปในทิศทางที่ถูกต้อง
การตรวจสุขภาพของการพึ่งพา
- ปัญหาของการเปลี่ยนแปลงในการพึ่งพา:
- การพึ่งพาอาจ เปลี่ยนแปลง หรือ เบี่ยงเบน ไปจากที่คาดหวังเมื่อเวลาผ่านไป
- หากปล่อยไว้ อาจนำไปสู่:
- บั๊ก
- build ล้มเหลว
- และผลลัพธ์น่าผิดหวังอื่น ๆ
- แนะนำให้ตรวจสุขภาพอย่างสม่ำเสมอ:
- ตรวจสอบการพึ่งพาเป็นระยะ:
- ช่วยให้มีโอกาสพบปัญหาล่วงหน้า
- ยังช่วยค้นพบความสามารถใหม่ของการพึ่งพา ซึ่งอาจเปิดทางให้ลดความซับซ้อนของโค้ดหรือถอดการพึ่งพาอื่นออกได้
- ความสำคัญของการบำรุงรักษาเชิงป้องกัน:
- หากคุณไม่วางแผนเวลาเพื่อตรวจสอบเอง สุดท้ายก็จะต้องถูกบังคับให้เสียเวลาเมื่อปัญหาเกิดขึ้นจริง
- ตรวจสอบการพึ่งพาเป็นระยะ:
- อุปมาของการบำรุงรักษา:
- คำกล่าวของช่างเครื่อง:
- "จงวางแผนเวลาสำหรับการบำรุงรักษาด้วยตัวเอง ไม่เช่นนั้นอุปกรณ์จะเป็นฝ่ายวางแผนเวลานั้นให้คุณ"
- คำกล่าวของช่างเครื่อง:
- การตรวจสุขภาพของการพึ่งพาเป็นประจำคือกิจกรรมจำเป็นต่อเสถียรภาพและประสิทธิภาพของซอฟต์แวร์ในระยะยาว
- ใช้สิ่งนี้เป็นโอกาสในการแก้ปัญหาล่วงหน้า และค้นพบการเปลี่ยนแปลงเชิงบวก
หนังสืออ้างอิงสำคัญ
- The Practice of Programming (Brian W. Kernighan, Rob Pike)
- The Mythical Man-Month (Fred Brooks)
- A Philosophy of Software Design (John Ousterhout)
- Kill It with Fire: Manage Aging Computer Systems (Marianne Bellotti)
สุดท้าย
คำแนะนำสำคัญสำหรับการพัฒนาซอฟต์แวร์ระยะยาว:
- รักษาความเรียบง่าย:
- ทำให้เรียบง่าย และเรียบง่ายกว่านั้นอีก! เพราะสามารถเพิ่มความซับซ้อนได้เมื่อจำเป็น ดังนั้นอย่าทำให้ซับซ้อนเกินไปตั้งแต่แรก
- การรักษาความเรียบง่ายต้องอาศัย การรีแฟกเตอร์และการลบโค้ดเป็นประจำ
- คิดเรื่องการพึ่งพาอย่างรอบคอบ:
- ยิ่งมีการพึ่งพาน้อยยิ่งดี ควร ตรวจสอบอย่างละเอียด และทำ audit
- หากคุณไม่สามารถ audit การพึ่งพา 1600 รายการได้ ก็ควรทบทวนแผนใหม่
- หลีกเลี่ยงการเลือกตามเทรนด์หรือกระแส (เช่น การพัฒนาแบบอิง LinkedIn)
- ตรวจสอบการพึ่งพาเป็นประจำ: ติดตามสถานะของการพึ่งพาอย่างต่อเนื่อง
- ทดสอบ ทดสอบ และทดสอบ:
- เพื่อให้ทันต่อการเปลี่ยนแปลงของการพึ่งพา
- ช่วยเพิ่มความมั่นใจระหว่างการรีแฟกเตอร์ และช่วยรักษาความเรียบง่าย
- เอกสาร:
- ไม่ใช่แค่ตัวโค้ด แต่รวมถึงปรัชญา แนวคิด และภูมิหลังของ "ทำไมจึงทำแบบนี้" ด้วย
- เป็นทรัพย์สินล้ำค่าสำหรับสมาชิกทีมในอนาคต
- รักษาทีมที่มั่นคง:
- สำหรับการลงทุนในโปรเจกต์ระยะยาว ควรพิจารณา การจ้างงานระยะยาว
- สนับสนุนให้สมาชิกทีมทุ่มเทกับโปรเจกต์ได้ต่อเนื่องเป็นเวลานาน
- พิจารณาโอเพนซอร์ส:
- หากทำได้ โอเพนซอร์สช่วยรักษามาตรฐานโค้ดให้สูงขึ้น
- ล็อกและ performance telemetry:
- มีบทบาทสำคัญในการค้นหาและแก้ปัญหาได้ตั้งแต่เนิ่น ๆ
- คำแนะนำเหล่านี้อาจไม่ใช่เรื่องใหม่ แต่เมื่อเป็นสิ่งที่นักพัฒนามากประสบการณ์ย้ำอยู่เสมอ ก็มีคุณค่ามากพอที่จะนำมาคิดอย่างจริงจัง
4 ความคิดเห็น
การแยกเลเยอร์ที่ความเสถียรมีความสำคัญออกจากเลเยอร์ที่ความเร็วมีความสำคัญ และการจัดการความสัมพันธ์ระหว่างสองส่วนนี้อย่างไร คือพลังทางวิศวกรรมที่สำคัญที่สุด
ถ้า Toss มุ่งแต่ความเสถียรอย่างเดียว ก็คงไม่ต่างอะไรจากธนาคารอื่น ๆ
ที่เสี่ยงก็อย่าง SpaceX ด้วยครับ Tesla ก็เหมือนกัน..
หรือว่าปัญหาคือการพัฒนาที่ขับเคลื่อนด้วยเรซูเม่
ความเห็นจาก Hacker News
การอัปเดต toolchain อย่างจริงจังเป็นส่วนสำคัญของกระบวนการพัฒนา หลายบริษัทลดความสำคัญของการอัปเกรด toolchain จนก่อให้เกิดปัญหาอย่างช่องโหว่ด้านความปลอดภัย ทุกครั้งที่มีการออกคอมไพเลอร์หรือระบบบิลด์เวอร์ชันใหม่ จะสร้าง branch เพื่อตรวจสอบสถานะการบิลด์ และถ้ามีข้อผิดพลาดก็ถือว่าเป็นบั๊กและจัดการทันที สิ่งนี้ช่วยให้ค่อยๆ ปรับโค้ดเบสให้ทันสมัยและรีแฟกเตอร์ด้วยความสามารถใหม่ของภาษา
การพึ่งพาไลบรารีจากภายนอกมักน่าผิดหวังในระยะยาว ในโปรเจกต์ใหม่อาจใช้ไลบรารีภายนอกเพื่อแก้ปัญหาระยะสั้นได้ แต่ในระยะยาวควรแทนที่ด้วยโค้ดที่เขียนเอง
จำเป็นต้อง vendor dependency และจัดการผ่าน code review บ่อยครั้งที่คุณภาพของโค้ดจากภายนอกต่ำ จนการเขียนเองกลับเป็นทางเลือกที่ดีกว่า
กำลังทำโปรเจกต์ที่มุ่งเน้นการขยายตัวได้ในระยะยาวโดยใช้ Qt, CMake และ C++ สมัยใหม่ เทคโนโลยีเหล่านี้ยังคงเพิ่มฟีเจอร์และการปรับปรุงอย่างต่อเนื่อง
การทำงานกับ Emacs Lisp เป็นประสบการณ์ที่สดใหม่ ข้อดีคือถึงไลบรารีจะไม่ได้อัปเดตก็ยังทำงานได้อย่างเสถียร ส่วนประสบการณ์กับ Gatsby และ Node นั้นลำบากเพราะปัญหาเรื่องการอัปเดต
การเขียนโค้ดให้เรียบง่ายเป็นสิ่งสำคัญ โค้ดซับซ้อนควรเขียนเมื่อจำเป็นเท่านั้น และเราแทบไม่เคยเสียใจกับโค้ดที่เรียบง่าย
การทำเอกสารของระบบและโค้ดเป็นสิ่งสำคัญ ยิ่งมีประสบการณ์พัฒนาซอฟต์แวร์มากเท่าไร ก็ยิ่งตระหนักถึงความสำคัญของเอกสารมากขึ้นเท่านั้น
การทดสอบมีบทบาทสำคัญในแผนงาน ควรอ้างอิงแนวทางการพัฒนาของ NASA และมุ่งเน้นการค้นหาข้อผิดพลาดในการเขียนโปรแกรม ในการพัฒนาซอฟต์แวร์ทางการแพทย์จะหลีกเลี่ยงการตีความกำกวมและไม่ใช้การจัดสรรหน่วยความจำแบบไดนามิก
วิธีที่ดีที่สุดในการเขียนซอฟต์แวร์ให้อยู่ได้นานคือการเขียนโค้ดที่ "น่าเบื่อ" ควรหลีกเลี่ยง dependency และยึดพื้นฐานให้มั่น
เคยมีประสบการณ์ลำบากกับปัญหา dependency ใน Python เรื่องนี้ถูกเรียกว่า "DLL Hell" และ COM ก็พยายามแก้ปัญหานี้แต่ไม่ประสบความสำเร็จนัก
แนวปฏิบัติที่ใช้กับซอฟต์แวร์ในภาคอุตสาหกรรมยังไม่แข็งแกร่งพอหากจะนำมาใช้กับซอฟต์แวร์ทั่วไป วิศวกรมักพยายามลดความเสี่ยง และเราก็มุ่งเน้นไปที่การลดความเสี่ยงเช่นกัน