写代码之前应该做的几件事
作者:borisyang,騰訊 WXG 應用開發工程師
作為程序員,剛剛開始學會寫代碼,常常是接過需求就開始擼代碼。有時候發現,寫完代碼,需求變了。更多時候,覺得寫業務代碼枯燥無聊,沒有技術含量。另外一邊的事實卻是,項目里面研發人數變多了,項目的質量缺卻變低了,多人開發也不過是一個個單打獨斗的組合而已。
1 研發環境日益成熟
經歷過 PC 互聯網的不斷深入發展,移動互聯網的蓬勃生長,互聯網進入了成熟繁榮期,研發環境也發生了巨大變化;從原來一個人,一把鍵盤,寫完代碼就上線,變成了更加規范的研發體系和更多人參與的共同協作。
研發流程不斷加速
為了盡可能提高需求交付速度,跟上市場的變化,我們通過不斷提搞軟件交付的速度,盡可能的,從需求,編碼實現,測試,發布的流程中不斷優化,利用 CICD,加速迭代。
多人協作無處不在
現在的軟件開發團隊,即使再小,也有 2-3 人一起研發,更別提測試,運維,運營,產品人員。一方面是軟件產品的競爭日趨激烈,需求日益復雜,堆砌人力成了必然;另外一方面是專業性的要求,精密的行業自然要求精細化的職業劃分。
2 困局
研發流程的速度提上去了,團隊的人也變多了,但是,需求變更依舊讓廣大研發同學感到痛苦,項目質量還在日益變差。
需求變更之痛
需求變更的痛苦為難了廣大研發同學,前腳剛為了優化性能,采用了 kv 存儲,后腳需求就變成了要支持模糊查詢;這是一種典型的架構設計不合理,導致業務需求的實現方式受限。
更令人痛苦的,還有產品需求變動多,今天簡單實現下,上線看看效果,明天用戶脾氣很大提了個訴求,再加一個功能上線,產品功能變成補丁加補丁。一方面是研發同學渴望一個完整又嚴謹的需求,提完需求進入研發階段就不許改;另一方面是產品同學受到各方面的壓力,只希望先把主要問題解決下,細枝末節以后再說。
項目質量變差
項目質量變差,一部分歸功于補丁代碼的產生,迫于時間受限,先上一個補丁,卻打開了破窗的先鋒,下一次,下一個同學就更敢于加補丁代碼。一個個臨時的 if else 不斷堆砌,最終導致了整個項目的代碼腐爛。我曾經維護過一個代碼片段,超過 20 個 if else,中間還有些過時的錯誤注釋夾雜其中,維護起來令人苦不堪言。
項目代碼腐爛的另外一個原因是多人協作,團隊的人越多,代碼反而變得越爛似乎成為了趨勢;為什么多人協作沒有提高代碼質量呢?一方面,多人協作實際上只是分攤的需求實現而已,大多數需求實現的分配中,反而盡可能將協作變少,避免實現受阻。另外一方面是,不同人的代碼模塊,設計意圖和代碼風格也截然不同。維護前人代碼,如果沒有全局視角,了解設計意圖,也只能是往里面加補丁代碼了。
項目代碼腐爛容易導致程序員出現錯覺,一是業務代碼沒什么料在里面,不如搞基礎建設;二是業務需求不可能完整又嚴謹,最終也會變來變去的,最終質量低下的鍋,一大半要給提需求的人。
3 怎么辦
在寫代碼之前要進行設計和建模。相比歷史短暫的 IT 行業,很多工業,建筑行業的精密性,都離不開前期的設計,在分析設計之后,按照圖紙規劃施工,寫代碼也應當如此。
設計建模的有效性源于,一,重新回到業務的跑道,跟業務一致;二,設計建模才能讓協作真實有效;
為什么研發實現需求跟業務一致很重要呢?研發和業務需求的摩擦,本質是研發實現跟實際需求不一致,無論是研發走偏了,沒有理解需求,還是需求本身不能滿足涉眾的利益,都會使得最終上線的功能需要回爐重造,折磨項目組的成員。業務項目,需求很重要,是整個項目質量的源頭,源頭的問題不處理好,會一直發散擴大,問題傳遞到尾部,甚至到了產品上線,對整體造成的損耗越大。從設計的語言上看,設計的層次有所不同,不僅僅有代碼細節上的設計,也有業務上高層次的設計,高層次的設計是用業務的術語去表達,最貼近業務實際情況,也能幫助研發同學發現業務中不合理的點。
設計建模為何能讓協作真實有效?我早先體驗的協作流程,無非就是各自工作在自己的領域內部,彼此盡量減少要協作的內容,避免過多阻塞。研發側的協作,因為缺乏設計,不好分工,另外一方面,多人寫同一個模塊,也會引發沖突,所以更多將協作放在在 code review 上。但 code review 作用范圍也有限,一方面,review 成本較高,逐行閱讀代碼來厘清設計對代碼質量要求很高,另一方面,review 時間節點往往發生較晚,臨近發布的時候,調整設計也不大可能。進行設計建模能夠讓協作變得有效,一方面,設計建模前期是溝通和信息對齊,將協作的內容提前,一方面,采用合適的圖形化工具,review 的成本是相對較低的。
4 怎么設計和建模
設計和建模分為好幾個部分
業務建模,關注業務,不關注具體的實現
系統建模,關注所建設系統的邊界,找準在業務中的系統的職責和約束
分析與設計,定位核心領域,找到實際的類,厘清類的職責和類之間的關系,通過設計使得代碼抽象復用
業務建模
總體上來說,業務建模主要聚焦于分析涉眾利益,厘清業務流程。從工具上來說,主要是用例圖,流程圖;從內容上來說,主要是找人(利益涉眾,系統執行者),找業務實體(其余系統,相關的重要對象)。
分析涉眾利益
分析涉眾利益之前,需要找到涉眾,一般要經歷以下步驟:
找到軟件產品的愿景,愿景表達了軟件產品帶來的核心意義
找到利益相關的的涉眾和其利益訴求
表格是一個很好的表達方式,我負責的一個商戶從第三方商城采購刷臉設備,由倉配系統配送設備的業務,可以表達如下:
愿景:將設備更多更快且準確無誤成本低地賣給商戶。
| 物料組老板 | 在準確無誤的情形下,更多更快成本低地將設備賣給商戶 |
| 設備渠道商 | 準確無誤且快速地配送設備給商戶 |
| 商戶 | 更快地獲得自己購買的設備 |
| 物料運營 | 更加準確的配送設備給商戶 |
一般而言,涉眾的利益是否被滿足直接決定了軟件產品的成功與否。而分析涉眾利益需要進行詳細的調研,研發同學可以根據產品的調研看到對應的涉眾,及其利益。
業務用例圖
知道了涉眾的利益之后,就要分析業務流程,并對現有的流程進行改進。軟件產品沒誕生之前,業務是如何被處理的,找到原來業務的處理方式則可以梳理出業務用例。
筆者負責的一個業務是向購買設備的商戶配送設備,對于業務團隊的實際業務來說,用戶購買設備有業務價值,業務用例如下:
物流公司和設備渠道商都是輔助購買設備的執行者,因此放到右邊。值得注意的是,業務用例要體現價值,雖然在實際業務流程中,商戶同時做了很多事情,比如簽收設備,但簽收設備不能反映業務價值,故而只有一個購買設備的用例。
業務流程分析
了解了涉眾的利益并且畫出用例之后,需要分析業務流程,找到我們軟件系統能夠改進的流程片段;完整的業務流程圖可能很龐大,需要關注的是其中最有可能影響涉眾利益的流程片段,如下為購買設備業務流程中配送設備的流程片段,該片段不大符合涉眾利益;
配送設備的業務流程可以看到,在原來的業務流程中,配送設備的流程是在全部業務流程中較為繁重,人肉工作量大的流程片段,不符合涉眾利益;
收集商城訂單信息不及時,導致配送不及時,影響涉眾的利益
人作為節點參與處理,成本高,耗時長,也是不符合涉眾利益的
所以很明顯,我們的系統需要改進流程,替代人的部分工作
新的流程有效地滿足了涉眾“將設備更多更快且準確無誤成本低地賣給商戶”的利益訴求。
業務序列圖中,每一個箭頭代表的是職責,在業務序列圖中,需要考慮的是職責的層次問題,過于小的職責放入流程圖中,會導致信息過載,忽略最有價值的職責。在上圖中,運營核對設備的配送信息是一個很重要的職責,在原來的需求中體現比較弱,研發同學可以借助業務流程的分析來分析需求中不合理的地方,完善需求,避免后期的改動,前期越是完善,后期的損失成本越低。
業務流程分析是一件很復雜的事情,研發同學可以利用需求中的信息,同時加上自己跟涉眾的日常溝通和調研,把握核心的涉眾利益,業務用例和業務流程,就可以解決大部分在需求上的理解偏差問題。
系統建模
系統建模關注的是系統與外部的邊界和系統自身的職責
系統建模需要做的事情
畫出系統用例
寫出用例規約
系統用例圖
系統用例圖是業務流程中,系統執行者與系統發生的有價值的交互。系統執行者可以是人,可以是外部系統,甚至可以是時間。系統用例要體現系統的價值,系統會做很多事情來實現業務價值,我們應當關注業務價值。有些是低層次的職責,沒有體系具體價值,如:“獲取商城訂單信息”是為了配送訂單中的設備而發生,應當關注“配送設備”。
如下是倉配系統的系統用例圖:
系統用例規約
有了業務流程圖和系統用例圖,需要根據進一步細化系統邊界上的約束,保證系統的穩定性。系統執行者與系統的交互細化了詳細的約束,系統的穩定性才能提高,如果沒有仔細列出約束,有可能會忽略一些邊界條件,導致系統的故障;如:倉配系統不考慮來自第三方商城訂單要配送的設備數量限制,則會因為第三方商城出現的錯誤,導致資產損失。
系統約束來源于系統用例,根據業務的規則,詳細地描述了業務流程中的基本路徑,擴展路徑和約束。
配送設備:
系統每小時向第三方商城查詢待配送的訂單
系統驗證訂單是否已經配送
系統驗證訂單要配送的 SKU 是否合法
驗證訂單中配送的設備數量是否超過最大限制 1000 筆
系統向物流系統請求給訂單中的用戶配送訂單中的設備
因為步驟 2,3,4 還有其余可能的路徑,稱之為擴展路徑。
訂單已經配送
系統忽略該訂單
這里的約束不是告訴研發同學如何實現功能,這里的約束是業務規則,厘清系統執行者與系統之間的邊界,以及邊界上的約束。設計評審的時候,可以關注關鍵路徑上的安全規則是否到位,這么做對提高系統的安全穩定有極大的幫助。
類的分析與設計
這可能是大多數研發同學比較熟悉的領域,經典的設計模式,類之間的關系,泛化,組合等。但是類從哪里來呢?是從需求之中憑空產生?又或者突然靈光一閃,有了類的雛形?對類的進行設計與分析之前,需要做的是找到他
識別類
經歷過業務流程,系統建模,我們終于來到了系統里面,來尋找類。我們所熟知的類有三種,邊界類,控制類和實體類。邊界類是外部系統在系統內部的映射,借由邊界類,系統和外部系統交互。所以一些接口請求,輸入輸出都屬于邊界類的職責。在倉配系統中,商城就是一個邊界類,將外部系統轉移到內部系統來,屏蔽了接口請求相關的細節。控制類往往是體現用例流程,一般而言,一個用例就是一個控制類。實體類則是系統的核心,實體類良好設計能夠提高系統的復用程度,減低系統的復雜性。
找實體名詞
知道了有這三個類還是不足夠我們識別具體的類,識別具體的類需要去業務流程,系統流程,系統規約中經常出現的名詞。在上面的流程圖中,訂單,商城,設備,物流,用戶是反復出現的名稱,說明這些類必然存在。
找到這些業務實體,就是找到類的第一步。
找到屬性
類的屬性也不是憑空產生的,需要對業務實現有價值,用戶不一定有姓名,在物流上下文中,用戶的屬性就只有 ID,收貨地址。找到那些對于系統實現必不可少的屬性,放到正確的類中。如倉配系統中的訂單,包含訂單號,商品,用戶。用戶則有收件地址。
在倉配系統中,用戶只有一個地址,在商城的系統中,用戶則有多個地址,充分說明了,不同的上下文中,類的屬性不是固定的。
找職責
從業務規則和約束中,可以找到一些實體應當有的職責,如訂單,就有驗證合法性的職責。
有時候,有些對象看起來信息很富裕,但是卻沒有什么職責,說明他是一個值對象,像上圖中的用戶和收件地址,我們不關心他的 id,只關心收件地址,收件地址就代表著這個用戶。
狀態機
找到類和對應的職責,對于一些主要的實體類,還需要設計出他的狀態機,清晰的狀態機能有效地厘清系統內的一些事件和狀態,增強系統整體的健壯性。
倉配中的訂單,從用戶購買的待發貨狀態,到通知物流發貨,再到實際發貨,物流簽收有一些列狀態的演變。
5 總結
在多人協作的項目中,不斷提高項目質量,除了依靠代碼之外的工程手段,還要依靠設計建模。
從具體實踐的角度來看,設計建模在不同的環境中,調整具體的流程和側重具體的節點,也能夠實現快速高效,不會導致繁瑣和低效能的現象。
在寫代碼之前應該做的幾件事情:
找準涉眾利益(越是新的項目,越是要分析好,如果是小功能的迭代,則可以從產品需求文檔中尋找);
畫出原來的業務流程圖,和改進之后的業務流程圖(業務流程圖是對業務理解是有極大幫助,在絕大部分場景中都不應該省略);
分析系統的職責邊界,畫出系統用例(往系統中添加較小的功能可以考慮不畫出來,心中有數即可);
寫出具體的用例路徑和約束(對系統安全和穩定越是關注,越應該去寫出具體路徑和約束);
識別主要的類,屬性和職責,畫出重要實體的狀態機(簡單功能則直接用代碼來表達即可)。
想和一群喜歡折騰與思考的同學一起提升嗎?來微信支付吧,這里鼓勵思想的碰撞與應用,這里有海量的數據,有令人激動的業務場景,有各有所長的優秀伙伴,快來一起玩耍吧。
微信支付歡迎你
參考文獻:
《軟件方法》
《軟件建模與設計》
總結
以上是生活随笔為你收集整理的写代码之前应该做的几件事的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信「看一看」 推荐排序技术揭秘
- 下一篇: 大牛书单 | 腾讯运维大咖陪你过724