架構師之路

iamdll發表於2019-03-28

1、引言

機算機科學是一門應用科學,它的知識體系是典型的倒三角結構,所用的基礎知識並不多,只是隨著應用領域和方向的不同,產生了很多的分支,所以說程式設計並不是一件很困難的事情,一個高中生經過特定的訓練就可以做得到。但是,會程式設計和編好程絕對是兩碼事,同樣的程式設計師,有的人幾年之後成為了架構師,有的人卻還在不停地coding,只不過ctrl-c、ctrl-v用得更加純熟了。在中國,程式設計人員最終的歸途無外乎兩條:一是轉向技術管理,它的終點是CTO;二是繼續深入,它的終點是首席架構師,成為CEO的人畢竟是少數。如果你現在還是個普通的程式設計師,希望繼續在技術這條路上前進的話,我想你還是應該先補充一點軟體工程的思想,學習一點有關設計模式的知識,只有具備這些能力,你才能從整體和巨集觀層面來考慮問題、分析問題和解決問題。本人Coding了很多年,中間走了不少彎路,雖然最終沒什麼大成就,但總算有一些心得,很願意把自己的一些經驗拿出來跟大家分享,這或許對你的發展有所幫助。

由程式設計師轉為架構師,最繞不開的概念就算是物件導向(OO)了。記得在大學的時候,我們專業開了一門課叫《物件導向的程式設計》。那個時候,我們剛剛學了一門C語言,開發環境用的還是DOS下的Turbo C,半點專案開發的經驗都沒有,純粹的空對空。所以,一學期下來,我始終處於一種懵懂狀態,既沒領會程式導向和麵向物件到底有什麼區別,也沒搞懂物件導向能帶來什麼好處。

2、程式導向(OP)和麵向物件(OO)

2.1 蛋炒飯和蓋澆飯

有人這麼形容OP和OO的不同:用程式導向的方法寫出來的程式是一份蛋炒飯,而用物件導向寫出來的程式是一份蓋澆飯。所謂蓋澆飯,北京叫蓋飯,東北叫燴飯,廣東叫碟頭飯,就是在一碗白米飯上面澆上一份蓋菜,你喜歡什麼菜,你就澆上什麼菜。我覺得這個比喻還是比較貼切的。

蛋炒飯製作的細節,我不太清楚,因為我沒當過廚師,也不會做飯,但最後的一道工序肯定是把米飯和雞蛋混在一起炒勻。蓋澆飯呢,則是把米飯和蓋菜分別做好,你如果要一份紅燒肉蓋飯呢,就給你澆一份紅燒肉;如果要一份青椒土豆蓋澆飯,就給澆一份青椒土豆絲。

蛋炒飯的好處就是入味均勻,吃起來香。如果恰巧你不愛吃雞蛋,只愛吃青菜的話,那麼唯一的辦法就是全部倒掉,重新做一份青菜炒飯了。蓋澆飯就沒這麼多麻煩,你只需要把上面的蓋菜撥掉,更換一份蓋菜就可以了。蓋澆飯的缺點是入味不均,可能沒有蛋炒飯那麼香。

到底是蛋炒飯好還是蓋澆飯好呢?其實這類問題都很難回答,非要比個上下高低的話,就必須設定一個場景,否則只能說是各有所長。如果大家都不是美食家,沒那麼多講究,那麼從飯館角度來講的話,做蓋澆飯顯然比蛋炒飯更有優勢,他可以組合出來任意多的組合,而且不會浪費。

2.2 軟體工程

蓋澆飯的好處就是“菜”“飯”分離,從而提高了製作蓋澆飯的靈活性。飯不滿意就換飯,菜不滿意換菜。用軟體工程的專業術語就是“可維護性”比較好,“飯”和“菜”的耦合度比較低。蛋炒飯將“蛋”“飯”攪和在一起,想換“蛋”“飯”中任何一種都很困難,耦合度很高,以至於“可維護性”比較差。軟體工程追求的目標之一就是可維護性,可維護性主要表現在3個方面:可理解性、可測試性和可修改性。物件導向的好處之一就是顯著的改善了軟體系統的可維護性。

