關(guān)于軟件開發(fā)的一些牢騷

寫在前面

我要寫得都是一些牢騷滿腹的東西。包含了我十年來覺得很不爽的東西,也有一些我覺得很不錯的觀點。寫代碼是個辛苦活,維護(hù)代碼更辛苦。有些時候為了趕時間會寫出低質(zhì)量的代碼,然后花大量的時間去還債。但是有些時候低質(zhì)量的代碼并不是由于時間的原因造成的。

客觀來講,低質(zhì)量的代碼可能是由于程序員對需求的了解不夠深入而引起的。大部分的軟件都是應(yīng)用于各行各業(yè)的,而程序員大部分又都是CS專業(yè)畢業(yè)的。拿醫(yī)療行業(yè)舉個例子,寫代碼的人和最終的使用者之間的差距,用“鴻溝”來形容都不為過。而且這種“鴻溝”基本上沒有彌補(bǔ)的可能性。程序員改了無數(shù)的BUG,可能都不知道軟件是在什么樣的環(huán)境中被什么樣的人所使用的。在沒有充分了解需求的情況下寫出高質(zhì)量代碼的可能性是有的——這需要一個能力非常強(qiáng),而且對于行業(yè)知識非常了解的人來帶領(lǐng)整個團(tuán)隊——,但是這種可能性很低。

主觀來講,在這個世界上壓根就沒有太多所謂的高質(zhì)量代碼。高質(zhì)量代碼的分布能遵循2/8原則就謝天謝地了。首先“高質(zhì)量”這三個字的含義都很模糊——對于不同的行業(yè),不同的時期,“高質(zhì)量”所指代的內(nèi)涵,以及內(nèi)涵的優(yōu)先級都是不一樣的。舉個例子,20世紀(jì)80年代的代碼,大約是以運行速度快和占用內(nèi)存小為“高質(zhì)量”的標(biāo)桿的。而到了本世紀(jì),硬件資源不那么稀缺了,在大部分的場景下,可讀性和可維護(hù)性要優(yōu)先于運行速度和空間耗費。即便對于同一個系統(tǒng),在不同的模塊間,代碼的要求也可能是不同的。對于DSP里運行的代碼,首要因素是速度快和結(jié)構(gòu)清晰,而上位機(jī)的代碼可讀性更重要。

啰嗦這么多只想說,寫好代碼是一件千難萬難的事情,是一個需要隨著時間而累積和修行的事情。只有扎實地做好每一步,才能寫出“高質(zhì)量”的代碼。

基本原則

十年開發(fā),大部分都是在修修補(bǔ)補(bǔ),根本沒有機(jī)會打造屬于自己的開發(fā)環(huán)境和開發(fā)模式。幾個月前從公司跳了出來,算是開始了一段創(chuàng)業(yè)歷程。這是我有生以來的第一次。以前我對創(chuàng)業(yè)是不屑的,因為在我的觀念里,好的技術(shù)全在大公司里,所以我前三年全部的經(jīng)歷都在琢磨如何提升自己,如何進(jìn)入大公司。在大公司里待了七年,修修補(bǔ)補(bǔ),挖坑排雷。這七年的提升不僅僅是技術(shù)上的提升,更重要的是心智和領(lǐng)導(dǎo)力的提升。當(dāng)你的思維進(jìn)入了正軌,大部分技術(shù)都只是時間而已。當(dāng)你見識得夠多,所有的眼花瞭亂其實都是萬變不離其蹤。我不能說所有的東西都是一樣的,但是解決問題的思路也就是那么有限的幾種。以前沒有實現(xiàn),并不是前人不夠聰明,而是現(xiàn)實世界的約束太強(qiáng)——巧婦難為無米之炊。因此,作為開發(fā)者,最理智的作法是從現(xiàn)有的技術(shù)里面,挑出我認(rèn)為最好的東西(有時候是隨機(jī)碰到的),組合使用它們,實現(xiàn)我的系統(tǒng)。

舉個簡單的例子,我選擇在開發(fā)中用Conan進(jìn)行二進(jìn)制包管理。其實這種類型的包管理工具一直都在我們身邊——Nuget就是一個很成熟的應(yīng)用。但是我為什么不選擇用Nuget呢?沒有什么特別的理由。我之前對于Nuget的使用體驗并不是特別好,無論是上傳還是下載都很費勁。正好在推上看到了Conan的宣傳,就下載來用用,發(fā)現(xiàn)不費勁,我要的功能它都提供了,所以就開始用起了Conan。

這樣的選型方式在我前七年的工作環(huán)境里確實有些隨意。大公司對于正式引入開發(fā)流程的任何工具和設(shè)備,都有嚴(yán)格的驗證流程需要遵守。并且要做出若干的表格進(jìn)行對比分析。這樣做有它的好處,但是對于創(chuàng)業(yè)公司未免就有點“殺雞焉用牛刀”的感覺。并且隨著整個業(yè)界水平的提升,同一種類型的工具在質(zhì)量上并不會有太大的差別。這也就是我敢于隨心選型的心理基礎(chǔ)。

