軟體工程—思考專案開發那些事(一)

發表於2015-08-07

1.背景

最近對軟體開發有了一個新的認識,這個認識源自連續看了兩本Craig larman大師的書籍《UML與模式應用》、《精益與敏捷開發大型應用實戰》和公司目前的專案情況這兩件事情一起碰撞導致的感悟。

先說下前者,為什麼會想到看Craig larman大師的書籍。其實我收藏的書籍已經上千本,在各個電商平臺上都有帳號,目的只有一個就是收藏好的書籍。家裡也堆了很多,沒事瀏覽新書是我現在最大的樂趣。我相信有這種感覺和愛好的不止我一個人,家裡堆上幾十本書的在IT行業算是很正常的。

書多了有時候不知道要看些什麼也很正常,我的原則就是隨時調整,看目前所面臨的困惑。根據我以往的經驗總結,在實際問題面前尋找答案最容易讓你有新的感悟和提升。我相信書中自有黃金屋、書中自有顏如玉,要在對的時間看對的書,說白了就是在有困惑的時候就去尋找給你答案的這方面書籍。為什麼要看Craig larman大師的書,是因為最近的工作內容有很多自己搞不懂的地方,希望能通過大師的指點有所感悟,果然受益匪淺。

再說下後者,最近一直在和這幾個事情打交道:遺留程式碼、技術債務、專案管理、專案質量、開發進度、快速開發、重構、單元測試、敏捷開發、Scrum、XP,你可能會有點疑惑,有些東西是重複的,比如專案管理中包含了專案質量、開發進度,再比如敏捷開發與Scrum和XP,似乎我在把一個大的概念拆解成多個小重複的概念。我之所以這麼做,是因為我想強調這些概念的區別和真正的相互作用,從軟體工匠的藝術角度出發來真正的看待這些概念。比如說,專案質量與程式碼有關係嗎,開發進度與遺留程式碼有關係嗎,專案管理與技術債務有關係嗎等等,這些問題的本質是完全不同的,作為技術人員尤其是應用開發的技術人員一定要強調概念,一定要明白不同的概念的本質含義,如果你不強調概念我想你的程式碼是寫不好的,對業務的理解也不會深刻。

最近我將自己的技術生涯的目標定為“軟體工匠”,其實說實話我不在乎title,我只在乎自己的工作內容是什麼。軟體工匠是沒有邊界的,只要和軟體開發有關係的內容都是屬於工匠需要去專研的領域。如果工匠離開工具就喪失了工匠的真正價值所在,所以說千萬別放棄寫程式碼。不管你是一名架構師還是一名開發經理,程式碼永遠是產品的最終設計,一旦你離他而去就離產品的質量越來越遠,後面我也會講下為什麼程式碼如此重要。

 

2.專案管理,質量、度量、進度

這節的標題是不受歡迎的,大家知道為什麼嗎。技術人員是能明白的,有過長達5-10年的開發出生的管理者也是能明白的,唯一不明白的就是沒有太多開發經驗的管理者,或者那些不喜歡開發的管理者,那些逃避開發的管理者,因為他們離真正的產品實現太遙遠,他們離軟體開發領域真正的問題太遙遠,管理一旦忽視程式碼質量問題就會慢慢找上你,你的專案往後的質量越無法控制,度量、開發進度都會遇到瓶頸。

說個當下的現象,我從事一線開發也有好幾年了,陸陸續續看到很多人轉作管理,但是你會發現做管理的人一般都是技術水平一般的人,或者對技術沒有太多追求的人,更誇張的是在有些小公司的管理者可能就沒寫過程式碼。

為什麼會出現這種現象,其實主要原因有兩個,首要的就是個人的職業規劃,在就是公司的價值導向。先說價值導向,往往寫程式碼的人的價值沒有專案管理的價值大,這在一些中小公司還是很普遍的,真正的科技型公司這類問題幾乎沒有。而職業規劃是完全可以接受的,畢竟每個人的興趣和追求不同,這無可厚非,應該尊重每個人的選擇。但是這裡的問題是,一旦沒有太多技術底蘊的技術人員坐上專案管理者的職位後會對技術的理解360度大轉彎。這其實是不對的,專案的成敗不可忽視技術。

不繼續討論這個話題了,這不是本篇文章的重點,人各有志,選擇是正常的,但是要明白的是選擇的本質不是價值導向,而是興趣導向,這才不會讓你忽視另外一個角度,因為一個軟體產品的最終成功是要靠專案管理和軟體工程相共同的努力,缺一不可。