程式導向(OP)和麵向物件(OO)是不是就是指編碼的兩種方式呢?不是!你拿到了一個使用者需求,比如有人要找你編個軟體,你是不是需要經過需求分析,然後進行總體/詳細設計,最後編碼,才能最終寫出軟體,交付給使用者。這個過程是符合人類基本行為方式的:先想做什麼,再想如何去做,最後才是做事情。有的同學說:“我沒按照你說的步驟做啊,我是直接編碼的”。其實,你一定會經歷了這三個階段,只不過你潛意識裡沒有分得那麼清楚。對於拿到需求就編碼的人,可能編著編著,又得倒回去重新琢磨,還是免不了這些過程,以OO為例,對應於軟體開發的過程,OO衍生出3個概念:OOA、OOD和OOP。採用物件導向進行分析的方式稱為OOA,採用物件導向進行設計的方式稱為OOD,採用物件導向進行編碼的方式稱為OOP。程式導向(OP)和麵向物件(OO)本質的區別在於分析方式的不同,最終導致了編碼方式的不同。

2.3 程式導向程式設計(OPP) 和麵向物件程式設計(OOP)的關係

關於程式導向的程式設計(OPP)和麵向物件的程式設計(OOP),給出這它們的定義的人很多,您可以從任何資料中找到很專業的解釋,但以我的經驗來看,講的相對枯燥一點,不是很直觀。除非您已經有了相當的積累,否則說起來還是比較費勁。

我是個老程式設計師出身,雖然現在的日常工作更多傾向了管理,但至今依然保持編碼的習慣,這句話什麼意思呢?我跟大家溝通應該沒有問題。無論你是在重複我走過的路,或者已經走在了我的前面,大家都會有那麼一段相同的經歷,都會在思想層面上有一種理解和默契,所以我還是會盡量按照大多數人的常規思維寫下去。

程式導向的程式設計(OPP)產生在前,物件導向的程式設計(OOP)產生在後,所以物件導向的程式設計(OOP)一定會繼承前者的一些優點,並摒棄前者存在的一些缺點,這是符合人類進步的自然規律。兩者在各自的發展和演變過程中,一定會相互借鑑,相互融合,吸收對方的優點,從而出現某些方面的趨同性。但是,即使兩者有更多的相似點,也不會改變它們本質上的不同,因為它們的出發點不同,完全是兩種截然不同的思維方式。關於兩者的關係,我的觀點是這樣的:物件導向程式設計(OOP)在區域性上一定是程式導向(OP)的,程式導向的程式設計(OPP)在整體上應該借鑑物件導向(OO)的思想。這一段說的的確很空洞,而且也一定會有引來爭議,不過,我勸您還是在閱讀了後面的內容之後,再來評判我觀點的正確與否。

象C++、C#、Java等都是物件導向的語言,c,php(暫且這麼說,因為php4以後就支援OO)都是程式導向的語言,那麼是不是我用C++寫的程式一定就是物件導向,用c寫的程式一定就是程式導向呢?這種觀點顯然是沒有真正吃透兩者的區別。語言永遠是一種工具,前輩們每創造出來的一種語言,都是你用來實現想法的利器。我覺得好多人用C#,Java寫出來的程式碼,要是仔細看看,那實際就是用物件導向(OO)的語言寫的程式導向(OP)的程式。

所以,即使給關羽一根木棍,給你一杆青龍偃月刀,他照樣可以打得你滿頭是包。你就是扛著個偃月刀,也成不了關羽,因為你缺乏關羽最本質的東西---絕世武功。同樣的道理,如果你沒有領會OO思想,怎麼可能寫得出真正的OO程式呢?

那是不是程式導向就不好,也沒有存在的必要了?我從來沒有這樣說過。事實上,程式導向的程式設計(OPP)已經存在了幾十年了,現在依然有很多人在使用。它的優點就是邏輯不復雜的情況下很容易理解,而且執行效率遠高於物件導向(OO)編寫的程式。所以,系統級的應用或準實時系統中,依然採用程式導向的程式設計(OPP)。當然,很多程式設計高手以及大師級的人物,他們由於對於系統整體的掌控能力很強,也喜歡使用程式導向的程式設計(OPP),比如像Apache,QMail,PostFix,ICE等等這些比較經典的系統都是OPP的產物。象php這些指令碼語言,主要用於web開發,對於一些業務邏輯相對簡單的系統,也常使用程式導向的程式設計(OPP),這也是php無法跨入到企業級應用開發的原因之一,不過php5目前已經能夠很好的支援OO了。

