第三章探討了軟體開發中的「藍圖與施工許可」,那些前置作業你未必能完全掌控。本章則聚焦於程式設計師與技術主管能直接決定的建構準備工作——相當於選擇工具箱裡的工具,以及出發前如何裝載你的卡車。
4.1 程式語言的選擇#
程式語言的選擇會從多個層面影響生產力與程式碼品質。
熟悉度與生產力#
研究顯示,使用熟悉的語言工作的程式設計師,生產力比使用陌生語言的高出約 30%(Cocomo II 估算模型)。IBM 早期研究甚至發現,經驗豐富的程式設計師生產力是經驗不足者的三倍以上。
高階語言 vs. 低階語言#
使用高階語言(High-level Language)的程式設計師,其生產力、可靠性與簡潔度比使用低階語言(如組合語言、C)者高出 5 到 15 倍。高階語言的每一行程式碼能表達更多意義。以下是各語言相對於 C 的等效程式碼比率:
| 語言 | 相對 C 的層級 |
|---|---|
| C | 1 |
| C++ | 2.5 |
| Fortran 95 | 2 |
| Java | 2.5 |
| Perl | 6 |
| Python | 6 |
| Smalltalk | 6 |
| Visual Basic | 4.5 |
比率越高,代表該語言每行程式碼能完成的工作越多。
語言塑造思維#
語言學中的 Sapir-Whorf 假說認為,語言會限制(或擴展)一個人的思考能力——程式語言也是如此。如果你不知道某個語言特性的「詞彙」,你甚至可能無法構思出相應的解決方案。
一個常見的現象:團隊改用新語言(例如 C++),但程式設計師因為背景不同(例如來自 Fortran),寫出的程式碼本質上仍是「偽裝的 Fortran」——使用 goto 和全域資料,卻忽略了物件導向的豐富功能。
各主要語言簡介
- Ada:通用高階語言,基於 Pascal,擅長即時與嵌入式系統,強調資料抽象與資訊隱藏。
- Assembly:低階語言,每個指令對應一條機器碼,僅在極端效能需求時使用。
- C:中階通用語言,功能強大但型別檢查較弱,常被稱為「可攜式組合語言」。
- C++:以 C 為基礎的物件導向語言,提供類別、多型、例外處理、模板等。
- C#:Microsoft 開發的通用物件導向語言,語法類似 C/C++/Java。
- Cobol:類英文語法,主要用於商業應用,至今仍是使用最廣泛的語言之一。
- Fortran:第一個高階語言,主要用於科學與工程計算。
- Java:物件導向語言,透過虛擬機(Virtual Machine)實現跨平台,廣泛用於 Web 應用。
- JavaScript:直譯式腳本語言,主要用於客戶端 Web 功能。
- Perl:以字串處理見長,常用於系統管理任務與 Web 應用。
- PHP:開放原始碼腳本語言,可嵌入網頁以存取資料庫。
- Python:直譯式、互動式的物件導向語言,用途廣泛。
- SQL:宣告式語言,為關聯資料庫查詢與管理的事實標準。
- Visual Basic:高階、物件導向的視覺化語言,由 Microsoft 開發。
4.2 程式設計約定#
在高品質的軟體中,架構的**概念完整性(Conceptual Integrity)**會一路延伸到最底層的實作細節。實作必須與架構一致,且內部也要保持一致。
變數命名、類別命名、格式排版、註解風格等建構指引(Construction Guidelines),為程式提供低層次的和諧感。如果缺乏統一的規範,程式碼就會充滿任意的風格差異,白白消耗腦力。
作者用繪畫做類比:如果一幅畫的設計很出色,但一部分是古典風格、一部分是印象派、一部分是立體派,那它看起來就像拼貼畫,毫無概念完整性。程式碼也是如此。
程式設計約定幾乎不可能在軟體完成後才「回頭補上」。必須在建構開始之前就制定好。
4.3 你在技術浪潮中的位置#
技術會經歷週期性的興衰浪潮(Technology Wave)。你所處的位置會深刻影響建構實踐的選擇。
成熟期 vs. 早期#
成熟期(浪潮末端)的環境提供:豐富的語言選項、完善的除錯工具、可靠的編譯器、整合式開發環境、大量的文件與社群資源。
早期(浪潮前端)的環境則相反:語言選擇少且有 bug、文件不足、除錯器可能根本不存在、工具不整合、編譯器頻繁更新且每次都可能破壞現有程式碼。
這並非建議你避開早期技術。許多最具創新性的應用(如 Turbo Pascal、Lotus 123、Mosaic 瀏覽器)都誕生於浪潮早期。重點是:你必須了解自己在浪潮中的位置,並據此調整期望與計畫。
「用語言寫程式」vs.「把想法寫進語言」#
David Gries 指出,程式設計工具不應決定你的思維方式。這裡有一個關鍵區分:
- Programming in a language(用語言寫程式):思維受限於語言直接支援的結構。語言原始,思維也跟著原始。
- Programming into a language(把想法寫進語言):先決定想要表達什麼概念,再找出如何用手邊的語言工具來實現。
作者以早期 Visual Basic 為例:他想將業務邏輯、UI 和資料庫分離,但語言本身不支援這種做法。於是他自訂約定——
.frm檔案只能存取資料庫、每個表單僅暴露一個IsFormCompleted()公開方法、所有業務邏輯必須放在對應的.bas檔案中。這個簡單的約定,幫助他避免了大量混亂的程式碼,保持了專案的可管理性。
如果你使用的語言缺少你想要的結構,或容易產生問題,就自己發明編碼約定、標準、類別庫或其他補強措施來彌補。這是本書最重要的原則之一。
4.4 選擇主要的建構實踐方法#
建構準備的一環是決定要採用哪些實踐方法。例如有些專案使用配對程式設計(Pair Programming)搭配測試先行開發(Test-first Development),另一些則使用個人開發搭配正式審查(Formal Inspection)。兩種組合都能奏效,關鍵在於根據專案特性做出有意識的選擇。
建構實踐檢核清單
編碼(Coding)
- 是否已定義多少設計在事前完成、多少在編碼時進行?
- 是否已定義命名、註解與排版的編碼約定?
- 是否已定義架構所隱含的具體實踐(錯誤處理、安全性、類別介面、重用標準、效能考量等)?
- 是否已確認你在技術浪潮中的位置,並相應調整做法?
團隊合作(Teamwork)
- 是否已定義整合程序(程式設計師將程式碼提交到主分支前必須完成的步驟)?
- 程式設計師是配對開發、獨立開發,還是混合模式?
品質保證(Quality Assurance)
- 程式設計師是否在寫程式碼之前先撰寫測試案例?
- 無論先寫或後寫,程式設計師是否都會撰寫單元測試?
- 程式設計師是否在提交前使用除錯器逐步檢視程式碼?
- 程式設計師是否在提交前進行整合測試?
- 程式設計師是否進行程式碼審查或互相檢視?
工具(Tools)
- 是否已選定版本控制工具?
- 是否已選定語言、語言版本或編譯器版本?
- 是否已選定框架(如 J2EE、.NET),或明確決定不使用框架?
- 是否已決定是否允許使用非標準的語言特性?
- 是否已確認並取得其他所需工具(編輯器、重構工具、除錯器、測試框架、語法檢查器等)?
要點#
- 每種程式語言都有其優勢與弱點,務必了解你所使用語言的特性。
- 在開始寫程式之前就制定好程式設計約定,事後幾乎不可能回頭修改。
- 可用的建構實踐方法遠多於單一專案能採用的數量,應有意識地選擇最適合的組合。
- 自問你的程式設計實踐是「受語言啟發」還是「被語言限制」——記得把想法寫進語言(program into a language),而非僅用語言寫程式(program in a language)。
- 你在技術浪潮中的位置決定了哪些做法是有效(甚至可行)的,應據此調整計畫與期望。