人們對軟體開發者的稱呼眾多。開發者(Developer)是最常見的,而程式設計師(Programmer)聽起來較中性且傳統。寫碼者(Coder)字面意思是寫程式碼的人,但也可帶有貶義,暗示著只被動寫程式碼,而不參與軟體開發的其他活動。光譜的另一端是軟體工程師(Software Engineer)。「軟體工程師」這個頭銜給人的感覺截然不同。不知為何,軟體工程師似乎比寫碼者更專業。不知為何,他們似乎比程式設計師更擅長數學。而且,不知為何,他們的工作似乎比開發者更重要。事實上,在加拿大某些省份,「軟體工程師」、「電腦工程師」以及其他包含「工程師」的頭銜,(原則上)保留給持有省級工程師監管機構核發執照的工程師。許多人認為,擁有工程師頭銜的人就持有公認的專業資格或執照。這一切都關乎「工程師」這個頭銜給我們的 وهو impression。但如果許多人都持有這種 وهو impression,就值得探究原因。如果軟體開發本身就是一種工程,那麼「軟體工程師」這個頭銜本身就沒什麼特別的了。這種 وهو impression 從何而來?為何軟體工程感覺與機械、電機或土木工程不同?又是什麼讓軟體開發成為工程?

軟體與工程

NATO 軟體工程會議(Robert McClure, Brian Randell)

工程學沒有單一定義,但通常可以描述為一個領域,它系統性地運用數學和科學知識,在各種約束條件下解決問題,以滿足人類需求。聯合國教科文組織 [1] 和美國國家科學院 [2] 對工程學提供了以下定義:工程學是實踐、專業和藝術領域,與技術科學和數學知識的發展、獲取和應用有關。它涉及理解、設計、開發、發明、創新以及為特定目的使用材料、機器、結構、系統和流程。工程學既是關於人造產品和流程的創造與設計的知識,也是一種稱為「約束設計」的解決問題方法。

試圖賦予軟體開發與其他工程學科相同的系統性基礎,可以追溯到計算機的早期。1968 年的 NATO 軟體工程會議 [3] 通常被認為是軟體工程的起點。在德國舉行的這次會議上,一個反覆出現的擔憂是,隨著軟體規模和重要性的迅速增加,其複雜性也在不斷提高。這被稱為軟體危機。與會者沒有達成共識,但他們似乎普遍認為,作為一個年輕的領域,軟體開發需要與成熟的工程學科相媲美的方法和結構來解決其眼前的問題。會議報告的編輯們在談到「軟體工程」這個詞時寫道:

「軟體工程」這個詞被刻意選為具有挑釁意味,暗示軟體製造需要基於傳統成熟工程學科的理論基礎和實踐學科。

與此同時,Thomas Haigh 認為,在會議之前 IFIP 工作組 2.1 內部的一場辯論具有更大的意義,該工作組正在開發 ALGOL 60 的後繼者 [4]。該小組的主流觀點是,應該能夠通過組合少數基本概念來表達複雜的程式。這種哲學強烈影響了 ALGOL 68 的草案。小組中那些更關心使複雜程式可靠,而不是如何表達它們的人,反對 ALGOL 68 的方向。ALGOL 68 的反對者是 NATO 軟體工程會議的核心人物。他們認為軟體開發需要成為一個更嚴謹、更可控的活動。其中一位,Edsger Dijkstra,將程式設計視為一種應用數學的形式,後來在主張結構化程式設計時再次提及軟體危機。

我們應該記住,這些關於軟體工程的辯論與應用程式設計師的工作相去甚遠。當時大多數會議參與者是研究人員,而當時大多數應用程式是使用 COBOL 編寫的用於商業數據處理的金融、會計和人事軟體。因此,1968 年討論的軟體工程概念無法解釋當時整個軟體行業。

然而,今天的程式設計師受到 ALGOL 68 辯論和 NATO 軟體工程會議的間接甚至直接影響。如果你曾經被告知在 C 語言程式設計中避免使用 goto,遇到物件導向或函數式程式設計等主題,甚至只是使用了現代程式設計工具,這都是真的。

將工程應用於軟體

經過數十年的努力,將軟體開發確立為一門工程學科,軟體工程知識體系(SWEBOK)[5] 使用了以下對「工程」和「軟體工程」的定義。電機電子工程師學會(IEEE)將工程定義為「將系統性、紀律性、可量化的方法應用於結構、機器、產品、系統或流程」……軟體工程被定義為「將系統性、紀律性、可量化的方法應用於軟體的開發、操作和維護;也就是說,將工程應用於軟體」。