2.4 詳解程式導向的程式設計(OPP)

在物件導向出現之前,我們採用的開發方法都是程式導向的程式設計(OPP)。程式導向的程式設計中最常用的一個分析方法是“功能分解”。我們會把使用者需求先分解成模組,然後把模組分解成大的功能,再把大的功能分解成小的功能,整個需求就是按照這樣的方式,最終分解成一個一個的函式。這種解決問題的方式稱為“自頂向下”,原則是“先整體後區域性”,“先大後小”,也有人喜歡使用“自下向上”的分析方式,先解決區域性難點,逐步擴大開來,最後組合出來整個程式。其實,這兩種方式殊路同歸,最終都能解決問題,但一般情況下采用“自頂向下”的方式還是較為常見,因為這種方式最容易看清問題的本質。

我舉個例子來說明程式導向的程式設計方式:

使用者需求:老闆讓我寫個通用計算器。

終端使用者就是老闆,我作為程式設計師,任務就是寫一個計算器程式。OK,很簡單,以下就是用C語言完成的計算器:

假定程式的檔名為:main.c。

int main(int argc, char *argv[]){

    //變數初始化
    int nNum1,nNum2;
    char cOpr;
    int nResult;
    nNum1 = nNum2 = 0;
    cOpr = 0;
    nResult = 0;

    //輸入資料
    printf("Please input the first number:\r\n");
    scanf("%d",&nNum1);
    printf("Please input the operator:\r\n");
    scanf("%s",&cOpr);
    printf("Please input the second number:\r\n");
    scanf("%d",&nNum2); 

    //計算結果  
    if( cOpr == '+' ){
    nResult = nNum1 + nNum2;
    }else if( cOpr == '-' ){
    nResult = nNum1 - nNum2;
    }else{
    printf("Unknown operator!");
    return -1;
    }

    //輸出結果
    printf("The result is %d!",nResult);
    return 0;
}

拋開細節不講,我想大多數人差不多都會這麼實現吧,很清晰,很簡單,充分體現了“簡單就是美”的原則,程式導向的程式設計就是這樣有條理的按照順序來逐步實現使用者需求。

凡是做過程式的人都知道,使用者需求從來都不會是穩定的,最多隻能夠做到“相對穩定”。使用者可能會隨時提出加個功能,減個功能的要求,也可能會要求改動一下流程,程式設計師最煩的就是頻繁地變動需求,尤其是程式已經寫了大半了,但這種情況是永遠無法避免的,也不能完全歸罪到客戶或者需求分析師。

以我們上面的程式碼為例,使用者可能會提出類似的要求:
首先,你程式中實現了“加法”和“減法”,我還想讓它也能計算“乘法”、“除法”。
其次,你現在的人機介面太簡單了,我還想要個Windows計算器的介面或者Mac計算器的介面。

使用者需求開始多了,我得琢磨琢磨該如何去寫這段程式碼了。我今天加了“乘”“除”的運算,明天保不齊又得讓我加個“平方”、“立方”的運算,這要是把所有的運算都窮盡了,怎麼也得寫個千八百行程式碼吧。還有,使用者要求介面能夠更換,還得寫一大堆介面生成的程式碼,又得來個千八百行。以後,這麼多程式碼堆在一起,怎麼去維護,找個變數得半天,看懂了程式碼得半天,萬一不小心改錯了,還得調半天。另外,介面設計我也不擅長,得找個更專業的人來做,做完了之後再加進來吧。這個過程也就是“軟體危機”產生的過程。伴隨著軟體廣泛地應用於各個領域,軟體開發的規模變得越來越大,複雜度越來越高,而其使用者的需求越來越不穩定。

根據使用者提出的兩個需求,程式導向的程式設計該如何去應對呢?我想大家都很清楚怎麼去改。Very easy,把“計算”和“介面”分開做成兩個獨立的函式,封裝到不同的檔案中。
假定程式的檔名為:main.c。

