
2020 年是我正式成為軟件工程師的第一年,也是我在舊金山度過的第一年。受疫情的影響,我沒有太多機會去探索這座新城市,只能呆在家里練習烘培技術和刷劇。然而,事情也有好的一面,我有大量的時間宅在家里做自己的項目。這一年里,我學習了很多有關軟件工程的最佳實踐,在本文中,我將介紹我學習到的最有價值的20條準則。
開發人員需要花費大量的時間閱讀代碼,甚至超過了編寫代碼的時間。這里我所說的閱讀包括以下工作:調試代碼、檢查他人提交的代碼、學習新的代碼庫等等。因此,你應該確保自己的代碼便于閱讀,即便有的時候你需要更長的命名、編寫更多代碼,以及舍棄自己的“小聰明”。
舉個例子,雖然變量名 timeInMillis 比 time 更長,你需要輸入的字符也更多,但是開發人員無需查看其他代碼就能明白這個變量計算的是哪種時間。
再舉一個例子,網上有很多一行代碼的解決方案。例如,如下判斷回文數的寫法非常聰明(注:回文數指的是像 14641 這樣“對稱”的數,即:將這個數的數字按相反的順序重新排列后,所得到的數和原來的數一樣):
def isPalindrome(self, x: int) -> bool:a=list(str(x))return a==a[::-1]
但是,非常難以理解。一行代碼的解決方案很有挑戰性,不建議在多人共同維護的代碼庫中采用這種寫法。
只有當重構幫助你和團隊成員節省的時間超過重構花費的時間,才值得投入。你應該將精力集中到頻繁閱讀和編寫的代碼上。
你可以考慮,將不緊急的重構分配給新來的團隊成員練手,這樣他們不但有機會學習,同時也能貢獻價值。
有時,從業務的角度出發,盡快提供有價值的功能可以獲取更大利益,比如趕在競爭對手發布類似的功能之前,即使這個時候的功能還不夠完美也沒關系,只要你可以建立計劃,趕在債臺高筑,被“利息”壓得透不過氣來之前,及時地改善代碼。如果技術負債的積累速度超過你的償還能力,那么就會出現問題,代碼庫的處理難度就會越來越大。
例如,在時間緊迫的情況下,在完成測試之前就發布某項功能也可能是正確的業務決策,但是事后你需要立即補上測試。如果你拖延測試,很快這些未測試的代碼之上就會出現新的代碼,未經測試就發布的功能也會相繼出現,那么償還這部分技術負債的難度就會越來越大,很難再還給團隊一個維護良好的代碼庫。
團隊成員會假定你的代碼遵循常見的慣例,所以你不應該偏離這些慣例,不要給他們制造驚喜。
例如,如果你編寫了一個函數 isButtonEnabled(),那么團隊成員肯定會假定這個函數是在檢查某個按鈕,它會返回一個布爾值,因為絕大多數的這類函數名稱都以“is-”開頭。如果你的函數還做了其他處理,那么就應該在名稱中澄清。
例如,for 循環中可以使用 i 和 j 之類的變量名,但是全局常量的名稱應該更加精準地表達它的意圖。
一般,我們常說重復三次以上的代碼都應該寫成函數,但我還想再加兩點應該寫成函數的情況:1)當需要添加注釋解釋這段代碼的用途的時候;2)當嵌套超過3層的時候。
舉個例子,假設我編寫了下列UI函數:
fun setupViews() {// set up textViewtextView.isVisible = …textView.text = ……more textView setup…// set up imageViewimageView.image = …imageView.backgroundColor = ……more imageView setup…}
我們應該將相應的代碼分別放入另外兩個函數 setupTextView() 和 setupImageView(),即便它們不包含重復代碼。通過這種方式編寫出來的代碼,本身就可以作為文檔,而且如果有人需要修改或調試 imageView,他可以直接去 setupImageView(),而無需閱讀所有的代碼。
另一個常見的情況是關于函數的最大代碼行數,這個值的設置非常隨意,通常在5~100的范圍內。我個人認為基本的標準是:閱讀函數的時候不需要翻頁。
DRY(Don't repeat yourself,不要重復你自己)是一個眾所周知的軟件工程原則。一般,最常見的重復就是完全相同的代碼,但是也有一些重復的形式并沒有那么明顯,例如實現的重復。
舉個例子,對于如下定義的類:
class TreeNode {val value: Stringvar children: List<TreeNode>val isLeaf: Booleanfun addChild(node: TreeNode) {children.add(node)isLeaf = false}fun removeChild(node: TreeNode) {children.remove(node)if (children.isEmpty()) isLeaf = true}}
其實,你不需要在每次 child 更新的時候設置 isLeaf, 你可以添加 fun isLeaf() = children.isEmpty(),如此一來,在更新這個類的時候,你就無需檢查 isLeaf 是否被更新了。
在實現某個功能之前,首先你應該先檢查一下代碼庫中是否已有現成的實現。
例如,你需要處理時間,常量 SECONDS_PER_MINUTE 可能已經存在了,你可以直接重用,而不應該在同一個代碼庫中多次定義這個常量。
一套統一的開發指南可以方便團隊成員理解彼此的代碼,也可以方便新來的成員。通常,實際的規則并不重要,重要的是你需要確保這些規則被貫徹執行了。例如,我曾見過一些 Kotlin,所有包含擴展函數的文件名都以“-Ext”結尾,而其他文件則使用“-s”結尾。實際的選擇并不重要,重要的是所有人的選擇必須統一,只有這樣程序員才知道哪里能找到 Foo 的擴展函數,是在 FooExt.kt 中還是在 Foos.kt 中?
如果你在項目中使用了lint工具,而且你經常手動調整格式,或者在代碼審核時經常有人提出格式方面的建議,那么就應該考慮一下增加一條新的lint規則。
現代 IDE(比如Android Studio 和 VSCode)非常強大。你應該學習如何使用 IDE 的各種小工具(比如調試器),以及鍵盤快捷鍵,雖然這需要投入一定的時間,但從長遠打算來看能夠為你節省很多時間。
你應該自定義設置和鍵盤快捷鍵,優化你的工作流程。例如,JetBrains IDE 默認不提供“Split editor tab”的快捷鍵(你必須點擊Window → Editor Tabs → Split Vertically),但是我添加了一個自定義的快捷鍵,因為我經常使用。
理想情況下,代碼應該不言自明,不需要添加注釋。程序員在修改代碼的時候,經常忽略更新注釋,時間久了,注釋就會不準確,與實際的代碼大相徑庭。在你打算寫注釋,解釋代碼的功能時,不妨考慮一下重構代碼,讓代碼不言自明。
然而,僅靠代碼自身還不足以解釋為什么你選擇這種方式。注釋可以提供上下文,比如幫助你做出決策的產品需求、系統限制或出于效率的考慮。
在編寫生產代碼的時候,你可能需要花點時間計劃代碼,確保在功能發布之前達到良好的品質,但是程序員通常都會忽視測試代碼,只要能正常運行就可以了。然而,測試代碼也需要維護,如果這些代碼很難理解,那么就會增加維護的負擔。
部分問題是測試代碼一般都不需要經過嚴格的審核。大家會花費大量時間審核生產代碼,卻覺得測試代碼沒這個必要,因為畢竟已經通過了測試。
幾個月以前,我發現了Junit的參數化測試,這種方法幫助我編寫了更多徹底的測試。
在常規單元測試中,通常每個輸入只有一個測試函數。最后會導致很多函數都有重復的代碼,而且很容易漏掉一些輸入。表格驅動測試有一個單獨的測試函數,還有一個表格囊括了所有可能的輸入以及預想的輸出,只需要一個測試函數,就可以測試所有輸入。
每個庫都有預發布的版本,很有可能會破壞已有的功能。
在新發布的庫中,易于測試可能是次要考慮因素,如果你想在大型項目中采用新庫,事先必須驗證這些庫是否能夠通過你的測試代碼,并兼容生產代碼。
在社區廣泛采納某個庫之前,遇到問題時,很難找到資源。而且可能這個庫永遠也不會被廣泛采納,項目本身也會被維護人員遺忘。
對于有些庫,看似每個人都在使用,但是真正的項目中采用了這些庫嗎?還是說只是出現在演示程序中?
注意團隊成員使用的資源和工具,如果將來再遇到類似的問題,你能夠更好地武裝自己,靠自己的力量解決問題。發現新的資源和工具都很有價值,比如文檔資源、Git命令、鍵盤快捷鍵等。
除了回應審核意見之外,你應該考慮重構或添加注釋來澄清。這樣可以確保將來其他人閱讀這段代碼的時候,不會遇到同樣的困惑。
當你在理解某段代碼時遇到困難,則應該仔細閱讀代碼的審核意見。從代碼的審核意見可以看出,同時間內還有哪些代碼發生了變化,因此閱讀這些審核意見很有價值,而且其中還可能包含代碼背后的決策說明。
如果你正在實現的某個功能與某個已有的功能非常相似,那么閱讀相似功能的代碼審核意見,可以幫助你規劃自己的實現。例如,如果我想添加某個Android 功能,但iOS或Web已有這個功能,則看看其他平臺的實現方法會有很有幫助性。
上大學的時候,除了課堂上的學習之外,你的知識主要來自自己的業余項目,在找工作的時候,這些經驗會幫助你脫穎而出。但是,在之后的工作中,如果你想跳槽,則與自己的業余項目相比,實際工作項目的經驗更能贏得面試官的青睞。
在業余項目中,你可以做自己喜歡做的事情,當然你可以繼續享受這些項目!但是,除此之外,還有很多其他的學習方式:閱讀博客、看演講、參加在線課程、聽播客等等。你可以找到自己最喜歡的方式,或者你也可以利用工作之外的時間發展其他興趣愛好。
任何人都可以通過互聯網發表技術博客文章。如果你打算通過某篇博客文章學習新技術,卻發現其中的內容不太合理,那么可能只是因為文章本身寫的不怎樣,你不必就此放棄,而是應該嘗試其他資源。
官方的資源和教程通常都是很好的切入點。會議演講以及公司的技術博客的質量一般也都比較高,因為這些資源都經過了嚴格的審查。
說到學習資源,以下是我常去的一些網站,本文提及的很多準則也正是來自這些資源:
Refactoring Guru:一個網站,介紹了如何編寫和重構整潔的代碼。
Clean Code:經典的軟件工程書籍。有些內容有點過時,而且還與Refactoring Guru有重疊,但是仍然值得一讀。
Martin Fowler’s website:作者撰寫了很多有關軟件開發的書籍,而且他的網站也有很多關于軟件架構與重構的信息。
Android Weekly newsletter:一份周刊,精選了很多技術文章、播客以及演講。僅限于Android,但是其他平臺也有類似的周刊。
Yelp Android school:科技演講GitHub存儲庫。有一半是Android為主,還有一半討論的是軟件工程。(本文轉自CSDN)
原文鏈接:https://medium.com/better-programming/20-software-engineering-guidelines-i-learned-in-2020-8106d03d953b


1.AIoT時代,計算機技術的新機遇與新挑戰
2.STM32F1和GD32F1有什么區別?
3.PCB元器件擺放十條小技巧,絕對有用!
4.英特爾回歸技術流,原CTO帕特·基辛格回來擔任CEO!
5.內嵌專業接口的RISC-V架構MCU,誰家有?
6.深度剖析C語言的main函數!

免責聲明:本文系網絡轉載,版權歸原作者所有。如涉及作品版權問題,請與我們聯系,我們將根據您提供的版權證明材料確認版權并支付稿酬或者刪除內容。