07 · Software Engineering
07 · วิศวกรรมซอฟต์แวร์
This chapter is the floor where a program stops being a text that runs and becomes an object that has to survive being changed.
ชั้นนี้คือจุดที่โปรแกรมเลิกเป็นข้อความที่รันได้ และกลายเป็นวัตถุที่ต้องรอดจากการถูกแก้
Why does software rot when it has no moving parts?
ซอฟต์แวร์ไม่มีชิ้นส่วนที่เคลื่อนไหวสักชิ้น แล้วทำไมมันถึงผุ (rot)?
On 1 August 2012, the trading firm Knight Capital pushed new code to the eight servers that routed its orders to the New York Stock Exchange. It arrived on seven. The eighth still carried a routine called Power Peg, which the firm had stopped using in 2003 and never deleted, and the new code had reused an old feature flag that — on that one machine — switched the dead routine back on. Over roughly forty-five minutes Knight sent millions of unintended orders into the market and lost $460 million, more than the company was worth. The Securities and Exchange Commission's order records one further detail: the dormant code had last been disturbed in 2005, when a function it depended on was moved elsewhere and nobody retested the combination (SEC Release 34-70694, 2013). Knight paid a $12 million penalty and did not survive the year as an independent firm.
วันที่ 1 สิงหาคม 2012 Knight Capital บริษัทเทรดหุ้น ปล่อยโค้ดใหม่ลงเซิร์ฟเวอร์แปดเครื่องที่ส่งคำสั่งซื้อขายไปตลาดหุ้นนิวยอร์ก โค้ดไปถึงเจ็ดเครื่อง เครื่องที่แปดยังมีรูทีนชื่อ Power Peg ค้างอยู่ บริษัทเลิกใช้มันตั้งแต่ปี 2003 และไม่เคยลบทิ้ง โค้ดใหม่หยิบ feature flag ตัวเก่ามาใช้ซ้ำ และบนเครื่องนั้นเครื่องเดียว มันปลุกรูทีนที่ตายไปแล้วให้ทำงานอีกครั้ง ในเวลาราว 45 นาที Knight ยิงคำสั่งซื้อขายที่ไม่ได้ตั้งใจนับล้านรายการเข้าตลาด ขาดทุน 460 ล้านดอลลาร์ มากกว่ามูลค่าทั้งบริษัท คำสั่งของ Securities and Exchange Commission บันทึกรายละเอียดไว้อีกจุดหนึ่ง โค้ดที่หลับใหลตัวนี้ถูกแตะครั้งสุดท้ายในปี 2005 ตอนที่ฟังก์ชันที่มันพึ่งพาถูกย้ายไปอยู่ที่อื่น และไม่มีใครเทสต์ซ้ำว่าสองส่วนนั้นยังเข้ากันได้ (SEC Release 34-70694, 2013) Knight จ่ายค่าปรับ 12 ล้านดอลลาร์ และอยู่ไม่ถึงสิ้นปีในฐานะบริษัทอิสระ
Not one line of Power Peg had changed in nine years. That is the whole difficulty of this floor. Software has no bearings to wear, no metal to fatigue, no parts to fall out of tolerance; a program left alone computes tomorrow exactly what it computed today. What moves is everything around it — the hardware beneath, the libraries beside it, the regulations above it, the people who understood it. Meir Lehman gave this its name in the 1970s as the first of his laws of software evolution: a program embedded in the real world must be continually adapted or it becomes progressively less satisfactory. His second law is the sting in the tail — as such a program evolves, its complexity increases unless deliberate work is done to hold it down (Lehman, Proc. IEEE 68(9), 1980). Rot is not decay of the artifact. It is drift of the ground.
ไม่มีบรรทัดไหนของ Power Peg เปลี่ยนไปเลยตลอดเก้าปี ความยากทั้งหมดของชั้นนี้อยู่ตรงนั้น ซอฟต์แวร์ไม่มีตลับลูกปืนให้สึก ไม่มีโลหะให้ล้า ไม่มีชิ้นส่วนหลุดพิกัดความคลาดเคลื่อน โปรแกรมที่ทิ้งไว้เฉยๆ จะคำนวณพรุ่งนี้เหมือนที่คำนวณวันนี้เป๊ะ สิ่งที่ขยับคือทุกอย่างรอบตัวมัน — ฮาร์ดแวร์ข้างล่าง ไลบรารีข้างๆ กฎระเบียบข้างบน และคนที่เคยเข้าใจมัน Meir Lehman ตั้งชื่อเรื่องนี้ไว้ในทศวรรษ 1970 เป็นกฎข้อแรกในกฎวิวัฒนาการซอฟต์แวร์ของเขา โปรแกรมที่ฝังอยู่ในโลกจริงต้องถูกปรับตัวต่อเนื่อง ไม่อย่างนั้นมันจะใช้การได้แย่ลงทีละน้อย กฎข้อสองคือหนามที่ซ่อนอยู่ท้ายเรื่อง เมื่อโปรแกรมแบบนี้วิวัฒนาการไป ความซับซ้อนของมันเพิ่มขึ้นเสมอ เว้นแต่จะมีคนตั้งใจลงแรงกดมันเอาไว้ (Lehman, Proc. IEEE 68(9), 1980) ผุ ไม่ใช่การเสื่อมของตัววัตถุ แต่คือพื้นใต้เท้ามันเคลื่อน
Which is why this discipline is not the study of writing programs. Google's engineers put the distinction in one line: "software engineering is programming integrated over time" (Winters, Manshreck & Wright, 2020). Programming produces something that works. Engineering produces something that can be made to work again, by someone else, after the ground has moved. A script you run once and throw away needs none of this floor. A payroll system running in 2040 needs all of it.
ศาสตร์นี้จึงไม่ใช่การศึกษาเรื่องการเขียนโปรแกรม วิศวกรของ Google สรุปความต่างไว้ในประโยคเดียว "วิศวกรรมซอฟต์แวร์คือการเขียนโปรแกรมที่ถูกอินทิเกรตไปตามเวลา" (software engineering is programming integrated over time) (Winters, Manshreck & Wright, 2020) การเขียนโปรแกรมผลิตสิ่งที่ทำงานได้ วิศวกรรมผลิตสิ่งที่ทำให้กลับมาทำงานได้อีก โดยคนอื่น หลังพื้นใต้เท้ามันเคลื่อนไปแล้ว สคริปต์ที่รันครั้งเดียวแล้วทิ้งไม่ต้องการอะไรจากชั้นนี้เลย ระบบจ่ายเงินเดือนที่ยังรันอยู่ในปี 2040 ต้องการทุกอย่าง
The first thing that floor must confront is that not all of the difficulty can be removed. Fred Brooks, who had managed IBM's OS/360 — the largest programming project of its era, and a famous struggle — split the work in two: the essential tasks, "the fashioning of the complex conceptual structures that compose the abstract software entity," and the accidental tasks, the labor of representing those structures in a language and getting them onto a machine (No Silver Bullet, 1986). Better tools attack the accidental half, and they have done so brilliantly — nobody now fights the compiler for a week. But the essential half is the specification of what the thing must actually do, tangled with everything else it must do, and no notation makes a tangled requirement simple. Brooks's prediction was that no single advance would deliver an order-of-magnitude improvement within a decade, because the part that remained was the part that was never about tooling.
สิ่งแรกที่ชั้นนี้ต้องยอมรับคือความยากบางส่วนกำจัดไม่ได้ Fred Brooks ผู้เคยคุมโครงการ OS/360 ของ IBM — โครงการเขียนโปรแกรมที่ใหญ่ที่สุดในยุคนั้น และเป็นการดิ้นรนที่โด่งดัง — แบ่งงานออกเป็นสองส่วน ส่วนแรกคืองาน เนื้อแท้ (essential) หรือ "การปั้นแต่งโครงสร้างเชิงมโนทัศน์ที่ซับซ้อนซึ่งประกอบกันขึ้นเป็นตัวตนซอฟต์แวร์เชิงนามธรรม" (the fashioning of the complex conceptual structures that compose the abstract software entity) ส่วนที่สองคืองาน บังเอิญ (accidental) คือแรงงานที่แทนโครงสร้างเหล่านั้นด้วยภาษาหนึ่งแล้วเอาขึ้นเครื่องจริงให้ได้ (No Silver Bullet, 1986) เครื่องมือที่ดีขึ้นโจมตีความซับซ้อนโดยบังเอิญ (accidental complexity) และโจมตีได้ยอดเยี่ยม ทุกวันนี้ไม่มีใครสู้กับคอมไพเลอร์เป็นอาทิตย์อีกแล้ว แต่ความซับซ้อนโดยเนื้อแท้ (essential complexity) คือสเปกของสิ่งที่งานนั้นต้องทำจริงๆ พันกันยุ่งอยู่กับทุกอย่างอื่นที่มันต้องทำด้วย และไม่มีสัญกรณ์ไหนคลายข้อกำหนด (requirement) ที่พันกันให้กลายเป็นเรื่องง่ายได้ Brooks จึงทำนายว่าจะไม่มีความก้าวหน้าจุดเดียวที่ทำให้ดีขึ้นสิบเท่าภายในสิบปี เพราะส่วนที่เหลือไม่เคยเป็นเรื่องของเครื่องมือตั้งแต่ต้น
If complexity cannot be removed, it can be confined, and this is the field's one great structural idea. David Parnas asked what makes a decomposition into modules good, and rejected the obvious answer — that modules should mirror the steps of the process. His criterion instead: "Every module … is characterized by its knowledge of a design decision which it hides from all others. Its interface … was chosen to reveal as little as possible about its inner workings" (Parnas, CACM 15(12), 1972). A module is a bet about what will change. Hide the decision that will change, and change stays local; expose it, and change propagates. Knight Capital's flag was exactly this failure made visible — a name shared between new code and code no one remembered, a coupling that existed in the machine but in nobody's head.
ความซับซ้อนกำจัดไม่ได้ แต่ กักไว้ ได้ และนี่คือไอเดียเชิงโครงสร้างที่ยิ่งใหญ่หนึ่งเดียวของศาสตร์นี้ David Parnas ถามว่าอะไรทำให้การแตกระบบเป็นมอดูล (module) ดี แล้วปฏิเสธคำตอบที่ดูชัดที่สุด คือมอดูลควรสะท้อนขั้นตอนของกระบวนการ เกณฑ์ของเขาเป็นอีกอย่าง มอดูลแต่ละตัวถูกกำหนดโดยการรู้การตัดสินใจเชิงออกแบบหนึ่งอย่างที่มันซ่อนไว้จากมอดูลอื่นทั้งหมด อินเทอร์เฟซของมันถูกเลือกให้เปิดเผยการทำงานภายในน้อยที่สุดเท่าที่จะทำได้ (Parnas, CACM 15(12), 1972) มอดูลคือการเดิมพันว่าอะไรจะเปลี่ยน ซ่อนการตัดสินใจที่จะเปลี่ยน การเปลี่ยนแปลงก็อยู่เฉพาะที่ เปิดมันออกมา การเปลี่ยนแปลงก็ลามไปทั่ว feature flag ของ Knight Capital คือความล้มเหลวแบบนี้ที่ปรากฏให้เห็นเป๊ะๆ ชื่อเดียวที่โค้ดใหม่ใช้ร่วมกับโค้ดที่ไม่มีใครจำได้ การเกาะเกี่ยว (coupling) ที่มีอยู่จริงในเครื่อง แต่ไม่มีอยู่ในหัวใคร
The instrument that makes change survivable is the test, and its power is narrower than it looks. Dijkstra's corollary is exact: "Program testing can be used to show the presence of bugs, but never to show their absence!" (EWD249). A test suite proves nothing about the system as a whole. What it does is convert a hope — this probably still works — into a specific, mechanically re-checkable claim, and a large system is changeable in proportion to how many such claims it carries. Version control does the same job for history rather than behavior: since Git in April 2005 (Torvalds), a project's past is a queryable artifact, and the question "why is this line here" has an answer that outlives the person who wrote it.
เครื่องมือที่ทำให้การเปลี่ยนแปลงรอดได้คือเทสต์ (test) และพลังของมันแคบกว่าที่ตาเห็นมาก ข้อสรุปของ Dijkstra ตรงเป๊ะ "การเทสต์โปรแกรมใช้แสดงการมีอยู่ของบั๊กได้ แต่ไม่มีทางใช้แสดงว่าบั๊กไม่มีอยู่ได้เลย!" (Program testing can be used to show the presence of bugs, but never to show their absence!) (EWD249) ชุดเทสต์ (test suite) ไม่ได้พิสูจน์อะไรเกี่ยวกับระบบทั้งระบบเลย สิ่งที่มันทำคือแปลงความหวัง — น่าจะยังทำงานได้อยู่ — ให้เป็นข้อกล่าวอ้างที่เจาะจงและตรวจซ้ำได้ด้วยกลไก ระบบใหญ่จะแก้ได้มากเท่าที่มันแบกข้อกล่าวอ้างแบบนั้นไว้ ระบบควบคุมเวอร์ชัน (version control) ทำงานเดียวกันนี้กับประวัติศาสตร์แทนพฤติกรรม นับจาก Git ในเดือนเมษายน 2005 (Torvalds) อดีตของโปรเจกต์กลายเป็นวัตถุที่คิวรีได้ และคำถามว่า "ทำไมบรรทัดนี้ถึงอยู่ตรงนี้" มีคำตอบที่อยู่ยืนกว่าคนเขียนมัน
The last principle is the one practitioners discover last. Melvin Conway, writing in Datamation in April 1968: "Any organization that designs a system … will produce a design whose structure is a copy of the organization's communication structure" (Conway's law). Two teams that rarely speak will build two components with a thin, brittle, under-specified interface between them, because that interface is a faithful cast of their conversation. Architecture is therefore partly a staffing decision, and reorganizations are silent design changes.
หลักการข้อสุดท้ายคือข้อที่คนทำงานจริงค้นพบช้าที่สุด Melvin Conway เขียนไว้ใน Datamation เดือนเมษายน 1968 ว่า "องค์กรใดก็ตามที่ออกแบบระบบหนึ่ง … จะผลิตงานออกแบบที่มีโครงสร้างเป็นสำเนาของโครงสร้างการสื่อสารในองค์กรนั้น" (Any organization that designs a system … will produce a design whose structure is a copy of the organization's communication structure) (Conway's law) สองทีมที่แทบไม่คุยกันจะสร้างสองส่วนประกอบที่มีอินเทอร์เฟซบางเบา เปราะ และสเปกไม่ครบคั่นกลาง เพราะอินเทอร์เฟซนั้นคือแบบหล่อที่ซื่อตรงต่อบทสนทนาของพวกเขาเอง สถาปัตยกรรมจึงเป็นการตัดสินใจเรื่องอัตรากำลังคนอยู่ส่วนหนึ่ง และการปรับโครงสร้างองค์กรคือการเปลี่ยนงานออกแบบแบบเงียบๆ
The field named itself in that same year, at a NATO conference at Garmisch in October 1968, where "software engineering" was chosen deliberately to provoke — an assertion that this work ought to rest on theory and discipline the way established engineering does, made at a moment when it visibly did not (Naur & Randell, eds., 1969). Nearly sixty years on, the aspiration is still doing more work than the achievement, and the honest members of the field say so.
ศาสตร์นี้ตั้งชื่อให้ตัวเองในปีเดียวกันนั้น ที่การประชุม NATO ณ Garmisch เดือนตุลาคม 1968 คำว่า "software engineering" ถูกเลือกอย่างตั้งใจให้ยั่วยุ เป็นการยืนยันว่างานนี้ ควร ตั้งอยู่บนทฤษฎีและวินัยแบบเดียวกับวิศวกรรมที่ตั้งตัวมานาน พูดในวันที่เห็นกันชัดๆ ว่ามันยังไม่เป็นอย่างนั้น (Naur & Randell, eds., 1969) เกือบหกสิบปีผ่านไป ความมุ่งหวังยังทำงานหนักกว่าความสำเร็จ และคนในวงการที่ซื่อตรงก็พูดแบบนั้น
Connections
เชื่อมโยง
Below this floor sit chapters 05 and 06: the operating system and the language give you a program that runs correctly once, and everything here begins after that. Chapter 02 supplies correctness for a single algorithm; this chapter is what happens when ten thousand of them must be changed by people who never met. Above and beside it, chapters 08, 09 and 10 are the domains where these disciplines are tested hardest, because a database, a network stack, or a distributed system cannot be stopped and rewritten. Chapter 11 is the case where a leak is not merely expensive but adversarial.
ใต้ชั้นนี้คือบทที่ 05 และ 06 ระบบปฏิบัติการกับภาษาโปรแกรมให้โปรแกรมที่รันถูกต้องได้หนึ่งครั้ง และทุกอย่างในบทนี้เริ่มหลังจากนั้น บทที่ 02 ให้ความถูกต้องกับอัลกอริทึมเดี่ยวหนึ่งตัว บทนี้คือสิ่งที่เกิดขึ้นเมื่ออัลกอริทึมหมื่นตัวต้องถูกแก้โดยคนที่ไม่เคยเจอหน้ากัน เหนือขึ้นไปและข้างๆ บทที่ 08, 09 และ 10 คือโดเมนที่วินัยเหล่านี้ถูกทดสอบหนักที่สุด เพราะฐานข้อมูล เครือข่าย หรือระบบกระจาย หยุดแล้วเขียนใหม่ไม่ได้ บทที่ 11 คือกรณีที่การรั่วไม่ได้แพงอย่างเดียว แต่เป็นปฏิปักษ์ด้วย
Open questions
คำถามที่ยังเปิดอยู่
The field's own evidence base is thin. Everyone quotes a figure for how much of software's cost is maintenance rather than initial construction, and the figures range from sixty to over ninety percent with no shared definition or measurement window behind them — a discipline that measures its central claim that loosely should be uneasy. Deeper: does machine-generated code shift Brooks's ratio, or does it merely make the accidental half cheaper while leaving the essential tangle untouched — and if reading and reviewing code becomes the bottleneck, is that a new floor or the same one? And if Conway's law holds, is it usable in reverse: can you get the architecture you want by first building the organization that would produce it?
ฐานหลักฐานของศาสตร์นี้เองยังบางมาก ทุกคนอ้างตัวเลขว่าต้นทุนซอฟต์แวร์กี่เปอร์เซ็นต์เป็นการบำรุงรักษา (maintenance) แทนที่จะเป็นการสร้างครั้งแรก ตัวเลขแกว่งตั้งแต่หกสิบไปจนเกินเก้าสิบเปอร์เซ็นต์ โดยไม่มีนิยามร่วมหรือหน้าต่างการวัดรองรับอยู่ข้างหลัง ศาสตร์ที่วัดข้อกล่าวอ้างหลักของตัวเองหลวมขนาดนี้ควรรู้สึกไม่สบายใจ ลึกลงไปอีก โค้ดที่เครื่องผลิตขึ้นเองขยับสัดส่วนของ Brooks จริงไหม หรือมันแค่ทำให้ครึ่งบังเอิญถูกลง โดยไม่แตะครึ่งเนื้อแท้ที่ยังพันกันยุ่งอยู่ — และถ้าการอ่านกับรีวิวโค้ดกลายเป็นคอขวด นั่นคือชั้นใหม่หรือชั้นเดิม? และถ้ากฎของคอนเวย์ (Conway's law) เป็นจริง มันใช้ย้อนกลับได้ไหม — สร้างองค์กรที่จะผลิตสถาปัตยกรรมแบบนั้นขึ้นมาก่อน แล้วจะได้สถาปัตยกรรมที่ต้องการหรือเปล่า?
Go deeper
อ่านต่อ
- Titus Winters, Tom Manshreck & Hyrum Wright, Software Engineering at Google, O'Reilly, 2020 — the clearest modern statement of the time-integrated view; free in full at abseil.io.
- D. L. Parnas, "On the Criteria To Be Used in Decomposing Systems into Modules," Communications of the ACM 15, no. 12 (1972): 1053–1058 — full text.
- Frederick P. Brooks, Jr., "No Silver Bullet — Essence and Accident in Software Engineering," IFIP Congress, 1986 — UNC technical report.
- Titus Winters, Tom Manshreck & Hyrum Wright, Software Engineering at Google, O'Reilly, 2020 — คำอธิบายยุคใหม่ที่ชัดเจนที่สุดของมุมมองแบบอินทิเกรตไปตามเวลา อ่านฟรีฉบับเต็มได้ที่ abseil.io
- D. L. Parnas, "On the Criteria To Be Used in Decomposing Systems into Modules," Communications of the ACM 15, no. 12 (1972): 1053–1058 — ฉบับเต็ม
- Frederick P. Brooks, Jr., "No Silver Bullet — Essence and Accident in Software Engineering," IFIP Congress, 1986 — รายงานทางเทคนิคของ UNC