#include "interface.h"
#include "calculate.h"
int main(int argc, char *argv[]){

    //變數初始化
    int nNum1,nNum2;
    char cOpr;
    int nResult;
    nNum1 = nNum2 = 0;
    cOpr = 0;
    nResult = 0;

    //輸入資料
    if( getParameters(&nNum1,&nNum2,&cOpr) == -1 )
    return -1;

    //計算結果  
    if( calcMachine(nNum1,nNum2,cOpr,&nResult) == -1 )
    return -1;

    //輸出結果
    printf("The result is %d!",nResult);

    return 0;
}

interface.h:
int getParameters(int *nNum1,int * nNum2,char *cOpr);

interface.c:
int getParameters(int *nNum1,int * nNum2,char *cOpr){
    printf("Please input the first number:\r\n");
    scanf("%d",nNum1);
    printf("Please input the operator:\r\n");
    scanf("%s",cOpr);
    printf("Please input the second number:\r\n");
    scanf("%d",nNum2);

    return 0;
}

calculate.h:
int calcMachine(int nNum1,int nNum2,char cOpr, int *nResult);

calculate.c:
int calcMachine(int nNum1,int nNum2,char cOpr,int *nResult){
    if( cOpr == '+' ){
        *nResult = nNum1 + nNum2;
    }else if( cOpr == '-' ){
        *nResult = nNum1 - nNum2;
    }else{
        printf("Unknown operator!");
        return -1;
    };
    return 0;
}

“計算”和“介面”分開之後,新增新功能或者修改bug就方便多了,遇到與“計算”相關的需求就去修改calculate模組,遇到與“介面”相關的需求就去修改interface模組,因此,整個系統模組之間的“耦合度”就被放鬆了,可維護性有了一定程度的改善。

程式導向的程式設計(OPP)就是將使用者需求進行“功能分解”。把使用者需求先分解成模組(.h,.c),再把模組(.h,.c)分解成大的功能(function),然後把大的功能(function)分解成小的功能(function),如此類推。

功能分解是一項很有技術含量的工作,它不僅需要分解者具有豐富的實戰經驗,而且需要科學的理論作為指導。如何分解,分解原則是什麼,模組粒度多大合適?這些都是架構師的要考慮的問題,也是我們後面要著重講的內容。

程式導向的程式設計(OPP)優點是程式順序執行,流程清晰明瞭。它的缺點是主控程式承擔了太多的任務,各個模組都需要主控程式進行控制和排程,主控和模組之間的承擔的任務不均衡。

有的人把程式導向定義為:演算法 + 資料結構,我覺得也很準確。程式導向的程式設計中演算法是核心,資料處於從屬地位,資料隨演算法而流動。所以採用程式導向的方式進行程式設計,一般在動手之前,都要編寫一份流程圖或是資料流圖。

3 架構師的職責

近來看到CSDN上有個CTO俱樂部,裡面聊得是不亦樂乎。我懷著無比崇敬的態度,拜讀了一下牛人們的發言。裡面有個哥們發起一個話題:“CTO, 你多久沒有寫程式了?”。有人回答:“不寫程式碼的CTO,屬於......這公司問題大了!”。看到這裡,我就趕緊撤了,怕忍不住反駁幾句,反而遭到牛人們的群毆。試想,一個上點規模的IT公司,還得靠CTO來寫程式的話,那是不是才叫問題大了呢。當然,我沒有做過CTO,所以我有我的不同看法,而且還願意表達出來,無知者無畏。我情願相信:我所理解的CTO跟這位CTO所理解的是兩回事。所以我想,如果有人能把CTO的職責給標準化了,也許就不會有這麼多的爭論了。
同樣的道理,關於架構師的定義,大家也有著不同的理解。什麼是架構師?架構師有哪些職責?我覺得有必要提前明確一下,要不然大家溝通起來也會產生類似問題,子說子理,卯說卯理,但是壓根說得不是一碼子事。

3.1 什麼是架構師

曾經有這麼個段子:

