爲啥程序會有bug?

若是這是第二次看到個人文章 ,歡迎點擊文末連接掃碼訂閱我我的的公衆號(跨界架構師)喲~  

每週五11:45 按時送達。固然了,也會時不時加個餐~
html

本文長度爲4818字,建議閱讀13分鐘。程序員

堅持原創,每一篇都是用心之做~windows


這是一篇半娛樂性的吐槽文章,權當給廣大技術人員解解悶:)。
微信


哈哈哈,而後我要開始講一個常常在發生的事實了。(程序員們可能會感到一些不適)架構

99.999999999%作技術的都會被問到或者被吐槽到:「你的程序怎麼又出bug了!」框架


反正,我做爲程序員的心裏世界是:如同一萬隻草泥馬飛奔而過,難以壓抑心裏的激動,每次都差點忍不住想說「你寫篇幾百字的做文還有錯別字呢,我碼個幾萬行的代碼還不容許出錯了?「elasticsearch

可能一樣是作技術的你此時在不斷點頭,哈哈。分佈式

可是這麼講畢竟也緩解不了矛盾,咱們仍是得擺事實講道理不是?工具

啥都不怕,就怕程序員有文化!單元測試

因此,Z哥想來帶你好好分析一下這個事情,當你再遇到這個狀況的時候,能夠拿這些觀點來反駁(不是作技術的也能夠了解下程序員的難處,誰沒個難處呢,多多包容)


什麼是Bug

任何一個「問題」的產生,自己是沒有好壞之分的,可是爲何會有的就不被care,甚至還會很喜歡,而有的會被吐槽呢?根本緣由是由於產生了利益損失。

好比年前拼多多出問題送了不少無門檻券。

做爲一個用戶,天然很喜歡,誇你誇到飛起,怎麼會吐槽你呢。可是做爲利益損失方,必然破口大罵,害我傾家蕩產!

因此,若是沒有產生利益損失,我想其餘人也不會來找你吐槽


可是「問題」就等於「bug」嗎?我認爲並非,「問題」不等於「 bug」

由於程序員的職責是什麼?拿造房子來比喻的話,我認爲最核心的工做真的和「搬磚」(非貶義詞)無異,就是根據設計師(產品經理)設計好的設計圖砌磚(編碼),建成和設計圖紙上如出一轍的建築。

因此,若是一個東西造出來與設計不符,那麼它能夠說是bug或者缺陷(缺斤少兩不完整)。不然,並非bug,但能夠被稱之爲「漏洞」(徹底沒考慮到的),表示不在預料以內的狀況。

以前看到過一個形象的比喻:你家裏的窗能夠從外面打開,那叫漏洞。你家裏的窗打不開,那叫bug


可是要認可,bug是必然存在的。爲何?它是如何出現的呢?


Bug是如何出現的

正如前面所說,程序員作的是「造房子」的事情。這件事完整的步驟分爲3步。

  1. 與產品經理討論並肯定功能(肯定一個能夠實現的設計圖紙)

  2. 將每一個單獨的元件抽象出來(肯定施工方案)

  3. 將相關的元件實現並進行組合,完成建設(帶上材料開始施工)


第一步,「與產品經理討論並肯定功能」主要是溝通,靠「看」和「理解」

可是溝通自己是一個有損耗的過程,特別是在職責很是明確的組織中,產品經理啪啦啪啦講了不少,到實際作的時候你必然仍是會去翻閱需求原型、需求文檔之類的從新理解一下。這個時候就是一個很是危險的時期。

好比像下面這個的答案是什麼?

答案是17?不對。

我猜你可能沒注意到這些地方。

爲了讓你有深入的印象,這個舉例可能比較刻意和誇張一些,可是我想在你的身邊,因爲沒注意到或者理解有誤的現象確定很常見。

溝通是相互的,這鍋只讓程序員背的話的確太委屈了點。


第二步,「將每一個單獨的元件抽象出來」這主要是一我的抽象能力的體現

可是抽象是啥?抽象是「透過現象看到本質」的能力,這個能力理論上是能夠無限增加的。隨着你對相關信息的掌握越多,這個能力會越強,會無限趨近於100%,但永遠不會真正達到100%,由於沒人知道怎麼纔算100%。

因此,當你具有的信息沒那麼多的時候,是否是就抽象的不是那麼合理?不合理會致使什麼?雖然不會直接產生bug,可是會更容易產生bug。可是人不都是須要經歷這麼一個成長的過程麼?

能夠說,精通一項能力的背後都是踩着無數的bug過來的。要麼在來這個組織以前已經踩過了,要麼在這個組織裏踩。所以,前者的薪資也比後者高。

因此,若是過度苛求沒有bug,等因而在扼殺每一個人成長的機會,而且在透支將來的可能性。人會變得很是保守、不敢嘗試新事物。

