Ch1 What is a Software Engineer
“ไม่มีอะไรที่ถูกสร้างบนหิน ทุกสิ่งถูกสร้างบนทราย แต่เราต้องสร้างมันให้ราวกับว่ามันเป็นหิน” — Jorge Luis Borges เรามองเห็นความแตกต่างที่สำคัญสามประการระหว่างการเขียนโปรแกรมและวิศวกรรมซอฟต์แวร์: เวลา ขนาด และการประนีประนอมที่เกิดขึ้น ในโครงการวิศวกรรมซอฟต์แวร์ วิศวกรจำเป็นต้องให้ความสำคัญกับระยะเวลาที่ผ่านไปและความต้องการที่จะต้องเปลี่ยนแปลง ในองค์กรด้านวิศวกรรมซอฟต์แวร์ เราจำเป็นต้องให้ความสำคัญกับขนาดและประสิทธิภาพ ทั้งในแง่ของซอฟต์แวร์ที่เราผลิตและสำหรับองค์กรที่ผลิตซอฟต์แวร์นั้น สุดท้ายนี้ ในฐานะวิศวกรซอฟต์แวร์ เราต้องทำการตัดสินใจที่ซับซ้อนมากขึ้นซึ่งมีผลลัพธ์ที่มีความเสี่ยงสูง โดยมักจะขึ้นอยู่กับการประมาณการที่ไม่แน่นอนเกี่ยวกับเวลาและการเติบโต ภายใน Google เรามักพูดกันว่า “วิศวกรรมซอฟต์แวร์คือการเขียนโปรแกรมที่ผสานเข้ากับเวลา” การเขียนโปรแกรมเป็นส่วนสำคัญของวิศวกรรมซอฟต์แวร์อย่างแน่นอน แต่โปรแกรมมิ่งจะเน้นไปที่การสร้างซอฟต์แวร์ในเบื้องต้น หากเรายอมรับความแตกต่างนี้ จะเห็นได้ชัดว่าจำเป็นต้องแยกความแตกต่างระหว่างงานเขียนโปรแกรม (development) และงานเปลี่ยนแปลงซอฟต์แวร์ (modification, maintenance) การเพิ่มมิติของเวลาและการเพิ่มมิติใหม่เข้ามาในงานเขียนโปรแกรมทำให้มีความสำคัญมากขึ้น คิวบ์ไม่ได้แค่ขนาดของพื้นที่หรือระยะทาง แต่การเขียนโปรแกรมเป็นการจัดการทั้งเวลาและการเคลื่อนที่ วิธีหนึ่งที่สามารถเห็นผลกระทบของเวลาในโปรแกรมคือการพิจารณาคำถามว่า “อายุขัยของโค้ดของคุณน่าจะเป็นเท่าไร?” คำตอบที่เหมาะสมต่อคำถามนี้จะแตกต่างไปตามค่าประมาณอย่างมาก อาจจะถึง 100,000 เท่า ตัวอย่างเช่น การจินตนาการถึงโค้ดที่จำเป็นต้องใช้เพียงไม่กี่นาทีเป็นเรื่องที่เหมือนกับการจินตนาการถึงโค้ดที่จำเป็นต้องคงอยู่ตลอดไปโดยไม่เปลี่ยนแปลง โดยทั่วไปแล้ว โค้ดในช่วงสั้น ๆ นั้นจะไม่ได้รับผลกระทบจากเวลา ในทางกลับกัน เราไม่ควรคาดหวังว่าโค้ดนั้นจะต้องปรับตัวเข้ากับเวอร์ชันใหม่ของฮาร์ดแวร์ ระบบปฏิบัติการ (OS) หรือภาษาการเขียนโปรแกรมที่จะถูกเปลี่ยนแปลงไปในช่วงเวลาสั้น ๆ ระบบที่มีอายุการใช้งานสั้นนั้นมักจะถูกมองว่าเป็น “ปัญหาโปรแกรมมิ่ง” แบบหนึ่งเช่นกัน เหมือนกับลูกบาศก์ที่ถูกบีบอัดไว้ในมิติต่าง ๆ เมื่อเราขยายเวลาออกไปเพื่อให้ระบบใช้งานได้ยาวนานขึ้น ความสำคัญของการเปลี่ยนแปลงก็จะยิ่งชัดเจนขึ้น ในช่วงเวลาหนึ่งทศวรรษหรือมากกว่านั้น การพึ่งพิงระหว่างโปรแกรมจำนวนมาก โดยที่เป็นการพึ่งพิงทั้งที่ชัดเจนและไม่ชัดเจน จะกลายเป็นเรื่องสำคัญ การตระหนักถึงความจริงข้อนี้คือสิ่งที่แยกแยะระหว่างวิศวกรรมซอฟต์แวร์และการเขียนโปรแกรม ความแตกต่างนี้คือแก่นแท้ของสิ่งที่เราเรียกว่า sustainability สำหรับซอฟต์แวร์ โครงการของคุณยั่งยืนหากคุณสามารถตอบสนองต่อการเปลี่ยนแปลงที่มีค่าได้ในระยะเวลาการใช้งานที่คาดการณ์ได้ของซอฟต์แวร์นั้น คุณจะต้องสามารถตอบสนองต่อการเปลี่ยนแปลงใหม่ ๆ ที่มีค่าไม่ว่าจะเป็นด้านเทคนิคหรือด้านธุรกิจได้อย่างทันท่วงที สิ่งที่สำคัญคือ เรามองหาความสามารถในการเปลี่ยนแปลง หากคุณไม่สามารถปรับตัวให้เข้ากับเทคโนโลยีพื้นฐานหรือทิศทางการผลิตใหม่ ๆ ได้ทันเวลา คุณจะต้องแบกรับความเสี่ยงที่สูงขึ้นในขณะที่การเปลี่ยนแปลงที่สำคัญจะไม่เกิดขึ้นเลย สำหรับโครงการระยะสั้น สิ่งนี้อาจเป็นทางออกที่ปลอดภัย แต่ถ้าเป็นโครงการที่ทำระยะยาวแล้ว มันอาจจะไม่ใช่ตัวเลือกที่ดีนัก อีกวิธีหนึ่งในการพิจารณาวิศวกรรมซอฟต์แวร์คือการพิจารณาขนาดของงาน มีคนจำนวนเท่าใดที่เกี่ยวข้อง? พวกเขามีบทบาทอะไรในการพัฒนาและดูแลรักษาระบบในระยะยาว? งานเขียนโปรแกรมมักจะถูกมองว่าเป็นการสร้างสรรค์ในระดับบุคคล ในขณะที่วิศวกรรมซอฟต์แวร์นั้นเป็นความพยายามของทีม ความพยายามเบื้องต้นในการนิยามวิศวกรรมซอฟต์แวร์ได้กล่าวถึงแนวคิดนี้ว่า “การพัฒนาซอฟต์แวร์โดยคนหลายคน” สิ่งนี้ชี้ให้เห็นถึงความแตกต่างระหว่างวิศวกรรมซอฟต์แวร์กับการเขียนโปรแกรมว่าเป็นทั้งเรื่องของเวลาและคน การทำงานร่วมกันของทีมก่อให้เกิดปัญหาใหม่ ๆ แต่ในขณะเดียวกันก็นำไปสู่โอกาสที่จะผลิตผลลัพธ์ที่มีค่าได้มากกว่าการทำงานคนเดียว การจัดองค์กรของทีม องค์ประกอบของโครงการ และนโยบายการปฏิบัติในการพัฒนาซอฟต์แวร์ล้วนมีบทบาทที่สำคัญในการเพิ่มความซับซ้อนของวิศวกรรมซอฟต์แวร์ เมื่อองค์กรเติบโตและโครงการมีขนาดใหญ่ขึ้น จะเกิดประสิทธิภาพมากขึ้นในผลิตซอฟต์แวร์หรือไม่? หรือว่าเวิร์กโฟลว์การพัฒนาของเราจะล้าหลังไปเมื่อเทียบกับความเติบโต?
เมื่อองค์กรเติบโตขึ้น เราจะมีประสิทธิภาพมากขึ้น หรือว่าแนวทางควบคุมเวอร์ชันและกลยุทธ์การทดสอบของเราจะมีค่าใช้จ่ายเพิ่มขึ้นตามขนาดหรือไม่? ปัญหาเกี่ยวกับการขยายตัวของทีมมนุษย์ได้ถูกพูดถึงมาตั้งแต่ยุคแรกของวิศวกรรมซอฟต์แวร์ ซึ่งย้อนกลับไปถึง Mythical Man Month ปัญหาเหล่านี้มักจะเป็นเรื่องเกี่ยวกับนโยบายและเป็นพื้นฐานสำคัญของคำถามเรื่องความยั่งยืนของซอฟต์แวร์: เราจะต้องเสียค่าใช้จ่ายเท่าใดในการทำสิ่งที่ต้องทำซ้ำๆ?
เรายังสามารถกล่าวได้ว่าวิศวกรรมซอฟต์แวร์นั้นแตกต่างจากการเขียนโปรแกรมในแง่ของความซับซ้อนของการตัดสินใจที่ต้องทำและการเดิมพันในสิ่งเหล่านั้น ในวิศวกรรมซอฟต์แวร์ เราจำเป็นต้องประเมินการแลกเปลี่ยนระหว่างเส้นทางที่ต้องเดินด้วยค่าใช้จ่ายสูงและมีค่าอย่างไม่แน่นอนโดยใช้การวัดค่าที่ไม่สมบูรณ์ งานของวิศวกรซอฟต์แวร์หรือหัวหน้าวิศวกรซอฟต์แวร์คือมุ่งเน้นไปที่การรักษาความยั่งยืนและการจัดการขนาดขององค์กร ผลิตภัณฑ์ และเวิร์กโฟลว์การพัฒนา ด้วยข้อมูลเหล่านี้ เราประเมินการแลกเปลี่ยนของคุณและตัดสินใจเชิงปฏิบัติการ คุณอาจจะต้องเลื่อนการเปลี่ยนแปลงบางอย่าง การปรับปรุง หรือเลือกนโยบายที่ไม่เหมาะกับการขยายตัวโดยรู้ว่าคุณจะต้องกลับไปทบทวนการตัดสินใจเหล่านั้นในภายหลัง ตัวเลือกเหล่านั้นควรมีความชัดเจนและระบุไว้อย่างชัดเจนถึงต้นทุนที่เลื่อนออกไป
แทบจะไม่เคยมีวิธีแก้ปัญหาแบบ “ใช้ได้กับทุกกรณี” ในวิศวกรรมซอฟต์แวร์ และแนวคิดนี้ก็ใช้ได้กับหนังสือเล่มนี้เช่นกัน เมื่อคำนึงถึงการประมาณความแตกต่างในลำดับ 100,000 สำหรับคำถามที่ว่า “ซอฟต์แวร์นี้จะมีอายุการใช้งานนานแค่ไหน” คำตอบที่อาจต่างกันไปถึง 10,000 เท่าเกี่ยวกับ “มีวิศวกรจำนวนเท่าใดในองค์กรของคุณ” และคำตอบที่ไม่มีใครรู้ว่า “มีทรัพยากรคอมพิวเตอร์สำหรับโครงการของคุณมากแค่ไหน” ประสบการณ์ของ Google อาจจะไม่ตรงกับของคุณ ในหนังสือเล่มนี้ เรามุ่งนำเสนอสิ่งที่เราพบว่าทำงานได้ดีสำหรับเราในการสร้างและบำรุงรักษาซอฟต์แวร์ที่เราคาดว่าจะมีอายุการใช้งานนานหลายทศวรรษ โดยมีวิศวกรหลายพันคนและทรัพยากรการประมวลผลขนาดใหญ่ ส่วนใหญ่แล้ว สิ่งที่เราพบว่าจำเป็นในระดับนั้นจะทำงานได้ดีสำหรับโครงการเล็ก ๆ ด้วย ในบางกรณี การขยายองค์กรขนาดใหญ่มาพร้อมกับต้นทุนของตัวเอง และเรายินดีที่จะไม่ต้องจ่ายค่าใช้จ่ายเหล่านั้น เราเรียกสิ่งนี้ว่าเป็นคำเตือน หวังว่าเมื่อองค์กรของคุณเติบโตมากพอจนต้องกังวลเกี่ยวกับต้นทุนเหล่านั้น คุณจะหาวิธีที่ดีกว่าในการแก้ปัญหา
ก่อนที่เราจะเจาะลึกในเรื่องการทำงานร่วมกัน วัฒนธรรม นโยบาย และเครื่องมือ ลองมาขยายความเพิ่มเติมเกี่ยวกับหัวข้อหลักเหล่านี้กันก่อน: เวลา ขนาด และการประนีประนอม
เวลาและการเปลี่ยนแปลง
เมื่อผู้เริ่มต้นเรียนการเขียนโปรแกรม อายุขัยของโค้ดที่สร้างมักจะถูกวัดเป็นชั่วโมงหรือวัน การมอบหมายและแบบฝึกหัดการเขียนโปรแกรมมักจะถูกเขียนครั้งเดียวโดยแทบไม่มีการแก้ไขใด ๆ และแน่นอนว่าไม่มีการบำรุงรักษาระยะยาว โปรแกรมเหล่านี้มักจะไม่ถูกสร้างขึ้นใหม่หรือนำไปใช้งานอีกเลยหลังจากการผลิตครั้งแรก เรื่องนี้ไม่ใช่สิ่งที่น่าแปลกใจในสภาพแวดล้อมเชิงการศึกษา บางทีในระดับมัธยมปลายหรือหลังมัธยมศึกษา เราอาจพบหลักสูตรการทำงานเป็นทีมหรือการฝึกปฏิบัติแบบลงมือทำ โดยปกติแล้ว นี่จะเป็นช่วงเวลาที่นักเรียนจะเขียนโค้ดที่มีอายุขัยเกินหนึ่งเดือนหรือนานกว่านั้น นักพัฒนาที่มีประสบการณ์อาจจำเป็นต้อง refactor โค้ดบ้างเพื่อตอบสนองต่อความต้องการที่เปลี่ยนแปลงไป แต่ก็ไม่เป็นที่คาดหมายว่าพวกเขาจะได้จัดการกับการเปลี่ยนแปลงที่กว้างขวางมากขึ้นในสภาพแวดล้อมนี้
เรายังพบการพัฒนาโค้ดที่มีอายุขัยสั้นในสภาพแวดล้อมอุตสาหกรรมทั่วไป แอปบนอุปกรณ์เคลื่อนที่มักจะมีอายุขัยที่ค่อนข้างสั้น และไม่ว่าจะดีหรือแย่ รีไรต์ (rewrite) โค้ดทั้งหมดก็เป็นเรื่องที่ค่อนข้างธรรมดา วิศวกรในสตาร์ทอัพระยะเริ่มต้นอาจเลือกอย่างเหมาะสมที่จะเน้นเป้าหมายที่จำเป็นต้องบรรลุในทันที เพราะบริษัทอาจไม่อยู่นานพอที่จะได้รับผลประโยชน์จากการลงทุนในโครงสร้างพื้นฐานที่ให้ผลตอบแทนช้า นักพัฒนาสตาร์ทอัพที่ทำงานต่อเนื่องกันอาจมีประสบการณ์การพัฒนานานถึง 10 ปี แต่แทบจะไม่มีหรือไม่มีประสบการณ์ในการรักษาซอฟต์แวร์ใด ๆ ให้มีอายุยืนกว่า 1-2 ปีเลย
ในอีกด้านหนึ่งของสเปกตรัม โครงการที่ประสบความสำเร็จบางโครงการมีอายุขัยที่ไม่จำกัดอย่างมีประสิทธิภาพ เราไม่สามารถทำนายจุดสิ้นสุดของ Google Search ได้ หรือโครงการ Apache HTTP Server Project สำหรับโครงการของ Google ส่วนใหญ่ เราต้องสมมติว่าพวกเขาจะมีชีวิตอยู่ตลอดไป — เราไม่สามารถทำนายได้ว่าเมื่อไรที่เราจำเป็นต้องอัปเกรดการพึ่งพา ภาษาการเขียนโปรแกรม หรือสิ่งอื่น ๆ เมื่อพวกเขามีอายุยืนขึ้น โครงการระยะยาวเหล่านี้จะมีความรู้สึกที่แตกต่างจากการมอบหมายงานเขียนโปรแกรมหรือการพัฒนาสตาร์ทอัพ
ลองพิจารณารูปที่ 1-1 ซึ่งแสดงให้เห็นถึงสองโครงการซอฟต์แวร์ที่อยู่คนละฝั่งของสเปกตรัม “อายุขัยที่คาดหวัง” สำหรับโปรแกรมเมอร์ที่ทำงานในงานที่มีอายุขัยเป็นชั่วโมง งานบำรุงรักษาประเภทใดที่เหมาะสมที่ควรคาดหวัง? นั่นคือ ถ้ามีเวอร์ชันใหม่ของระบบปฏิบัติการออกมาในขณะที่คุณกำลังทำงานบนสคริปต์ Python ที่จะถูกรันเพียงครั้งเดียว คุณควรจะหยุดสิ่งที่คุณกำลังทำอยู่แล้วอัปเกรดหรือไม่? แน่นอนว่าการอัปเกรดไม่ใช่เรื่องสำคัญ แต่ในฝั่งตรงข้ามของสเปกตรัม การที่ Google Search ต้องติดอยู่บนเวอร์ชันของระบบปฏิบัติการที่ออกในยุค 1990 จะเป็นปัญหาที่เห็นได้ชัด
กฎของ Hyrum
หากคุณดูแลโครงการที่ถูกใช้งานโดยวิศวกรคนอื่น ๆ บทเรียนที่สำคัญที่สุดเกี่ยวกับ “มันทำงาน” เทียบกับ “มันสามารถดูแลรักษาได้”
“เมื่อมีผู้ใช้งาน API เพียงพอ มันจะไม่สำคัญว่าคุณให้คำสัญญาอะไรในสัญญา: พฤติกรรมที่สามารถสังเกตได้ทั้งหมดของระบบของคุณจะถูกพึ่งพาโดยใครบางคน”
จากประสบการณ์ของเรา ข้อความนี้เป็นปัจจัยสำคัญในการอภิปรายใด ๆ เกี่ยวกับการเปลี่ยนแปลงซอฟต์แวร์เมื่อเวลาผ่านไป มันเชื่อมโยงกับแนวคิดเรื่องเอนโทรปี: การอภิปรายเกี่ยวกับการเปลี่ยนแปลงและการบำรุงรักษาเมื่อเวลาผ่านไปต้องคำนึงถึงกฎของ Hyrum เช่นเดียวกับที่การอภิปรายเกี่ยวกับประสิทธิภาพหรือเทอร์โมไดนามิกส์ต้องคำนึงถึงเอนโทรปี การที่เอนโทรปีไม่เคยลดลงไม่ได้หมายความว่าเราควรละเลยความพยายามที่จะมีประสิทธิภาพ การที่กฎของ Hyrum จะมีผลเมื่อดูแลซอฟต์แวร์ไม่ได้หมายความว่าเราไม่สามารถวางแผนหรือพยายามเข้าใจมันได้ดีขึ้น เราสามารถลดผลกระทบได้ แต่เรารู้ดีว่ามันไม่สามารถกำจัดออกไปได้ทั้งหมด
กฎของ Hyrum แสดงถึงความรู้ทางปฏิบัติที่ว่า—ถึงแม้เราจะมีเจตนาที่ดีที่สุด วิศวกรที่ดีที่สุด และการปฏิบัติที่ดีในการตรวจสอบโค้ด—เราไม่สามารถคาดหวังว่าจะสามารถปฏิบัติตามสัญญาที่เผยแพร่หรือการปฏิบัติที่ดีที่สุดได้อย่างสมบูรณ์ ในฐานะเจ้าของ API คุณจะได้รับความยืดหยุ่นและอิสระบางประการจากการที่สัญญาของอินเทอร์เฟซชัดเจน แต่ในการปฏิบัติจริง ความซับซ้อนและความยากลำบากของการเปลี่ยนแปลงใด ๆ ขึ้นอยู่กับว่าผู้ใช้พบพฤติกรรมที่สามารถสังเกตได้ของ API ของคุณมากน้อยเพียงใด หากผู้ใช้ไม่สามารถพึ่งพาพฤติกรรมเหล่านั้นได้ API ของคุณจะเปลี่ยนแปลงได้ง่าย แต่ถ้ามีเวลามากพอและผู้ใช้มากพอ แม้แต่การเปลี่ยนแปลงที่ดูเหมือนไม่มีผลกระทบอะไร ก็ จะ ทำให้บางอย่างล้มเหลว การวิเคราะห์มูลค่าของการเปลี่ยนแปลงนั้นจำเป็นต้องรวมถึงความยากลำบากในการสืบสวน หาสาเหตุ และแก้ไขการล้มเหลวนั้นด้วย