這裡想聊聊專案管理的三個重要的方面,質量、度量、進度。首先我不是一個專業的專案管理者,但是我是一名專業的軟體工程師,我不知道專案管理的具體內容有哪些,但是我知道專案管理的最終目標是和軟體工程的目標是一致的,都是為了專案高質量的完成。

專案的成敗光靠專案管理是解決不了的,如果可以就不會出現《軟體工程》、《設計原本》了。保證軟體專案的真正成功是需要軟體工程的支撐才行,而管理更加是對開發的組織、協調、溝通上的,這是兩個層面兩個角度互相作用的。專案管理中不會有設計、抽象、可維護性等這些內容。

這裡尤其想討論的就是軟體專案的質量,現在看來衡量軟體專案的質量忽視了程式碼的質量,客戶驗收、功能完成、穩定上線,沒耽誤進度,這就是完成了一個專案,我們忽視了一個就是程式碼的質量,為什麼要關心程式碼的質量。

度量,度量是對開發週期內所有發生的事情進行資料視覺化,BUG數、釋出回退數、程式碼行數(比較特殊)、需求變更數等等,還有些我不是太清楚的度量資料,總之應該會有很多。度量的目的是為了什麼,是為了能夠在這些資料出來後改善專案的各方面質量,控制各個不穩定的方面。

開發進度,“質量”一段中我最後丟擲了一個問題“為什麼要關心程式碼的質量”,因為他直接決定了你的專案進度,當你的程式碼質量越來越差的時候你就失去了對專案進度的控制。你再多的度量指標都是無意義的,就算你可以統計出BUG數上升了,但是你也控制不了BUG數下降,因為你已經偏離正常航線太遠,就算你可以控制需求變更的速度和次數,但是你無法控制適應變更的程式碼的速度和次數。變更是無法避免的,你的程式碼無法面對這些複雜的變化,因為你的程式碼不是設計出來的而是堆出來的。最後你的專案質量也無法很好的保證。

(圖1:專案管理與軟體工程的結合才是完整的軟體開發)

最近在看Michael C. Feathers 大師的《修改程式碼的藝術》一書,感觸頗多。裡面講到了我們面對遺留程式碼的時候,為了增加一個新的功能要付出多少時間和精力,出現明顯的BUG機率有多高,出現隱藏的BUG機率有多高。遺留程式碼直接決定了上述三個專案管理的方面。Michael C. Feathers 大師強調了很多關於我上面講到的專案管理和程式碼質量之間的關係,這本書很值得看。

其實真正推動軟體開發不斷髮展的是軟體工程、開發方法論,專案管理只是輔助於軟體工程在時間和空間上有效實施。

這裡還要區別下就是專案管理和團隊管理的區別,這兩個東西是不一樣的。專案管理基本上不需要軟體工程的支援,但是團隊管理在某些方面是需要軟體工程的支援才能做的更好。

 

3.軟體開發是一種設計活動而不是建築活動

在《精益與敏捷開發大型應用實踐》一書中是這樣描述軟體設計和架構的:

1:“軟體架構借鑑了建築的架構,但結果證實這是個不太恰當的類比,而且給軟體開發帶來了有趣的副作用。建築是硬的,因為在這個領域,設計只在施工前進行一次,然後該建築或者設計就幾乎是永久不變的了。注意建築師和施工工人是不同的。但是軟體不是一座建築,軟體是軟的,而且程式設計也不是施工的過程,“軟體架構”只不過是一大堆比喻列表中可以選擇的一個不太完美類比而已”。

2:“……唯一確實看起來滿足工程設計條件的軟體文件是原始碼“。

3:”我意識到圖表和文件並不是真正的設計,而原始碼才是真正的設計。再次重申“……唯一確實看起來滿足工程設計條件的軟體文件是原始碼“。

這幾句話足以證明軟體開發是一個非常複雜的過程,是思維密集型腦力活動,而且體現在每一個編碼過程中。在很多專案管理中都認為軟體開發是一個非常簡單的活動,主要架構設計好編碼是比較簡單的,難道真的是這樣嗎,我們再看看書中怎麼說的:

1:”原始碼是真正的藍圖“。

2:”真正的架構在哪裡,無論好壞、有意或偶然的?是在架構團隊維護的文件中?還是在上萬個檔案中?顯然是後者,原始碼是真正的設計,而且它的總和反映了真實的大型設計或架構。架構就是架構,不是某人的意願“。