根據這個定義,使軟體開發成為工程的,是將工程方法應用於軟體開發。工程方法是一個過程,在這個過程中,工程師根據某些標準,從幾個可行的解決方案中選擇一個,實施它,並監控結果。這個過程不必是線性的,但必須是迭代的。事實上,工程方法本質上是迭代的。在任何階段獲得的知識都可能影響到早期階段,自然會引發另一次迭代。工程決策基於估計,因此決策的品質取決於估計的品質。工程師因此必須將估計與實際結果進行比較,以創建一個用於估計的迴圈。理解導致估計與實際結果之間差距的原因,可以讓他們改進估計技術,並在未來做出更準確的估計。這反過來又使他們能夠不斷做出更好的決策。

用工程術語解釋直覺

這聽起來可能有點像象牙塔裡的思考,所以一個具體的例子可能會有所幫助。有一天,營運團隊告訴一位正在開發電子商務平台的程式設計師,產品詳細頁面載入太慢,並要求他們縮短載入時間。一位熟悉該系統的程式設計師聽到頁面載入緩慢時,可能會憑直覺想到一個解決方案。這不一定會導致糟糕的決策。但很難解釋為什麼這個決策比其他替代方案更有根據,需要提高多少效能才算成功,或者它對用戶實際會產生多大的影響。

工程方法始於準確理解實際問題。「太慢」可能意味著很多事情,所以第一步是測量需要改進的產品詳細頁面的效能。最近的指標顯示,這些頁面的 FCP p75 為 2,700 毫秒。建議的 FCP p75 以獲得良好用戶體驗是 1,800 毫秒或更少 [6],這是一個合理的目標。

程式設計師分析追蹤數據,發現 SSR 伺服器花費了相當多的渲染時間在等待產品詳細 API 的回應。產品詳細 API 的 p95 延遲為 1,000 毫秒,緩慢的請求花費 800 毫秒等待資料庫讀取查詢。現在問題可以重新定義為「資料庫查詢是讀取密集型產品查找的延遲瓶頸」,而不是「頁面載入緩慢」。

這個問題有幾種解決方案。程式設計師可以引入記憶體快取層、改進查詢或索引、查詢讀取副本,或將整個頁面靜態渲染並通過 CDN 提供。每種解決方案都有其優缺點和權衡。重要的是不要急於得出第一個想到的解決方案就是正確的。

流量分析顯示,最受歡迎的 5% 產品佔了查找請求的約 90%,快取 TTL 模擬表明引入 Redis 可以實現超過 95% 的快取命中率。Redis 的讀取速度已知為幾毫秒,因此快取命中應該能將延遲降低到約 200 毫秒。在比較了各種方案後,程式設計師決定建立一個帶有 Redis 的記憶體快取層將是最有效的解決方案。

引入 Redis 後,指標顯示快取命中率為 65%,API p95 延遲為 850 毫秒,FCP p75 為 2,000 毫秒。這些數據顯示了適度的改進。調查實際結果為何與估計不同,發現產品資訊依賴於個人化數據,導致快取金鑰的基數比預期更高。程式設計師重新設計了快取策略,將靜態產品資訊儲存在全域快取中,並單獨獲取個人化數據。這將快取命中率提高到 97%,API p95 延遲降低到 200 毫秒,FCP p75 降低到 1,400 毫秒。

整個過程都遵循工程方法,從測量問題、比較可能的解決方案,到估計結果,再到通過比較實際結果與估計來進行改進。

何時需要工程方法

從這個角度來看,軟體開發顯然具有工程方面的特徵。它仍然感覺與其他工程學科不同的原因可能是,有可能在不符合工程學定義的情況下,製作出工作得相當不錯的軟體。程式設計師可以不採用系統性方法進行設計,不帶紀律地編寫程式碼,並通過一個無法量化的過程來生產軟體。由於無論開發過程如何都可以產生可工作的軟體,因此在實踐中很容易忽略工程方法。

軟體開發在短時間內發生了巨大變化。即使是我們通常所說的計算機科學基礎知識,其變化的速度也遠遠快於其他工程學科所依賴的自然法則。因此,許多軟體開發組織因此專注於速度,而不是遵循健全的原則。結果是,儘管軟體很重要且其故障可能很嚴重,但軟體品質卻很容易被視為次要問題。軟體供應商可能認為「軟」體容易修復,因此可以證明品質低劣是合理的。然而,對於消費者來說,使用不可靠的軟體是非常令人不快的,有時甚至可能很危險。