可是外部環境在不斷變化,新事物總會被動的須要去接納(技術的更新愈來愈快,趨勢不可逆),然而對新事物的接受能力又得不到鍛鍊,一旦遇到這種狀況,在接觸新事物的時候會產生更多的問題(欠下的債總要還的)。


第三步,「將相關的元件實現並進行組合,完成建設」這就是實際的coding過程,而coding是一個主觀的,徹底由人主觀掌控的事情

人畢竟不是機器,不可能不犯錯,就如前面提到的寫文章的時候出現錯別字同樣。

可能你會說,有測試人員啊,測試的工做不就是經過逆向思惟來給程序員查缺補漏嗎?

的確是的,但測試的介入只是下降錯誤率,只是讓不出現bug的機率小數點後多幾位

,期望發現100%的問題仍是不太現實的。至少在當下的條件下是這樣,爲何呢?由於代碼的本質是各類邏輯的組合。

好比,一個完整的業務流程有10個環節,每一個環節有3種可能性,這是一個什麼複雜度的系統?3 ^ 10 = 59049個分支(理論上存在的可能性數量),想要100%覆蓋這些場景,付出的成本幾乎是不可接受的。

然而咱們實際的系統中遇到的個別場景甚至還要複雜的多。

其實每一個正在運行的系統都有bug,包括咱們天天在使用一些熱門系統(玩遊戲的小夥伴們確定熟悉「卡bug」這個詞)。只是這些bug有沒有被執行到,有沒有被發現,被多少人發現而已。


那麼,咱們只能舉手投降嗎?那倒不至於,辦法仍是有的。


減小bug的慣性想法

首先最容易想到的一點是,增長測試人員。

這也是最容易看獲得的「成本」一種方式,畢竟招一我的就得支出一份工資啊。因此,增長測試人員這個方案是最不容易被老闆們採納的方案。除非你能夠說服這我的力成本的投入小於得到的價值。

另外,這個方案其實還增長了溝通成本,溝通的「隱性成本」其實很是大,可是每每容易被忽略。(關於溝通成本,感興趣的能夠看我以前寫的《就簡單聊聊溝通效率問題》)


其次會想到的就是程序員代碼寫的嚴謹一點,仔細一點啊。這也是一種缺啥補啥的慣性思惟。

先撇開到底能不能達到嚴謹一點,仔細一點的目的。那怕達到了,他會產生什麼結果呢?多是下面3種。

  1. 更多的條件驗證

  2. 更多的單元測試

  3. 更多的抽象提煉

能夠肯定的是,這些工做會增長2樣硬性的東西,投入的時間和總體的複雜度。時間很好理解,咱們就來聊聊複雜度。

一個常識是,越簡單的東西越不容易產生bug。好比1+1=2,出現bug的可能性無非就是加號寫成來減號,1寫成了4之類。可是,1+1=2,而且1*1=1,而且1/1=1,。。。等等這些驗證條件越多,那麼因爲驗證條件自身的錯誤而產生問題的可能性反而更多。

因此,代碼的複雜度和產生bug的機率是成正比的,而且具備「邊際效用遞減」的效果。這就意味着,作更多的驗證帶來的收益會愈來愈小。

所以,這個方案哪怕真能執行到位,也不是一個特別好的方案。


那有沒有相對靠譜一些的辦法呢?有,但須要咱們換一個角度來看待這個問題。


換一個角度看待bug

既然沒法100%避免bug,那咱們能夠換個角度考慮一下,如何讓解決bug的過程更快,甚至快到你都沒有察覺。

解決bug主要就是作2件事,找到bug的產生點,而後修復它。

天天都在解決bug的程序員們應該知道,這事最費時間的是「找bug」的過程

由於「修復bug」是一個技術性問題,這個對不一樣人的差別實際上是很小的,由於程序員們天天在寫的代碼都是差很少的,很是同質化的,何況還有標準答案「文檔」能夠參考。好比,都知道string.concat()是拼接,string.split()是分割。該用分割的地方不當心用了拼接,那改掉就好。


可是「找bug」就不是這樣了。好比,你剛剛改完一行代碼後發佈出現的問題,你不用找就知道問題出如今哪。可是讓你排查一個剛接手沒多久的系統確定是一臉懵逼。

根本緣由在於,這個過程不像技術性問題具備肯定性,它是充滿不肯定性的,處在一個「混沌」的環境中。


因此,對待bug的重點就變成了:如何更快的發現和找到bug

關於這點Z哥的建議是:

  1. 打好日誌

  2. 學會利用工具

  3. 每次的迭代規模儘量的小

首先,打好日誌。日誌其實就是咱們在編碼的時候安插在程序中「記錄員」,它替咱們記錄着咱們認爲容易出現問題的地方所產生的信息。

可是系統無時無刻都在運行着,必然會產生大量的日誌信息,如何從這些信息中快速的找到關鍵信息,就是須要考慮的問題。