現在很多開發者還有一個明顯的技術理解錯誤就是”寫程式碼“是比較簡單的活動。複雜的是軟體架構,只要架構設計好後寫程式碼應該是程式設計師的事兒,這裡明顯有一個錯誤的價值觀,認為寫程式碼的人都是廉價的,不具有任何的設計和創造新。這其實是一個很不專業的看法。真以為一個簡單的PPT、WORD文件中的架構圖就表示架構了。其實這個想法是很幼稚和膚淺的。用Craig larman大師的話講,在整個軟體生命週期的活動中,複雜的是編寫程式碼,而程式碼才是架構,所以說架構的就是程式碼。你原本理解的架構才是真正難的地方其實也就是程式碼才是真正難的地方,不可浮於表面,這樣才能更加的接地氣才能真正的有價值。

架構師應該深入到一線參與一些開發,這時會發現很多問題,然後將問題帶到架構的位置,用架構的視角設計方案,在親自把這個方案帶到一線落實下去,這才是架構落地一個技術方案的正確方法。

軟體開發是一項設計活動而不是建築活動,軟體是會不斷變化的,而建築一旦敲定是不會改變的。

 

4.快速開發(簡單的系統結構與複雜的業務模型)

這節我想聊聊快速開發。在圈子裡面對快速開發的理解大部分都是和快速開發框架對應起來,覺得應該有一個框架來支援快速開發。只要有了一個框架就可以進行快速開發。這樣的看法或想法其實是錯誤的,對快速開發的理解太狹隘。

《設計原本》作者,電腦科學巨匠Frederick P. Brooks說過,對於軟體開發來說沒有銀彈存在,沒有所謂的能夠用簡單發方法來開發複雜的系統。越複雜的系統開發起來不會簡單的,開發一個滿足100個人使用的系統和開發一個滿足1000個人使用的系統在複雜性上已經完全不同了。量變引起質變,當業務量、訪問量、資料量等等這些軟體指標超出一定的範圍之後就和最初的設計完全不同,設計思路也完全不同。

回到當下。我現在經常面臨這樣的一個問題,我現在所從事的業務是比較複雜的,對系統的設計要求很高。如果用量來比喻的化,其實我現在所面對的業務量是比較大的,業務量中的業務複雜性的量其實相比於訪問量、資料量等方面的量在設計方法要難的很多。通常做設計的架構師都只會考慮併發量、訪問量而忽視業務量,比如業務的多變性、業務的擴充套件性,業務本身的複雜性,這尤其考研設計能力,考驗抽象能力。這跟你用什麼程式語言用什麼資料庫是沒太大關係的。你腦袋裡運用的是OO、實體關係,這些與具體技術框架沒關係的設計思維。

業務量對於編寫程式碼要求要高很多,同比於其他幾個量來說很難落地。訪問量、併發量可以通過基礎架構的調整優化升級來解決,而業務量的問題域是業務邏輯,是領域模型,當前所面對的業務域,任何一個細小的業務都需要在程式碼中體現。

最近陸續在做一些系統重構的工作,就在前兩天我重構了一段程式碼,不是基礎性的程式碼,是業務邏輯程式碼。大概情況是這樣的。

在系統中有一個重要的領域概念“重量”,這個重量的概念存在很多個業務量的質變可能性,就是說它本身不是簡單不變的,隨時存在著變化,當我們品類擴充的時候就立馬會變化。

重量的定義是這樣的:重量=單件重×數量,看上去好像很簡單的樣子,其實不是,這裡的單件重是會變化的,有些時候是保留3位小數有些時候是保留6位小數。而且這個重量的業務邏輯是在N多個地方都需要用到的,檢視程式碼下來大概有幾十個地方都在重複著編寫“重量“的業務邏輯。

後來我在同事的協助下重構了這塊業務模型,為什麼我這裡不用業務邏輯來形容我的重構工作,是因為我考慮業務的時候不會是過程式的,如果用”業務邏輯“來思考業務就會給人造成一個錯覺就是”過程式“的程式碼結構。所以我考慮任何業務都是”模型驅動開發“方法,業務要抽象為模型才能重用、擴充套件、抗變化性。這其實是OOA/D的精髓。業務邏輯只是在模型中的一小塊一小塊的具體動作,它是在模型的範圍內使用的,而不能一上來就是業務邏輯,業務邏輯太細小不便於抽象化。