總結(jié)一下我的基本原則只有兩點:

  • 適用于小型團(tuán)隊
  • 看眼緣

開發(fā)語言的選擇

十年之間斷斷續(xù)續(xù)接觸了很多編程語言:C++, C#, Go, JS, Scalar,等。其中C++是我吃飯的家伙,所以格外花得時間多一點。其它都是有需要的時候翻翻文檔,邊查邊寫。幸運的是,除了C++之外其它語言學(xué)起來都不是那么難。C++活了這么多年,都快成活化石了,雖然大家都覺得它很難搞,但是總還是有它的強(qiáng)項。

首先就是性能問題。我們所開發(fā)的系統(tǒng)是一個封閉的系統(tǒng),要給客提供軟件、硬件以及機(jī)械結(jié)構(gòu)的一整套東西。并且,封閉式的系統(tǒng)一般情況下不會升級硬件,網(wǎng)絡(luò)資源也很有限。因此,相較于開放式的開發(fā)環(huán)境(類似于網(wǎng)頁應(yīng)用或者一些桌面應(yīng)用),封閉系統(tǒng)的計算資源受到很大的制約,性能就成了一個非常重要的考量方面。

其次與已有的成熟系統(tǒng)有關(guān)。感謝開源社區(qū)的發(fā)展,以及全世界無數(shù)英才的無私貢獻(xiàn),現(xiàn)在已經(jīng)很少需要從無到有地開發(fā)一個項目了。大部分基礎(chǔ)性的工作在社區(qū)里都能找到。作為開發(fā)者所要做的事情,就是找到你需要的項目,再把這些項目做裁剪,改進(jìn)并膠合起來。除了開源社區(qū),你也總能找到一些商用軟件可以全部或者部分得解決你的問題。這些開源或者商業(yè)的軟件所使用的語言,一定程度上會決定項目的開發(fā)語言選擇。

這些原因綜合起來,讓我決定以C++作為主力的開發(fā)語言。

單元測試

十年C++的開發(fā)經(jīng)驗中,寫單元測試的經(jīng)歷少之又少,也只在我自己的業(yè)務(wù)項目里面會寫寫測試用例。在公司正式的開發(fā)過程中,從來沒有寫過單元測試。因為大家都很明白,給C++寫單元測試就是一個坑,尤其是給一個已經(jīng)跑了20年,并且從來沒有重構(gòu)過的系統(tǒng)寫單元測試,這個坑不是一般得大。對于這種老系統(tǒng),寫單元測試的可能性已經(jīng)幾乎為零(需要重構(gòu)幾乎所有的業(yè)務(wù)代碼才有可能寫出較大覆蓋率的測試用例),更不要說市場部門還在不停地壓縮開發(fā)時間。另外,這種老系統(tǒng)還有一個特點就是所有的開發(fā)人員被迫使用“open-close”原則。對于這種老系統(tǒng)已經(jīng)沒有人能夠完全理解(比深度學(xué)習(xí)訓(xùn)練出來的網(wǎng)絡(luò)還要神秘),所以最保險的方式就是加代碼。有些年輕人就是不信邪,但是碰過兩次壁之后就都學(xué)乖了,十年來從沒有過例外。

所以在系統(tǒng)開發(fā)的起初就要求必須給每個組件寫單元測試和系統(tǒng)測試。單元測試是對源代碼的測試,而系統(tǒng)測試是對組件的測試(系統(tǒng)測試可以是對單個組件的測試,也可能是對多個組件組合功能的測試)。在C++里組件一般是以shared library的形式出現(xiàn),也有可能是header only library。無論是哪種形式,原則上每一個體現(xiàn)具體功能的文件都應(yīng)該被測試到,即單元測試應(yīng)該直接將相關(guān)文件包含進(jìn)來,針對里面的代碼寫測試用例,而不是針對組件暴露的接口寫測試(這屬于系統(tǒng)測試)。比如有一個名字叫Foo的庫,庫里面有4個文件分別是FooA.h/cppFooB.h/cpp。在做單元測試的時候首先需要建立測試工程TestFoo,然后將Foo里的4個文件全部加到TestFoo工程里,然后分別針對4個文件里的代碼寫測試用例。然而實際上這樣的測試用例很難寫(有時候基本不可能,有時候則是代價太大)。前段時候用Boost.Asio寫了串口通信的庫,跟串口相關(guān)的功能就很難寫測試。另外googletest(我在項目里使用google test)也沒有很好地支持異步調(diào)用。

對于沒有反射支持的語言,單元測試都會是個頭疼的問題。很多測試代碼寫起來非常繁瑣,我甚至一度懷疑寫單元測試是不是一個正確的選擇。尤其是在寫Fake Object的時候,想要模擬一些與硬件異步通信相關(guān)的行為,經(jīng)常會被搞得焦頭爛額。但是一但單元測試寫出來了,這些測試用例就會跟著你的項目一起成長。在寫單元測試的過程當(dāng)中你會更加了解你自己的代碼,也更了解項目的需求,扎扎實實地寫出高質(zhì)量的代碼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容