甲:我已經應聘到一家中型軟體公司了,今天上班的時候,全公司的人都來歡迎我。
乙:羨慕ing,都什麼人來了?
甲:CEO、COO、CTO、All of 程式設計師,還有會計、司機都來了。
乙:哇,他們太重視你了,人才啊,這麼多人迎接你!
甲:沒有啊,就一個人!
乙:靠,#%¥$%...

很多的創業公司,一人身兼數職的情形還是很常見的。至少,我是經歷過的,一個人包辦了所有的開發過程,連測試我都做了,絕對的一條龍,但是經常踩鋼絲、騎獨輪車總會有失足的時候,結果有一次,從我手裡發出去的光碟母盤,含有病毒殭屍,以至於被迫收回已經推上市場的2萬張光碟,從那之後,我的心臟就開始變得無比堅強,現在就是整個後臺服務都癱瘓了,我也只是微微一笑。其實,一個人身兼架構師和程式設計師,甚至多種角色,沒什麼不妥,後面還會講這個話題,這種現象不是中國特色,跟國外是完全接軌的。我曾經跟米國的一個工程師在msn中聊過類似的話題,發現他們的路子跟我們們沒什麼不同,在IT這個行業,我們跟世界的差距只有1天,他們剛弄出來的新東西,我們這裡第2天保準見得到。

架構師這個稱呼不是拍腦袋想出來的,是有國際標準(ISO/IEC 42010)可查的。架構師是軟體開發活動中的眾多角色之一,它可能是一個人、一個小組,也可能是一個團隊。微軟對架構師有一個分類參考,我們參考一下,他們把架構師分為4種:企業架構師EA(Enterprise Architect)、基礎結構架構師IA(Infrastructure Architect)、特定技術架構TSA(Technology-Specific Architect)和解決方案架構師SA (Solution Architect)。微軟的這個分類是按照架構師專注的領域不同而劃分的。

EA的職責是決定整個公司的技術路線和技術發展方向。蓋茨給自己的Title就是首席軟體架構師,網易丁磊也喜歡這麼稱呼自己,實際上就是EA角色;IA的工作就是提煉和優化技術方面積累和沉澱形成的基礎性的、公共的、可複用的框架和元件,這些都是一個技術型公司傳承下來的最寶貴的財富之一;特定技術架構師TSA,他們主要從事類似安全架構、儲存架構等專項技術的規劃和設計工作;SA的工作則專於解決方案的規劃和設計,“解決方案”這個詞在中國已經到了嚴重氾濫的程度,大忽悠們最喜歡把它掛在嘴邊。所謂解決方案,就是把產品、技術或理論,不斷地進行組合,來創造出滿足使用者需求的選擇。售前工程師一般都是帶著它到客戶那裡去發揮的。

大公司會把各種型別的架構師分得很清楚,小公司一般就不那麼講究了,架構師多數是是IA+TSA+SA,一人包打天下,所以說大公司出專才,小公司出全才。

實際工作中,我們也經常會見到另一種比較簡單的分類方式,把架構師分為軟體架構師和系統架構師。軟體架構師基本上是TSA+IA,這也是程式設計師最容易突破,最可能走上的一條道路,比如JAVA架構師、DotNet架構師、LAPM架構師等等,我後面所講的內容都是與軟體架構師的相關的話題。系統架構師實際上是SA+TSA,更著力於綜合運用已有的產品和技術,來實現客戶期望的需求。系統架構師要求通曉軟、硬體兩方面的知識,所以它的知識體系相對龐雜。關於系統架構師的話題,我們可以稍後再作討論。

3.2 架構師的職責

架構師需要參與專案開發的全部過程,包括需求分析、架構設計、系統實現、整合、測試和部署各個階段,負責在整個專案中對技術活動和技術說明進行指導和協調。

架構師主要職責有4條:

1、確認需求

在專案開發過程中,架構師是在需求規格說明書完成後介入的,需求規格說明書必須得到架構師的認可。架構師需要和分析人員反覆交流,以保證自己完整並準確地理解使用者需求。

2、系統分解

依據使用者需求,架構師將系統整體分解為更小的子系統和元件,從而形成不同的邏輯層或服務。隨後,架構師會確定各層的介面,層與層相互之間的關係。架構師不僅要對整個系統分層,進行“縱向”分解,還要對同一邏輯層分塊,進行“橫向”分解。