另外,若是每一個人都隨意的用本身喜歡的記錄日誌的方式,那麼從風格迥異的日誌中找你須要的信息就變得很頭疼,時間不一致,格式不一致等等。

因此,要作好打日誌這個事情,就須要定義一個標準,好比必需要有時間,包含當前上下文的參數等等。

咱們還能夠給日誌作一下歸類,定義不一樣的日誌級別,在記錄的時候帶上前綴。好比【info】、【warning】、【error】之類。如此一來,平時更着重關注的就是error級別的信息,並且因爲將其餘級別的信息剝離了出去,使得這裏的數據量大大減小,更便於查看。


不過,日誌記錄畢竟是一個在作「預判」,若是日誌中沒有記錄到怎麼辦呢?這裏提醒你們不要先想着怎麼調試

若是你面對的系統是一個單體應用倒還好。若是你面對的是一個大型的分佈式系統,調試的效率低不說,這事你一我的可能還完不成。並且,若是你直接調試生產環境的話,說不許還會產生什麼反作用,攤上新的問題

找bug本質上是一個排除法的過程,設斷點調試也是如此。可是從起點開始一步一步的作排除法效率過低了。應該先經過本身的經驗、擁有的部分信息先邏輯推理一下,縮小排查的範圍。哪怕你最終仍是須要調試的話,先作這個事情也會讓後續的工做更高效一些。


第二點,利用工具。這裏的「工具」不要簡單的理解成利用「調試工具」。正如上面提到的,找bug的本質是一個排除法的過程,那麼任何可以幫你更高效的作排除法的工具都是能夠利用的。好比,

  • 從系統的「事件查看器」中獲取更多的環境信息。

  • 利用windows平臺的windbg、lunix平臺的MAT之類的工具直接分析抓到的dump文件。

  • 藉助可視化工具更高效的發現問題,如FlameGraph等。


另外,若是能主動的告訴你哪裏出現bug了,就更棒了。因此,咱們能夠搭建一套查看方便,信息同步及時的日誌框架,以便讓有價值的信息第一時間呈如今你的面前。若是有高效的篩選功能就更好了。

不少日誌框架Z哥沒用過,就不發表什麼言論了,可是elasticsearch + logstash + kibana這套用起來仍是很爽的,體系也比較成熟,部署起來也很簡單,你們能夠嘗試一下。再配上ElastAlert或者Sentinl,能夠把實時預警機制也包含了。


最後,每次的迭代規模儘量的小。這個提及來容易,作起來難,由於這是由整個團隊的文化來決定的。這個點的內容徹底能夠單獨開一篇講,這裏就簡要闡述下。

MVP(Minimum Viable Product)式的小步快跑,其實除了讓系統或者產品的功能演進更科學以外,還可讓每次迭代所面臨的風險更小。正如前面提到的,你改一行代碼發佈上去,若是出問題,你說問題在哪?

相對的,再想象一下,一次性發佈一個開發了半年的版本,前一晚能睡的安穩不?


總結

好了,咱們總結一下。

這篇呢Z哥先闡述了我對「什麼是bug」的理解,而後分析了bug是如何產生的,以及咱們可能會作的一些慣性選擇。

最後給你的建議是,以如何更快的找到bug爲出發點來考慮。經過「打好日誌」、「學會利用工具」、「每次的迭代規模儘量的小」這3種方式來進行


不過話說回來,雖然咱們沒法避免出bug(一個項目開發完後沒測出bug?你問任何一個技術人員都說「作夢呢」),可是爭取讓bug更少是咱們的本職工做。

由於對bug容忍度低的另外一層含義是,你們對系統的依賴愈來愈重,愈來愈多的事情在經過程序完成,而不是人力。

可是再有人咄咄逼人,就把這篇文章丟給他!



相關文章:


做者:Zachary

出處:www.cnblogs.com/Zachary-Fan…


若是你喜歡這篇文章,能夠點一下左側的「大拇指」哦~。

這樣能夠給我一點反饋。: )

謝謝你的舉手之勞。


▶關於做者:張帆(Zachary,我的微信號:Zachary-ZF)。堅持用心打磨每一篇高質量原創。本文首發於公衆號:「跨界架構師」(ID:Zachary_ZF)。<-- 點擊後閱讀熱門文章

按期發表原創內容:架構設計丨分佈式系統丨產品丨運營丨一些思考。

若是你是初級程序員,想提高但不知道如何下手。又或者作程序員多年,陷入了一些瓶頸想拓寬一下視野。歡迎關注個人公衆號「跨界架構師」,回覆「技術」,送你一份我長期收集和整理的思惟導圖。

若是你是運營,面對不斷變化的市場一籌莫展。又或者想了解主流的運營策略,以豐富本身的「倉庫」。歡迎關注個人公衆號「跨界架構師」,回覆「運營」,送你一份我長期收集和整理的思惟導圖。

相關文章
相關標籤/搜索