軟件的本質是什么?
隨著互聯網和信息技術的高速發展,各行各業的軟件層出不窮,通過PC端或者手機端辦任何事情都離不開軟件。那么軟件的本質究竟是什么呢?下面是我對軟件本質的分析。
軟件是一種固化的思維。其根本組成是概念和邏輯。軟件世界中的一切的故事始于一個機器模型,而這個基本的機器模型并不復雜,甚至可以用三個關鍵概念來概括:指令、數據以及棧。其邏輯也比較簡單,即按照指定的順序,逐步執行各條指令。但也就是這樣一個簡單的模型,支撐起了整個軟件的世界。軟件構建的過程就是從客觀世界中的概念和邏輯向機器模型逐步進行映射的過程。由于編譯器(或解釋器)的存在,最后一重映射已經被無限簡化,因此我們可以認為以編程語言為載體的代碼即是固化后的思維,包含了所有固化后的概念和邏輯。
為完成這一任務,首先軟件的邊界必須清楚,即“要轉換的究竟是什么”必須盡可能明確,此即需求開發的根本任務。從需求向最終代碼的映射可以稱為軟件構造。需求開發的結果:規格說明和軟件構造的結果:代碼表述的實質上表述的是相同的東西,所不同的只是視角,表達方法和詳盡程度。需求開發姑且不論,軟件構造即在確定的范圍內打造概念的邊界和定義概念間的邏輯關系的過程。
打造概念邊界時原則可以有許多,但手段只有一個,即抽象。從本質上講,抽象是一種認清事物本質,并進行歸類的過程。與抽象相對的是具體,但抽象的來源也是具體。假使我們需要對【人】這一名詞進行定義,那么必然是要從張三,李四等等具體的人身上抽取共通特征,而后才能完成定義。最終結果是【人】這一概念來源于張三,李四,但又不是張三李四。這樣一個從具體的事物中抽取共性,再進行命名的過程就是抽象。
我們常說的功能分解(Function Decomposition),抽象數據類型(ADT),面向對象(OO)都可以看做是對事物進行抽象的具體方法。但不管使用什么樣的方法,打造概念邊界通常并不容易。這種困難起源于概念本身的邊界并不清楚,存在模糊性。比如:當我們描述一本書的時候,那么這本書是否被借出了這種信息,是既可以作為書的基本信息的一部分,也可以通過查閱借閱人的信息來存儲的。對此,哲學上的表述是:世上萬物是運動的,聯系的,而非靜止的,孤立的。
更困難的是一旦切換視角,相同的概念又可以有多種劃分方法。好比說,我們可以很容易界定什么是人,什么是猿,但當我們試圖把人猿歸類的時候就依據我們的視角進行抉擇。因為它似乎是人,似乎是猿,卻又更是人猿。打造概念邊界時正是類似人猿這類概念讓我們犯難。有些問題甚至只有選擇而沒有答案。莊子對這種事情的觀點是:自其異者視之,肝膽楚越也;自其同者視之,萬物皆一也 。
也正因此編程是一種實踐多于是一種理論。
我們可以抽象出一些指導性原則,比如開閉原則,比如里氏代換,比如高內聚低耦合,但一旦面對現實時卻只能具體問題具體分析。也許有人認為這里所說的澄清概念邊界專屬于面向對象,其實不是。當你決定某一組函數專門負責文件操作時,你同樣是定義了【文件操作】這樣一個概念的邊界。包,類,模塊,數據結構,方法等等這些名詞都可以對應到一個個具體的概念,是抽象這一工作的結果。
我們把概念之間的關系定義為邏輯。而概念間的邏輯關系可以被分為兩類:一類是概念所固有的,基本不受具體應用影響的靜態關系。比如:人是比老師或學生更為泛化的概念,老師或學生都需要有一個名字。這就是我們常說的繼承,包含聚合(整體與局部)等。需要特別一提的是框架(或設計模式)更多的體現的是一種靜態關聯關系。框架把全局性,共通的部分抽象出來,固定在框架之中,把局部的,需要定制的東西開放給用戶,來應對變化。與這種靜態的邏輯關系相比,具體化的概念之間的動態關系顯的更為繁雜。如果說概念間的靜態關系體現的是一種預先存在的必然關聯的話,那么概念間的動態關系體現的則是實現具體功能時體現出來的偶然關聯關系。假設說我們要做一個簡單的監控系統。那么大致會衍生出下面幾個方面的概念(模塊):
1 照相機:負責拍照
2 圖像處理:負責分析照片中是否有異常
3 數據庫:用于存儲過往的記錄
4 報告功能:一旦發現異常,對相關人等進行通知
5 控制器:根據既定的處理流程,使程序動起來。
6 ... ... 這個時候,控制器和照相機(或數據庫間)的關聯則是一種偶然關聯,是動態關聯關系。把照相機替換為攝像頭也無不可。
對照實現來說的話,照相機的實例可以通過控制器的接口傳入,也可以在控制器的方法中創建,但如果把照相機作為控制器成員,則和這些概念間既有的關聯關系向背離,耦合度會有不必要的增加。
在動態關系中第一重要的是動作的時序,即先后順序。
時空的特征決定了這世界上大多的事情皆有因果,也決定了程序中凡事必有先后。當我們明確了先做什么,再做什么,最后做什么之后,我們才能對事情真正有所把握。不管采用什么設計方法,都要讓這類路線盡可能明晰。惟其如此,程序才更容易懂,因為這是正常人最基本的認知世界的方式。
對時序影響很大的一個因素是并行,并行的一個常見實現方法是啟用多線程。多線程程序之所以難寫,不在于線程本身的機制或同步多么難以掌握,而在于并發使整個程序中的邏輯變的更加復雜。
最后做一點總結:軟件是固化的思維,其基本組成是概念和邏輯。