軟體架構師的功力基本體現於此,這是一項相對複雜的工作。

3、技術選型

架構師通過對系統的一系列的分解,最終形成了軟體的整體架構。技術選擇主要取決於軟體架構。

Web Server執行在Windows上還是Linux上?資料庫採用MSSql、Oracle還是Mysql?需要不需要採用MVC或者Spring等輕量級的框架?前端採用富客戶端還是瘦客戶端方式?類似的工作,都需要在這個階段提出,並進行評估。

架構師對產品和技術的選型僅僅限於評估,沒有決定權,最終的決定權歸專案經理。架構師提出的技術方案為專案經理提供了重要的參考資訊,專案經理會從專案預算、人力資源、時間進度等實際情況進行權衡,最終進行確認。

4、制定技術規格說明

架構師在專案開發過程中,是技術權威。他需要協調所有的開發人員,與開發人員一直保持溝通,始終保證開發者依照它的架構意圖去實現各項功能。

架構師與開發者溝通的最重要的形式是技術規格說明書,它可以是UML檢視、Word文件,Visio檔案等各種表現形式。通過架構師提供的技術規格說明書,保證開發者可以從不同角度去觀察、理解各自承擔的子系統或者模組。

架構師不僅要保持與開發者的溝通,也需要與專案經理、需求分析員,甚至與終端使用者保持溝通。所以,對於架構師來講,不僅有技術方面的要求,還有人際交流方面的要求。

3.3 架構師的誤區

1、架構師就是專案經理

架構師不是專案經理。專案經理側重於預算控制、時間進度控制、人員管理、與外部聯絡和協調等等工作,具備管理職能。一般小型專案中,常見專案經理兼架構師。

2、架構師負責需求分析

架構師不是需求分析員。需求分析人員的工作是收集需求和分析需求,並與終端使用者、產品經理保持聯絡。架構師只對最終的需求稽核和確認,提出需求不清和不完整的部分,他會跟需求分析員時刻保持聯絡。架構師是技術專家,不是業務專家。

3、架構師從來不寫程式碼

這是一個尚存爭論的問題。目前有兩種觀點:

觀點1:架構師不寫程式碼,寫程式碼純體力活,架構師寫程式碼大材小用。架構師把UML的各種檢視交給開發人員,如果有不明確的地方,可以與架構師隨時溝通。

觀點2:架構師本來自於程式設計師,只是比程式設計師站的層面更高,比程式設計師唯一多的是經驗和知識,所以架構師也免不了寫程式碼。

我個人覺得這兩種說法是與架構師的出身和所處的環境有關。

架構師首先是一個技術角色,所以一定是來自於技術人員這個群體,比如系統架構師,多是來自於運維人員,可能本身程式碼寫得並不多,或者說寫不出來很漂亮的程式碼。軟體架構師多是來自於程式設計師,有著程式設計師的血統和情懷,所以在專案開發過程中,可能會寫一些核心程式碼。我們的理想是架構師不用寫程式碼,但事實上有時候過於理想。架構師寫不寫程式碼,可能取決於公司的規模、文化、開發人員的素質等現實情況。另外,架構師也不是跟程式設計師界限分得那麼清楚,按照能力也有高中低之分,寫不寫程式碼不是區分兩者的根本標準。

3.4 架構師的基本素質

周星馳有個片子《喜劇之王》,劇中的尹天仇整天揣著本《演員的自我修養》,一個好演員不僅需要天賦,也需要一定的理論指導,無師自通的人畢竟是少數。架構師的成長過程也是這樣。從普通程式設計師到高階程式設計師,再到架構師,是一個經驗積累和思想昇華的過程。經驗積累是一個方面,素質培養是另一個方面,兩者相輔相成,所以我覺得有必要把架構師的所要具備的素質羅列一下,作為程式設計師努力的方向。

1、溝通能力