還有其他看待軟體開發的方式 [7]。Peter Naur 認為,程式設計的真正目標是建立程式設計師心中的理論,而不是生產我們稱之為程式的產物 [8]。Naur 借用 Gilbert Ryle 的觀點,用「理論」來描述程式設計師心中形成的知識和理解。程式表達了存在於程式設計師內心的心理建構,因此當該理論被寫成文字時,資訊不可避免地會丟失。失去程式設計師就等於失去程式。

Sherry Turkle 和 Seymour Papert 將那些先製作出可工作的軟體,然後不斷修改和觀察它的程式設計師稱為「Bricoleurs」[9],並研究了他們的程式設計方式 [10]。他們認為,程式設計師可以通過與可工作的軟體互動來生產高品質的軟體,而不是預先規劃其整個結構並將其分解為實現。

軟體園藝(Software gardening)則將軟體視為生物體,並接受其不可預測性。從這個角度來看,程式設計師是專業人士,他們精心照料不斷變化的軟體園圃,憑藉直覺和主人翁意識來指導。

儘管對軟體開發有這些不同的觀點,軟體開發組織仍然需要工程方法。它不能保證完美的軟體,但至少可以提高品質的底線。那些在心中建立了理論的經驗豐富的程式設計師無法永遠留在一個組織中。也不是每個程式設計師都能成為具有卓越直覺的 Bricoleur 或對產品有強烈主人翁意識的園丁。一個組織必須儘管個別程式設計師的能力參差不齊,但仍能生產出品質一致的軟體。

工程方法的優勢在於,即使是天賦較差的人,通過遵循一個設計良好的系統化流程,也能提高他們做出良好決策的機會。我們不需要將每個問題都視為工程問題。但是,當一個問題有多種可能的解決方案而不是一個正確答案時,應用工程方法來比較權衡、選擇解決方案和實施它,讓我們有理由預期更好的結果。當一個軟體開發組織必須在不依賴個人天才的情況下,重複產生可靠的結果時,工程方法就變得必要了。

什麼使軟體開發成為工程,與問題的難易程度或工程師的資歷無關。將工程方法應用於軟體開發,才是使其成為工程的關鍵。為了解決問題,工程師會估計、實驗、測量、重現結果、改進並重複。而我們將以這種方式解決問題的軟體構建者稱為軟體工程師。

軟體工程的終結

在首次嘗試將工程方法應用於軟體開發約六十年後,軟體工程正被其滅亡的預言所困擾。論點是,由於人工智能,傳統的軟體工程方法已無法為程式設計師提供實質幫助。如果這裡的人工智能指的是大型語言模型(LLMs),那麼軟體工程可能不會那麼輕易地結束。這些預言真正預示的是人類軟體工程師的終結。

目前,當人類程式設計師在將工程方法應用於軟體開發方面發揮主導作用時,仍然存在有意義的好處。第一個原因是,人類必須向 AI 提供關於環境的上下文,包括技術限制以及具體要求。給予 AI 抽象的業務需求,它就會產生抽象的結果。在花費了很長時間與 AI 搏鬥以改進一個未能妥善處理邊緣案例的輸出後,你最終會意識到,程式碼是業務需求的最佳規格。

第二個原因是,AI 輸出的品質參差不齊,不夠可靠 [11]。在舊有系統(brownfield systems)中,這種限制尤其明顯,人類軟體工程師必須介入測量和驗證輸出是否符合要求和限制。

由於這些原因,由人類主導的軟體工程仍然提供了一個框架,引導人類和 AI 在實踐中持續生產出更好的軟體。

在過渡時期,任何人都可以提出看似合理的預言。也許有一天,人工智能能夠自行識別現實世界的限制並定義需求,生產出完美解決問題的黑箱軟體。Ben Shneiderman 將實現更高自動化同時賦予人類更多控制權的 AI 系統描述為可靠、安全且值得信賴(RST)的系統 [12]。

如果我們只關注自動化軟體開發,最終軟體是在沒有人類控制的情況下製作的,如果沒有人對該軟體負責,而我們內心深處又渴望這樣的軟體,那麼我們滅亡的預言將成為一個自我實現的預言。至少目前,軟體工程師可以決定自己的未來。