程式設計正規化的演進:增加約束(讀之二)
目前為止只存在三種程式設計正規化(可能也不會有第四種了),結構化程式設計、面向物件程式設計 和 函數語言程式設計。

圖片發自簡書App
結構化程式設計基於嚴格的數學證明,只需要順序、分支和迴圈三種結構就可以製造出任何程式(圖靈完備)。Dijkstra 指出goto語句不必要而且是有害的,進而希望給出程式的形式化證明,即對功能進行降解拆分到最基本的結構,再證明每個結構的正確性就可以證明整個程式的正確性,這裡證明的複雜度實際上是被大大降低的,並不需要遍歷所有可能的組合。實際上沒有人這麼做。結構化程式設計留下的重要思想是不是goto有害,而是對功能進行降解和拆分,將功能拆分到一個個可以被驗證的小函式。思想有兩種偉大,第一種打到了當時不可一世的巨人(貴族或者謬誤),被打倒的巨人再也站不起來進而這個打倒成為一個 歷史事件 ,比如被棄用的goto;另一種是,創造一種思想的工具, 被收入在工具箱,時時派上用場 ,比如功能性降解拆分。可惜這種降解拆分還沒有成為本科程式設計教學的一部分,否則我們就不會需要就某些基本常識反覆給新入行者糾正(比如別寫大函式)。
面向物件,是三種正規化中唯一沒有數學證明作為基礎的正規化,這也就決定了它的模糊性,不容易給一個一般的定義。bob大叔看來, 面向物件思想程式設計方法中最珍貴的不是封裝和繼承,而是多型 。從架構角度看依賴倒置是非常重要的,即應該面向介面(抽象)來做設計。要實現對抽象的依賴,c語言中提供的手段是函式指標。但函式指標的危險性是眾所周知的,而oo提供了多型,可以用介面類來輕鬆的實現依賴倒置,進而實現外掛式的架構,即核心業務邏輯用抽象介面來說明自己的需求,而外圍服務(介面、資料庫等)實現這些介面。這樣業務邏輯就對外圍服務沒有了依賴,並且容易插拔不同的服務外掛(只要它們滿足業務邏輯的抽象介面即可)。這種設計並不一定要oo才可以實現,只是oo提供了一種機制,大大降低了實現的難度。注意, oo並沒有降低設計的難度。
函數語言程式設計,取消了變數。如果不考慮巨大的物理資源開銷,這是更安全更可靠的方法。需要強調的是,這並沒有降低設計的難度,你獲得了一個新的拆分維度,即將可變性模組和不變性模組分離。

圖片發自簡書App
站在架構設計角度,重新看結構化程式設計和麵向物件程式設計:前者強調功能性降解拆分(functional decomposition)的可能性和必要性 ,分治是降低問題複雜度的不二法門,但需要面對以抽象介面為錨點的組合問題。OO提供了一種組合的便利性(多型) 。沒有方便的工具,再理想的設計理念都難以普及。也只有在一種職業有相當的規模後,一般性的工具才會湧現出來。
BOB大叔告訴我們, 三個程式設計正規化實際上並沒有給程式設計(程式設計師)提供新的能力,而是分別提出了約束 ,結構化程式設計約束了程式控制權的直接轉移(禁止goto),面向物件約束了程式控制權的間接轉移(用多型替代函式指標),函數語言程式設計禁止了賦值操作! 50年來,我們只是學會了什麼不應該做。這個洞見非常深刻。三個正規化的提出和普及伴隨著程式設計規模的大規模增長。Dijkstra時代"程式設計師”還不是一個被認可的職業,今天"寫程式"某種程度上也不是一種職業而是一種基本工具。 程式設計師沒來得及專業化,就已經被去專業化了 ,這是人類歷史中比較罕見的一種情況!如是,關於程式設計基本的方法論和紀律都沒有完全形成或者在“專業人士”內部普及。再想一下敏捷軟體開發這件事,精英化(專業化)的考慮團隊能力建設和定義工作方式是有困難的。道和術要分開,牧羊犬和羊群要分開。 一般的團隊需要制定明確的降解拆分的方法和組合手段,然後用技術手段增加約束(比如提供白名單,禁止使用範圍之外的方法),最終約束羊群不會跑到危險之地。