為了提高效率,架構師必須贏得團隊成員、專案經理、客戶或使用者認同,這就需要架構師具有較強的溝通能力。溝通能力是人類最普遍性的素質要求,技術人員好像容易忽略,想成為架構師就不能忽略。千萬不要抱著這樣的觀念:懷才跟懷孕似的,時間久了總會被人發現的。還是天橋上賣大力丸的哥們說得對:光說不練假把式,光練不說傻把式。看看你周圍的頭頭腦腦們,哪一個不是此中高手,我們千萬不要鄙視,認為這是阿諛奉承、投機鑽營,凡事都要看到積極的一面,“溝通”的確是一種能力。我認為自己是一個略內向的人,因為我是農村出來的孩子,普通話都說不好,以前或多或少帶有點自卑感,幻想著是金子總會發光,所以在職業生涯中吃了不少虧。現在,我深深懂得了溝通的重要性,我會很主動地跟同事們,跟老大們不定時地溝通,感覺工作起來順暢多了。

這一條我認為最為重要,所以排在首位。我甚至認為下面幾條都可以忽略,唯一這一條得牢記,而且要常常提醒自己。

2、領導能力

架構師能夠推動整個團隊的技術進展,能在壓力下作出關鍵性的決策,並將其貫徹到底。架構師如何來保證這種執行力?這就需要架構師具有領導能力。

架構師的領導能力的取得跟專案經理不太一樣。專案經理主要負責解決行政管理,這種能力與技術關係不大,他有人權和財權,再扯上一張“領導”的虎皮,採用“胡蘿蔔加大棒”的方式,基本上可以保證執行力。架構師在專案裡面可能更多地使用非正式的領導力,也就是我們常說的影響力,裡面包括個人魅力、技術能力、知識傳遞等等。

3、抽象思維和分析能力

架構師必須具備抽象思維和分析的能力,這是你進行系統分析和系統分解的基本素質。只有具備這樣的能力,架構師才能看清系統的整體,掌控全域性,這也是架構師大局觀的形成基礎。你如何具備這種能力呢?一是來自於經驗,二是來自於學習。架構師不僅要具備在問題領域上的經驗,也需要具備在軟體工程領域內的經驗。也就是說,架構師必須能夠準確得理解需求,然後用軟體工程的思想,把需求轉化和分解成可用計算機語言實現的程度。經驗的積累是需要一個時間過程的,這個過程誰也幫不了你,是需要你去經歷的。但是,如果你有意識地去培養,不斷吸取前人的經驗的話,還是可以縮短這個週期的。這也是我寫作此係列的始動力之一。

4、技術深度和廣度

架構師最好精通1-2個技術,具備這種技術能力可以更加深入的理解有關架構的工作原理,也可以拉近和開發人員的距離,並形成團隊中的影響力。

架構師的技術知識廣度也很重要,需要了解儘可能多的技術,所謂見多識廣,只有這樣,才可能綜合各種技術,選擇更加適合專案的解決方案。有的人說,架構師技術廣度的要求高於技術深度的要求,這是很有道理的。

總而言之,一句話:架構師是專案團隊中的技術權威。

程式導向和麵向物件這兩個基本概念,不僅架構師需要非常清楚,程式設計師、設計師也要非常清楚,這也是系統分析、設計和編碼最基本的常識。我接觸的程式設計師,很多人只停留在一種“似是而非”的程度,這是不行的,想要繼續前進,就得把基礎夯實,所以我覺得很有必要先回回爐,補補課。

3.5 詳解物件導向的程式設計(OOP)

3.5.1 什麼是物件導向

剛接觸程式設計的時候,多數人本能的反映可能是程式導向(OP)的,而不是物件導向(OO)的。這種現象其實是很正常的,改變思維方式是需要一個過程的,我大體歸納了一下其形成的原因:

1、直接原因

你還沒有養成物件導向分析問題和解決問題的習慣。建立物件導向的思維方式需要一定時間的訓練和揣摩才能形成,所以你可以在學習或具體專案中刻意地強化這種意識。一般情況下,經過一段時間之後,你會覺得這是自然而然的事情,只有心中OO,眼中自然OO了。

2、歷史原因

我們從小接受的培訓都是採用程式導向(OP)的方式分析問題和解決問題,尤其是數學,多數是強調按部就班的解決問題,計算機軟體的發展一直就與數學是很有淵源,所以,順理成章的,把程式導向(OP)的方式帶入到軟體開發也是很自然的事情。

