摘要:在本文中,我們將探討軟體開發過程中關於角色、重構和質量的問題。
“每天都會有更多的技術發生,每家公司都在網際網路上,每家公司都將成為一家科技公司。”OKTA營運長兼聯合創始人Frederic Kerrest說道,因為他們必須找出使用該軟體的更好方法。軟體不僅成為了一個必需品,更成為了一個競爭優勢。因為眾多公司圍繞軟體而競爭,軟體開發相關的事宜顯得越發重要。開發軟體的人——軟體工程師正顯得越發重要。
“對於知識,要求知若渴;對於自己,要虛懷若谷。”優秀的軟體工程師一定是在軟體開發的道路上前行者。自學是其成長的一個重要手段,在自學的過程中,我們是可以通過考試的方式來收斂思緒,督促自己學習,從而提高自己的基本素質。誠然,原則和模式是軟體工程質量的基石。但技術是工具, 是為人服務的,而不是相反的。我們不能為了迎合某種技術而束手束腳,讓自己特別難受。與此同時,要讓自己的能力發揮到極致,良好的心境是必須要有的,因為軟體工程中的一個核心因素是人的因素。
誠然,在軟體開發過程中,我們不僅要將自身內功修煉好,更應該 “用產品說話”。那麼,在這個過程中,我們該如何保證開發的質量呢?在開發的過程中如何專注於自己擅長的事情呢?在本文中,我們將探討軟體開發過程中關於角色、重構和質量的問題。
角色
我們經常提一句話:革命工作只有分工不同,沒有高低貴賤之分。這裡的分工其實就是角色的劃分。角色劃分是為了讓個體承擔的工作量最小化,從而可以把我們從繁文縟節中解放出來,專注於自己擅長的事情。那麼,在軟體工程當中,這樣的理念應該如何貫徹呢?
軟體工作裡面的髒活兒、累活兒一般是指技術老舊而不得不維護的一些工作。還有一些重複性強的工作也被稱為髒活兒、累活兒。
對於這種活兒,一般工程師都想推脫掉。主要原因是認為做這類活兒技術提高的空間很小,再加上技術陳舊,這些技巧學會了以後也用不上,同時也比較枯燥。
這類工作的工程師一般是指派的。需要對相關的工程師進行一些必要的技術培訓或者直接招收懂得相關技術的工程師加入工作。
效率和價值主要體現在幫助客戶解決現有軟體系統中的問題,或者新增新的功能。客戶可能很少願意購買一套嶄新的系統,因為價格相對比較高,所以他們寧願少花點錢去做些修修補補的工作,能夠解決燃眉之急就可以了。
運維工作的價值是把已經開發出來的元件和系統整合起來統一的工作。是推出面向使用者的軟體系統產品的重要一步。我不認為是邊角料的活兒。
運維相關的工作越簡潔越清晰越好。這部分相關的文件一般是read me markdown的形式存放在軟體系統的repo中。通過檢視這些文件,應該可以自行部署整套系統。
系統部署一般會分幾種類別,開發模式,qa模式,staging模式和生產模式。
業界對於軟體開發過程中的角色有不同的理解和看法。筆者觀點如下:
- 1.專案產品經理負責業務需求的處理,負責跟客戶與開發團隊打交道。
- 2.專案開發組長一定是全棧,需要統籌規劃,與專案經理一起探討需求分析,與開發組成員一起探討開發設計,任務分配與開發實現。
- 3.前端工程師負責網路頁面程式開發,手機端應用開發,桌面端應用開發等等。
- 4.後端工程師負責API設計與開發, 資料分析處理與訊息推送。
- 5.運維工程師負責部署環境的搭建與看護。
- 6.針對具體的業務需求,還會有更細分的角色類別,比如說大資料工程師,演算法工程師,AI工程師,機器學習工程,深度學習工程師, 中介軟體工程師。
- 7.測試工程師負責系統整合後的業務需求案例測試。這一部分的輸入跟開發團隊的輸入是一樣的,都是使用者的需求。輸出則是需求案例對應的測試報告。而開發團隊的輸出就是整個軟體系統。
重構
為什麼我們需要對程式碼和設計進行重構?主要是因為我們發現了更好的做法,如效率更高,更容易維護等等。
簡單的程式碼重構我們都比較熟悉,比如說你通過工具就可以做一些整理。
一般來說,重構是為了解決複雜度的問題。
現在比較頭疼的一個話題就是對老產品的重構,一些老產品涉及到上千萬行,上億行的程式碼。
關於老產品整改的問題。如果只是縫縫補補的話,可能起不到化繁為簡的目的。其實做類似這種工作的話,有一個比較可行的方案。就是把現有的產品當做一個成型系統也就是現有執行的產品,不要做大的改動,頂多就是修改bug。
然後以這些成型的系統為基準,去寫新的系統。相當於參照一個大的白盒就寫一個小的白盒,這樣新的小的白盒質量上肯定比大的白盒效能上要有優勢。
這樣子按部就班去做的話,就會比較靠譜。
有朋友會說上面的做法是重寫,字面意義上沒錯的。
實際上不矛盾。區別就是重構的方式應該從下往上還是從上往下。比如說我們現在大部分的重構都理解為從下往上來做。也就是感覺這個檔案裡頭有壞程式碼的味道,然後就改這個檔案,這樣做是沒有問題的。前提是這項工作的上下文比較單純,無技術債務。
很多情況不是如此幸運的,比如現在有些人遇到的問題,就是發現上下文不是很清晰,這個程式碼為什麼要這麼寫?為什麼一個檔案有1萬行或者3萬行,這個來龍去脈不是很清楚。
這個時候可能就需要從整個子模組來進行一個自上而下的分析。梳理出這個子模組的功能需求是怎樣的,需要有多少個公共介面?內部公共介面的實現方式是不是應該像目前這樣的?
一個檔案能夠寫成1萬行或者3萬行,肯定是有一定歷史原因的,絕大程度是由於全域性把握的程式設計能力不夠造成的。
像這種情況,如果從這個檔案本身去做重構的話,難度非常之大,但是如果從上往下,從模組的整個設計角度來做重構的話,可能就容易一些。
對於這樣的龐然大物,最好的辦法就是分而治之。首先要確定系統的功能邏輯點,針對這些邏輯點,要編排好對應的檢測點,也就是說等我們完成了重構以後,我們得確保我們的重構是沒有問題的,這些檢測點就是做這個的,我們可以理解成整合類的測試。
這些整合類的測試一定要確保可以在當前未重構之前的系統上正常執行。
有了這個設施以後,我們就可以開展我們的重構工作。重構的方法有很多,比如採用比較好的工具,函式和變數的命名改變,呼叫方式的改變等等。這些是在現有程式碼的基礎上進行的重構。這裡我們重點說一下重寫的方式來實現重構。所謂重寫呢,就是另外開闢一套程式碼底座。甚至可以選用不同的程式語言。
這種情況下重構首先要重用已有的業務邏輯,實現針對業務邏輯整合測試100%的通過率。
具體不管採用哪種方式都要一個模組一個模組的進行推進。驗證完成一個是一個,千萬不能急於求成,試圖一次性的把某些問題搞定。如果出現很多次失敗,有可能會消磨掉你的自信心。所以一定要一點一點的往前推進,始終是在進步當中。採用了這種方式以後,不管當前的系統有多麼的龐大,你只要堅持做下去,就一定能夠把重構工作徹底完成。
這個時候需要做的具體步驟可以參考如下:
1. 根據功能需求定義公共介面。
2. 根據公共介面寫出測試案例程式碼。
3. 這個時候可以按照測試驅動開發的理念去填充程式碼。
4. 程式碼可以從現有的程式碼中抽取出來。
5. 在抽取的過程中進行整理重構。
這樣,這個子模組完成以後,就可以嘗試去替代現有的子模組,看看能不能在整個系統中安全的執行。
對於整個系統來說,我們又可以分成很多個子模組。然後又可以對各個子模組各個擊破,最終完成對整個系統的重構。
如果一開始對整個系統進行重構的話,也是可以從自上而下的角度來看的。
比如說開始的時候先把所有的子模組看成一些佔位符,假定他們已經完成他們的介面了。那對於整個系統來說,它本身就是一個子模組,屬於提綱挈領的那個模組。
這個過程,從字面意義上可以理解成重寫,實際上,它也是一個重構的過程,因為我們肯定會重用這個系統本身的一些現有程式碼和現有的邏輯。
上面我們是假定系統在已經完成的情況下進行的重構,其實重構可以貫穿於軟體開發的始終。軟體開發的首要目標是實現業務邏輯,能夠解決客戶的問題。這個目標實現以後,我們就要追求程式碼的乾淨度,複雜度能夠降到最小,當前的技術能夠用到最先進。
所以只要有機會,我們都應該對程式碼和設計進行重構。
質量
質量直接關係到客戶是否對我們的產品滿意。那我們應該如何保證軟體開發的質量呢?
要遵循整個開發團隊的共識才能保證質量。共識是一個可大可小的術語,大到理想、哲學、人生觀;小到軟體設計原則,設計模式,程式碼風格。如果是打造一個團隊那就是長期的目標,共識一定要從大的方向上入手。如果僅僅為了開發一個專案,共識可以從具體的細節著手。
軟體質量的保證,需要整個團隊形成共識,大家都遵循這個共識。這個共識體現在開發原則,設計模式和程式碼上,具體表現在架構程式碼和模板程式碼上,在專案最初的開發階段,開發速度一定要慢,就是為了經過反覆的推敲夯實,把程式碼的共識部分建立起來。
風格上的目標是,不管這個團隊有多少個人,寫出來的程式碼,就像一個人的程式碼一樣,風格是一致的。
程式碼的質量也體現在複雜度上。複雜度的目標是,在目前的技術條件下,當前的程式碼的複雜度應該為最低。
另一個軟體高質量的重要指標是程式碼的白盒可測性。測試的框架應該在專案開始階段搭起來。等部分程式碼成型的時候,逐步的新增必要的測試案例。測試案例的選取可以按照環形複雜度的計算方法來確定,也可以根據整合測試對應的使用者需求來確定。
接下來進一步細說一下軟體開發中的測試。與程式碼相關的測試,一般有單元測試,整合測試和系統級的測試。
單元測試,一般被認為非常繁瑣。單元測試的繁瑣主要體現在測試案例的選取上, 如果使用全覆蓋方式來選取測試案例的話,會產生大量的測試程式碼,以後維護起來也是一個負擔。如果採用環形複雜度來選取測試案例的話,會產生適量的測試程式碼,但是環形複雜度的計算也是一個很大的時間開銷。
整合測試跟客戶的實際業務需求相關。在這個過程中需要理清介面的輸入與輸出,以及執行路徑,然後據此來設計測試案例,寫出測試案例程式碼。
開發人員一般不會拒絕寫整合測試。因為她帶來的好處是實實在在的,會極大的提高你的開發效率和除錯效率。尤其是對於無介面的程式介面尤為重要。
系統級測試是大系統中子系統之間的整合測試。這個主要包含兩個方面:
一個方面是有介面的自動化測試,通過這樣的測試架構來模擬人類使用者的使用過程,同時增加一些隨機性的行為,試圖能夠找出系統的一些漏洞。
另一種是無介面的測試,體現在多個服務系統之間的呼叫上或者類似瀏覽器自動化框架的使用上。
一套完整的測試系統,可以幫助工程師提高開發效率,減少以後系統維護和重構的成本。
從測試的緊迫性上來說,整合測試最為必要,系統間的測試有時候使用手工測試通過一些測試工具來代替。單元測試可以有很廣闊的討論空間,這部分要具體問題具體分析。
如果只是為了應付檢查而寫測試程式碼,是沒有意義的。
如果測試程式碼沒有起到應有的價值,寫測試程式碼也是沒有意義的。
工程師是軟體高質量的主要執行者。專案組長,架構師和開發經理是軟體高質量的護航者和守護者。
所以不能放任讓工程師從下而上的去保證軟體質量,這個要求對工程師來說過高了。
小結
最後提一下工程師文化和主人翁精神。對於工程師文化的內涵,我認為包含如下幾點:
- (1)工匠精神,對於所做的事情有著精雕細琢的熱忱。
- (2)試錯文化,勇於嘗試,願意做第一個吃螃蟹的人。
- (3)自律,這個自律是指“吾日三省吾身”。不斷的自我糾錯反省提高。
對於主人翁精神,不管做什麼工作,只要想充分發揮自己的能力,真正的做些事情,不管級別如何,薪水多寡,簡單地說,就是時刻把所做的事情當作自己的事情來做。否則的話,時刻斤斤計較,我們做事情的時候就無法全力以赴。
如果抱有患得患失的心態,我們的工作效率就會下降。久而久之,不僅賺不到想賺的“大錢”,也會阻礙自己能力和心境的提高,可謂是撿了芝麻,丟了西瓜。時間是寶貴的,真的不容浪費。
對於主人翁精神的一些具體表象很多,諸如:從來不說“這不是我的事”;做事情不為了短期利益而犧牲長期利益;等等。
通過本文,筆者梳理了一下從事軟體工作二十多年來的心得體會,希望能給大家帶來一些有意義的啟示。