(圖2:重量、單件重模型 檢視原圖

我用上面的這個模型對重量業務模型進行了重構。將原本很重要的業務概念重量、單件重、不同型別的單件重,進行了概念顯示化,保證這些重要的領域模型不被過程式的程式碼淹沒。且用兩個工廠封裝了建立重量和單件重的業務邏輯。這樣做之後我們的模型就具有抗變化性,以後要是對Weight有任何的建立邏輯的變動我們就可以在WeightFactory中處理,如果有新的品類擴充進來後需要對單件重相關的處理我們只需要擴充套件下ItemCategory和PieceWeightFactory兩個模型。如果你需要做為完全配置化,這個時候模型就更有價值。比如,我們可以將IitemCategory拿出去,通過品類擴充套件的時候自動生成相關的型別,如果你覺得這還不夠完美,我們可以進一步將PieceWeightFactory中有關於“根據ItemCategory建立PieceWeight(Decimal) “,做成”Mapper模型“在進行配置化。

這裡你會發現一個很奇妙的地方就是,一旦模型化後業務的量變引起的質變可以通過逐步重構模型、提取模型、精華模型來解決。

所以說簡單的系統結構是無法表示複雜的業務模型的,如果可以的話OO語言就不會發展成今天的這樣子。複雜的業務無法通過簡單的系統結構或者說所謂的簡單的快速開發框架之類的東西可以解決的。

 

5.技術人員的業務理解與產品經理的業務理解的最終業務模型

很多時候我們都在強調“多去了解業務、多去熟悉業務”,在業務驅動型公司這是必須的,公司中的任何角色的單位都需要熟悉公司的業務範圍。這沒有問題,我想說的是不同的角色對於業務的理解最終的業務模型是不同的。

不管是在傳統的軟體企業中還是網際網路企業中,我們要用軟體來服務於我們或者客戶,當然這裡所說的是業務系統。業務系統的核心就是業務,系統的精神就是業務模型及模型之間的關係。

這節我想說的是,技術人員去了解業務後和產品經理去了解業務後最終的業務模型是怎樣的。技術人員與產品經理是不同的角色,具有不同的職業背景,不同的知識結構和專業度。現在存在一個普遍的認識錯誤是,技術人員理解業務後與產品經理理解的業務後的最終的模型是一樣的,是怎樣的呢。是無法抽象的業務,大概的業務,場景化的業務,無法落地到系統中的業務。此時技術人員並沒有用自己的專業度來對業務進行抽象和建模,並沒有直接帶來真正的價值,而是在交談和理解需求的時候感覺上的價值錯覺。

技術人員不能夠業務技術化其實對於公司所說的“當技術人員理解業務後產生的價值是巨大的”其實是不準確的。

5.1.產品的業務理解(業務流程、資料流程及場景)

產品對於業務的理解是整體上的,包括業務流程、資料流程,場景,在他們的腦子裡是真實的業務場景,是必須要還原的業務場景,不能夠有任何的其他模型在作怪。如果產品用任何的其他知識來抽象和強制理解業務是會出現問題的。

產品對於業務的最終模型是業務流程、資料流程和一個不需要表現的場景。

(圖3:產品的業務理解最終模型—業務流程圖)

由於資料流程圖比較簡單,當前例子中只會有“訂單”的資料實體,畫出來意義不大,我這裡就只畫一個業務流程圖來表達意思即可。

在這個程度上是無法直接將流程圖落到系統上的,它距離真正編寫軟體還有一段過程要進化,而下面那段過程才是技術人員理解業務後要發揮的價值和作用。

5.2.技術人員的業務理解(領域模型、設計模型、抽象建模)

技術人員的瞭解業務要有所側重,你理解的業務和產品理解的業務是不一樣的,技術人員需要將業務最終技術化才行。技術人員的最終的業務模型是有正確的模式可以參考的,就拿“建立訂單”這個流程來說,等待技術人員需要去提取和抽象的東西是比較多的也是比較複雜的,需要結合很多的知識來進行設計活動。

比如訂單,你需要結合“四色原型”模式來提取“訂單”的模型,包括“訂單的型別“、”訂單的跟蹤“,需要結合設計模式來抽象”建立訂單的邏輯“,根據”不同的訂單型別建立不同的最終訂單“。還需要進行設計模型的抽象,比如建立訂單,各個物件的互動是如何的,每個互動的輸入和輸出是什麼。這些都需要技術人員理解了業務後應該具有的業務模型,如果需要將模型語言化就需要結合使用UML來建模。

如果技術人員理解業務後和產品經理理解業務後的結果是一樣的,那技術人員要去理解有什麼價值。技術人員理解業務後要系統化的將各個業務模型落地到具體的領域內或者說某個子系統子服務中,然後各個系統和服務是如何互動的,邏輯的歸屬到底是哪邊的。最終你寫出來的程式碼才是滿足業務的程式碼模型,才是有核心競爭力的業務系統有別於無核心競爭力的系統差距。

技術人員瞭解業務後,針對不同的業務場景開始建立領域模型草圖,根據領域草圖再進行設計模型草圖建立,當然這是一個敏捷的迭代的過程。

(圖4:“建立訂單”相關的領域模型 檢視原圖

有了領域模型之後就需要建立設計模型,也就是各個模型之間的協作關係。還是要強調下,這是一個快速迭代的過程,且勿將其看成是瀑布的依賴過程。領域模型的精華也是沒有止境的,當後面進行設計模型的過程時會有對領域模型有補充的靈感,此時不可以教條,要快速的精華領域模型然後再進行設計模型的過程。

(圖5:“建立訂單”相關的設計模型 檢視原圖

基於領域模型建立設計模型中的物件協作模型,設計模型不僅僅只有協作模型一種還有其他的。協作模型是必須的也是最重要的。有了協作模型之後我們就可以走查場景是否滿足“建立訂單”的這麼一個業務動作。當八九不離十的時候就可以進入到編寫程式碼階段,進行一個快速的構建程式碼模型,因為這個時候還是會有問題出現,只有在程式碼模型中沒有問題後才是真的沒有了。

我這裡只是假設一個簡單的業務場景作為示例,目的是為了介紹技術人員區別於產品對於業務理解後的最終模型是不同的。技術人員一定要有完善的能將業務技術化的知識結構,這樣才能真正的將業務發揮價值。

 

6.技術債務(腐爛的遺留程式碼)

技術債務其實是無法避免的,各種原因,時間進度、需求變更、市場迫切等,都迫使研發開始堆積技術債務,程式碼逐漸開始腐爛,難道我們作為技術人員就只有抱怨和推卸責任嗎。這裡我有一些個人看法,這些個人看法可能跟你的理解不一樣,你可能會說我太理想主義了,但是我想說的是:“作為一個技術人員一定要有情懷,一定要有追求。”用我最尊敬好朋友馮老師的話說:“寫程式碼一定要考究“。就算在時間比較緊的時候可以先寫,但是要記住你的工作並沒有完全完成。

我是從開發做到架構,經歷過很多專案磨練,也深知在專案時間比較緊急的時候自己是在一個什麼精神狀態下寫程式碼的,自己也幹過到處複製程式碼貼上程式碼的時候,加班到12點,眼睛基本上已經很難看清程式碼,敲程式碼的速度已經趕不上功能交付的速度。我只能說這也沒有辦法,市場決定了專案的進度。我們可以吐槽,但是不能抱怨,更不能消極。

其實現實情況下我們做開發的基本上都是在這個節奏下工作,但是我是怎麼處理這個問題的呢。首先寫好程式碼是個人對技術的一個追求和職業素養的問題,如果你對程式碼沒有美感你很難能編寫出好的程式碼,你的程式碼也會到處留有壞味道,時間長了就是腐爛的遺留程式碼,嚴重的技術債務,研發整天怨聲四起,各種抱怨,吐槽,這樣下去其實是不好的,團隊裡有追求的技術人員會流失。

實話實說,當自己今天晚上12點寫好了程式碼提交了測試,但是我的工作並沒有完成,我通常會在早上很早就醒了,我會很早的來到公司對自己的程式碼進行重構和梳理,早上是大腦特別清醒的時候,在這個時候你進行程式碼的整理是非常不錯的,而且這個時候公司一般都沒什麼人,特別安靜,當你重構完程式碼舒服舒服的再去整理自己每天早上來的其他事務。

你可能會說那是你個人問題,我不一定會在第二天早上能起的那麼早,就算起的來我到了公司也不會對第二天的程式碼進行整理,因為那已經上線了已經是完成的功能,我該繼續下一個需求。

用我的價值觀來看的話,其實你的工作只完成了一半,你並沒有保質保量的完成工作,你的軟體交付質量在產品層面是完成了,但是你在技術層面是有殘缺的。你給軟體帶來了很多的技術債務,你給某個物件帶來了腐爛程式碼的開始。

這點我現在的公司是非常不錯的,公司高層對專案的管理者首要的要求就是必須懂技術。

我一沒事就會和我的好朋友也是好同事馮老師交流技術,互相review程式碼,提意見,在互相重構,彼此學習。我們有一個共鳴,就是讓寫程式碼有追求的人來把控專案是非常不錯的,可以保質保量的完成功能,當然不是光說有寫程式碼能力就OK的,需要綜合性的。其實說白了,讓一個精通技術的人在去精通業務做出來的軟體應該是不錯的。 (這裡所說的精通技術是指應用開發方面的精通,不是指技術專家、系統層的技術專家)

作為應用開發人員,要時刻記住你所應該具有的專業的職業素養,寫程式碼要講究,要記住對你來說程式碼意味著什麼。

未完待續。。。。。。

相關文章