什麼是物件導向,或者談談你對物件導向的理解,這恐怕是軟體開發人員,尤其是程式設計師和設計師應聘的時候,面試官常最掛在嘴邊的問題吧。物件導向對應的英文是Object-Oriented,把Object-Oriented翻譯成“物件導向”,我一直覺得這個譯法不太確切,因為多數人第一次看到“物件導向”這四個字,都很難從字面上理解它到底是什麼意思。後來,我又查閱了一些有關的資料,發現港澳臺的計算機書籍中是把它翻譯成了“物件導向”,這個譯法,我感覺不錯,於我心頗有些慼慼焉。“物件導向”比較準確地反映了物件導向認識和解決問題都是要圍繞物件展開的。

所以,物件導向的思維方式認為:軟體系統是一組互動的物件的集合。一組相關的物件組合為一個子系統,一組子系統繼續組合為更復雜的子系統,直至組合成整個系統。

物件導向方式的出發點是儘可能模擬人類習慣的思維方式,將“問題域”中涉及的內容抽象為“物件”,使軟體開發的方法與過程儘可能接近人類認識世界解決問題的方法與過程。

程式導向就是分析出解決問題所需要的步驟,然後用函式把這些步驟一步一步實現,使用的時候一個一個依次呼叫就可以了。物件導向是把構成問題事務分解成各個物件,建立物件的目的不是為了完成一個步驟,而是為了描敘某個事物在整個解決問題的步驟中的行為。

程式導向認識和解決問題的思維,可以稱為“流程論”,重點放在處理過程的步驟,流程是整個系統的核心。

物件導向認識和解決問題的思維,可以稱為“組裝論”,重心放在物件的抽象和提取上,然後將物件組裝為整體。

所以OO和OP從思維方式來講,出發點還是完全不同的。

3.5.2 OP PK OO

我們們用象棋對戰的例子,來比較OP和OO的不同:

紅方:功夫熊貓 黑方:悍嬌虎 裁判:龜仙人

採用程式導向(OPP)的設計思路,首先分拆整個對戰過程,分析雙方對戰的步驟,得到如下流程:

把上面每個步驟分別用函式進行實現,問題就解決了。

我們再來看看物件導向是如何來解決問題,整個象棋遊戲可以抽象出3種物件:

1、棋手,負責行棋,這兩者行為一致。

2、棋盤,負責繪製棋盤畫面。

3、裁判,負責判定諸如吃子、犯規和輸贏。

三者之間的關係如下:

第一類物件棋手負責行棋,並告知第二類物件棋盤中棋子佈局的變化,棋盤接收到了棋子佈局的變化後,負責在繪製螢幕,同時利用第三類物件裁判來對棋局進行判定。

從以上兩種的實現方式可以看出幾點:

1、可維護性

物件導向是以資料和功能來劃分問題,而不是依據流程和步驟。同樣是繪製棋盤的行為,在程式導向的設計中分散在了很多的步驟中,很可能出現在不同的繪製版本中,只是不是很像一份“蛋炒飯”中的雞蛋?在物件導向的設計中,繪圖只可能在棋盤物件中出現,從而保證了繪圖的統一,這就是把雞蛋從“蛋炒飯”中分離出來的效果。

2、可擴充套件性

假如我要加入悔棋的功能,如果要改動程式導向的設計,那麼從行棋到顯示再到判定這一連串的步驟都要改動,甚至步驟之間的循序都要進行大規模調整。如果是物件導向的話,只用改動棋盤物件就行了,棋盤物件儲存了雙方的棋譜,簡單回溯,減一就可以了,而顯示和判定不涉及,同時整體對各個物件功能的呼叫順序都沒有變化,改動只限定在了區域性。

3.5.3 OO的深層思考

OO認為:軟體系統是一組互動的物件的集合。

因為人類對現實世界是非常熟悉的,所以OO就是通過抽象的方式,把問題域對映到現實世界,儘量模擬現實世界的萬事萬物。通過這種方式,就可以運用現實世界中解決問題的方法與過程,來解決軟體領域內的問題。

有人說:OO眼裡一切皆物件,這句話還是很有道理的。

OO到底給軟體開發帶來了什麼樣的好處?OO的抽象的尺度是如何把握的呢?這都是問題。

相關文章