為什麼程序比較難寫、bug 比較難調呢?

題主試試Haskell吧,會有一番新的體驗。


為什麼bug難調,舉個生活中簡單的例子。

家裡買了很多電器,有好多發票。假如電器都沒壞,那相安無事;假如電器壞了,你要找出發票來保修。可是總會很悲催的發現,其他發票都在,就那張不見了蹤影。

想必,這張票要找出來是得費一番功夫的。


答題的都沒答到點子上,關鍵是在於規模問題。

樓主看武俠小說嗎?裡面有一個理念是:將簡單的動作重複多次而不出錯就會上升到一個更高的境界,典型的比如傅紅雪揮刀(自宮?)十萬次,方練成絕世刀法。

毛太祖曾經說過,一個人做一件好事容易,難的是一輩子做好事。其實都是一個道理。

寫一個幾百行的代碼,用戶規模不超過5人,應用場景兩張稿紙就能列完,這樣的代碼完全可以做到無bug。

但是放大之後,一套幾百兆的源代碼,對你沒看錯,不包括資源文件,就是記錄源代碼的純文本文件就有幾百兆,這裡面bug的數量是會呈幾何比例上升的。

支撐編程的,只有那麼幾條能數清的規則,但當規模擴大之後,原本簡單的,也變得不簡單了。這就是工程學的魅力。


嘛....本人大學狗碼農一隻....工程也寫了不少...個人覺得

1.你說的程序不好寫 我也不知道怎麼說了這個 只能說應該算是思維不夠好,如果只是寫個小tool那麼確認目標就分析下流程就應該能piapiapia的寫了0 0 至少我是這樣的...當然 如果是大工程...得考慮什麼資料庫,程序構架,模式等等等等 很多的軟體工程的東西,因為涉及到穩定性可擴展性等,要考慮的很多,比如怎麼設計才方便後期維護,怎麼設計才方便功能增加,什麼什麼的,..這個希望對題主有用..當然對我而言 更多是自己多寫 寫著寫著就有感覺了 看到問題能馬上反應出用什麼技術,怎樣弄流程是什麼這樣....

2.至於bug難調試....

個人覺得 首先要養成良好的編程思維,我是長期寫Window的0 0所以多參考下MSDN,注意越界,注意一個變數不同的值會引發什麼,注意極值的問題什麼的

剩下的就是如果調用API就要多研究MSDN的說明,看看會返回什麼出錯會有什麼原因等等

只有這樣做才會減少bug的出現,發現bug時,先嘗試從邏輯上走走,看看是不是邏輯掛了,如果邏輯沒問題,可以直接看看出錯的時候的數據是什麼,是什麼引發的,程序中如果是演算法 很多時候是出現了預測之外的值,或者不存在的值

如果是內存,可能是空指針越界什麼的..好多好多情況 無法一一舉例什麼的

額 好像看了題主的問題...總覺得太模糊..如果題主只有學習了數據結構的基礎...還是先掌握一門語言為主 沒有語言 不了解系統 不知道程序運行和系統調度的流程 是很難寫的...希望我的回答對博主有用....

畢竟學生狗TnT我也不容易....TnT 自己遇到的bug都是寫的時候為了圖方便 少了一些判斷 ..真用起來才發現很多東西不判斷不行...然後回去繼續加...導致bug不停...思維不到家...


那麼請題主不用線代和高數的知識計算一下500個點的最小二乘擬合?


有幾類bug比較難調的,一是無法再現的bug,二是代碼不讓看的bug,三是多線程,資源競合環境下bug的大部分。

題主目前最主要的問題是工程經驗不夠,踩坑不夠,目測踩5年坑,再來談這個問題可以有深入的領悟。

吐槽一下,如果題主對隊列棧圖都比較好懂,那你大多數能再現的bug都不在話下。

本人改bug改了很多年,主要判斷依據和解決辦法是再現方法,log,stack trace,dump,面相,心理學,口才功力。

改bug最重要是保留案發現場,然後要管理好用戶的期望值,最後要用說得技能讓用戶聽你的。

碰到大坑一定繞行。

不要想改的很完美,除非確定坑有多深。不確定坑有多深不要貿貿然動手,大概率引入新bug。

掉進坑裡了及時棄坑而逃。

Bug數量可以用歷史曲線擬合的,所以可以先做好task management。

對於新手而言,我的勸告是先不要把對的改錯,錯的也沒改對。

一點小小的人生經驗。

最後寫好代碼和改好bug根本不算一個檔次的東西好嗎!

測試是妹子的時候戰鬥力加50%。可以和老闆說,要年輕貌美的,男女搭配幹活不累。

一般都讓我挑。


紙上得來終覺淺,須知此事要躬行


排名第一的答主回答的還不錯,但通篇只介紹了其中的一個原因,應該還有其他原因不是?

1、邏輯複雜度

排名第一的答主已經做了詳細介紹,這裡不贅述了,只是額外說一句,如今的軟體工程學一直都在致力於解決如何構建複雜、規模化軟體系統的問題,在我看來複雜性只是客觀原因,但不是本質原因,office夠複雜吧,但bug很少。

我們不妨思考一下:

A:為什麼公司總有那麼幾個牛叉的人,寫的代碼bug很少?這些人寫的很多成果已經成為基礎設施,幾乎是公司的永久資產。

B:不同的人開發相同的輪子,結果差別為何會如此之大?

在我看來,其實還是人的問題,不從自身上找問題,而是去找客觀原因,有違做事的基本法則。

以下是我的一些觀點:

2、問題分析能力尚缺,思考不夠嚴密

我相信很多人都體驗過排名第一答主的類似經歷,很早的時候,我也是這樣,一看到需求,就急不可待的啪啪啪敲鍵盤,然後就會出現各種各樣的低級bug,好,問題出現了不怕,沒上線之前再改就是了,即使上線了,哪有不出bug的程序?windows還出bug呢。

很多人會這樣為自己找借口,我也曾經如此,但,這對自我的提高沒有任何裨益。

這個問題簡單來說,就是思考的不夠細,不夠深思熟慮,隨著年齡的增長,做事情如果還是這樣,那基本決定了他未來的發展道路了。

我們必須養成深思熟慮的習慣,之後再動手,如果你沒有想明白八九十,那就放下手中的鍵盤,好好想一想,拿起手中的筆,把一些關鍵環節寫下來。大學的時候,寫論文是這樣的,為何一畢業,寫代碼就丟棄了這樣的方法呢?

我以前跟別人這麼建議或要求的時候,聽到最多的回答,「客戶催的太緊了,先應付一下」,「沒必要,這個並不難,拿以前的改一改就行了」,項目經理說這樣的話很多人都會抱怨,卻不知道不少程序員被要求提供交付件時,也在說同樣的話。

技能在不斷的實踐中,是能不斷成熟的,原先出一個詳細設計(思考+繪製)可能需要1天時間,之後隨著經驗的增長,可能幾十分鐘就能搞定,比起將來的維護時間投入,這實在是非常小的開支。

退一步說,將來找工作,你繪製的詳細設計會是談判的一個很大籌碼,比起光會說的人,這東西一個頂一萬句。

3、化繁為簡的能力不足(設計能力不足)

看似簡單易用的結果,其後面付出的設計絕非簡單一詞就能概括,這需要設計者具備化腐朽為神奇的能力,在經過嚴密思考的情況下,抽絲剝繭,把職責理清,並扎紮實實的做好宏觀設計和微觀設計。

在我認識的人中,很多人從來都不做設計的,把問題想的過於簡單,代碼就是上手就來,這樣不出錯才怪了。有人說:「我看很多牛人也不做設計」,那正是人家牛的地方,設計很清晰的放在腦海中,只是沒有寫下來而已。

不要相信,沒有設計會出好軟體!就像一個家庭一樣,布局和收納沒有經過設計,那一定伴隨著臟、亂、差。

在我的一次項目實施中,已經到了尾聲,我因為重要事情離開了一段時間,在離開之前,客戶提出了一個需求,這個需求的實現方式跟我們已有的一個技術路線非常相似,因此,我通知我的小夥伴讓其做一個詳細設計給我,在我離開之前,催促了好幾次也沒給我(這期間,他確實有很多其他的事情需要做),等我出去的時候,過了幾天,電話不停的打過來,說這個需求搞不定了,他和另一個小夥伴整了幾天也沒搞定,客戶又催的很緊,他實在沒有辦法了。我問,為什麼搞不定,這跟以前的技術路線不是很相似嗎?他說,他一開始也這麼想,自以為很快就能搞定,所以就偷了一下懶沒做詳細設計。我想說的是,很多事情並沒有想像的那麼簡單,很多人自以為簡單,然後忽略了很多必要的流程,結果付出慘重的代價。

做軟體需要不斷的去思考,去優化,甚至去重構,如果沒有這樣的基因,是很難做好軟體的。

如何去優化?通常可以通過這幾個方面去思考

a:職責

軟體中各種模塊的職責是否清晰,職責越清晰,那麼出錯的可能性越小。跟人做事一樣,身兼多頭,不出錯才怪。流水線出錯的可能性很小,就是因為職責非常單一。

b:分層

把複雜性通過合理的設計,分離到多個層次中,關於這一點可以參考網路的七層模型。這類手段通常用於較複雜的一些框架設計,分層其實也是一個職責重新劃分的問題,該設計背後的邏輯實際上是問題域的劃分,從而利於程序的維護,出了錯誤很快就能知道問題可能在什麼地方。

最後說一下工具的運用,現在要做好軟體工程,不用工具那真是很難想像。

分析類工具:uml

設計類工具:visio,powerdesigner等


Computational mathematics


寫的少。


計算機的基礎是二進位。相比人類的邏輯能力,二進位邏輯非常低級(或者說愚蠢)。編程就是讓傻子理解正常人的思路,能不難么。

上帝往地上扔了多少個蘋果才讓人類懂得萬有引力。


1. 腦子裡的模型轉化成實體代碼的過程

棧、隊列、樹、圖都比較好理解 但是你知道怎麼用c語言實現嗎?

2. 各種欠缺考慮的情況

就算你把它實現了 你能保證在你代碼的某個角落

沒有出現解引用空指針的情況 或者其他各種奇怪的情況嗎?

3. bug難以重現 導致難以找出並解決

4. 需求不斷在變化

就算你把它寫出來了 也debug好了 你還要考慮後續維護的事情

一個東西做出來容易 維護起來難啊

建議你以後寫什麼東西先考慮一下 沒事不要瞎開坑

====================================================================

總之就是現實世界太複雜了 高數線代那些理論只對真空中的球形雞有效

現實世界如果像高數線代那麼簡單抽象化就好了


bug多感覺是因為很多細節的東西沒處理好。比如我在曾經在遞歸里多寫了一個分號結果內存爆炸找了一天錯誤。。難寫在於有些自己想表達的東西用程序就是寫不出來。。感覺還是多練多寫吧。。一些拙見。。。


經驗問題,別扯什麼圖形學,演算法學,各種導論各種參考書。

我沒見過哪些大牛把這些書說的這麼神的,反倒是一些新手喜歡吹噓什麼導論多牛,好像學了就能脫胎換骨一樣(YY去吧)。請多實踐,多動手解決問題。


寫代碼最重要的就是一個「寫」字,你說你對這些概念理解的較好,那最多說明你理解了基本概念和原理。但代碼不是靠「想」出來,而是要靠寫的,腦中的概念往往都是基於最理想化,最正常的情況,而實際寫代碼時卻面臨著充滿各種異常的真實狀況,這兩者的差別就好比會砌磚、會攪拌水泥和真正修房子一樣,調bug更是需要在不斷地調試中積累大量的經驗,這些都不是一蹴而就,也不是簡單的理解幾個數據結構和演算法就能搞定的。所以,想寫好代碼,拚命的寫就對了!


其實Bug分為兩種
編譯時異常
運行時異常
如果現在你在代碼的過程中,Bug還一直處於經常犯錯在變異時異常的話,那麼說明你還比較入門,或者是對這塊的知識點了解的不夠全面,解決辦法就是多敲多練

如果,你在編碼時,很少出現Bug在編譯的時候,那麼說明你,已經是較為熟練的掌握這塊的知識點了,那麼唯一的不足就是,你對,這塊整個流程的執行,或者是函數之間互相調用的邏輯結構還不是特別清晰,那麼解決辦法就是,每當你敲完一遍後,按照斷點,或者執行順序,走一次,看看,整個過程到底是咋樣的!

總之,熟能生巧,努力不會白付出!


根本上來說還是人類智力和生產力有限。編程分成提出程序的需求,解決程序的計算方法,和編程的工程實施。因為人類的智力有限,解決計算(數學)問題對人類本身就是難題,且不談一個程序不僅僅只包含一個計算上的難題。解決數學問題更要求邏輯上的完備,而人類的計算要達到邏輯完備也很難。提出程序的需求和解決程序的計算方法都可以看作數學過程,兩者的不完備就會導致程序的BUG。智力有限決定學習能力有限,你無法大量掌握其他人的經驗避免不犯下別人犯過的錯誤。生產力有限一方面決定了編程需要長久的困難工作,另一方面決定了編程的工程實施需要分工,需要有人造輪子有人使用輪子。因為製造出來的輪子不是明確的或者完美無瑕的(存在BUG),這導致了使用輪子的人無法避免地去了解輪子(設計的目的和如何避免BUG),加重學習負擔,延長了工時,也導致了有人嘗試製造更好用或者更專業的輪子,以至於更多大量的有缺陷的輪子被重複發明出來,在一個明確的而且完美的輪子被發明出來,以上過程會成為一個無盡的循環。

解決一個BUG既可以看作數學問題也可以看作工程問題。看作數學問題既是從計算過程中排查錯誤,看作工程問題既是從程序的運行中去檢查出錯點。前者本身從解決一個數學問題上說就是不容易的,後者除了程序調試的工具不方便,重現問題的不容易外,還可能關係到各種輪子的問題:自己的代碼沒有錯,是系統、編程語言、虛擬機或編譯器、編程框架出錯。


樓主提出的是代碼難寫,難調,實質上,計算機科學中有很多高大上的演算法也很難理解,但樓主問題不在這裡,我們就先不討論這個了,

代碼難寫,結合我自身5年coding及思考的經驗

首先,你的邏輯方式是否正確就是個問題,說的通俗點,在軟體開發中,你的需求分析,方案設計是否合理,或者是在演算法設計中,你的演算法是否對應著這個問題,這其實是公認的難題,需要結合很強的思考能力,嚴密的邏輯能力,當然還有結合當前環境的經驗。

**************************************插入點東西,發現自己對演算法部分的分析似乎少了點*********

作者的問題問的是程序為什麼難寫,事實上就是說明他知道怎麼寫,但是寫不好,演算法的難度我用一個ACMer的話來說吧,「你想入門是吧,先把演算法導論看完再來找我吧」,說實話,演算法導論和計算機程序設計藝術,雖然被稱為CS領域的聖經與荷馬史詩,而且這兩本書銷量也不錯,但正真能夠認真的把這兩本書研究透的人鳳毛麟角(比爾蓋茨說過,你要是看完了TAOCP計算機程序設計藝術,那你把你的簡歷和讀書筆記發我郵箱里),可見,合理的演算法在計算機程序設計中的重要性,當然,作為一個業餘的acmer,只能看著專業隊員門各種AC而忘梅止渴了。。

其次,就算你邏輯正確了,你還要用對應的形式化編程語言將你的邏輯表現成一種機器認可的方式,這就涉及了很大的一部分東西的考慮,包括你的邊界條件,錯誤捕捉,運行環境,鏈接的庫的版本,中間很大問題,而且當你把這些東西都考慮周到之後,你的代碼也只是到達了第一個階段,有了一個可用的原型,對於許多中型的項目來說,這時的代碼量已經到幾w了。要達到這些目的,你需要避免如下的難點:

1.要整體沒有bug,就必須要你所寫的每個部分都有bug,就拿自然語言來說(我們日常所說的語言被稱為自然語言,相對於自然語言,在計算機科學中,有種語言稱為形式語言,參考《形式語言與自動機》),在我們寫的文章中,如果超過幾w,我們很難保證其中不出現語言錯誤,或錯別字,如果讓另一個人讀,他可能會根據上下文猜出錯字錯句含義,但對於形式語言(很重要的一點就是消除歧義性)來說你的一個拼寫錯誤極有可能造成一個編譯錯誤(這點對於新手來說更甚,記得我剛開始學編程的時候,一個小錯可以找一下午,這時候引發的錯誤是很好發現的),

2.就算我們在理想狀況下,在編碼時完全沒有拼寫或語法錯誤,但我們在邏輯轉化成形式語言的過程中,也會出現很多錯誤(比如所,我曾經因為"char a=0xc9; printf("%d
", a==0xc9); "這樣類似的一句話調了1個多小時,讀者們猜想下這條編碼的輸出是什麼),這些問題實質上出自我們對語言理解的不充分,

3.最後還有一種錯誤,也是目前我遇到的做難調的bug,我們在自己的腦海中假設了某種程序運行的外部環境(比如說,程序要求內核是linux2.68的,但實際上我用的是別的版本,這就引發了一些潛在的問題,事實上這類問題極難發現,還有一次,我將我的代碼移植到一台全新的伺服器上去,但是一直出現bug,然後經過幾個小時的調試,我終於把問題定位到了memmem語句,由於我預先假設了系統環境中的庫和我之前使用的是一個版本,實質上,在bug系統中,利用memmem所返回的指針會將高位截斷),

其實我是個菜鳥級的程序員,但我開發中遇到的錯誤就這麼大的一堆,而且其中不乏有很多海森堡(Heisen bug不可重現的錯誤),不管過去現在還是未來,bug總是刺激著我的神經,又給我創造著成就感,你干好了別人干不好的東西,還需要更多的肯定么?

再次,在我們程序的可行性,穩定性,移植性都滿足的情況下,還需要完成的就是可讀性,和可擴充性,

你寫的東西是否屬實,經得住時間考驗,換個環境也湊效《---------------------------》可行性,穩定性,移植性

你寫的東西是否優美,是否稍加修改又能滿足更多的需求《-----------------------------》可讀性,可擴充性

c++為什麼能衝擊c語言,並在原先c的市場上佔領一席之地,第一點就是OOP編程良好的可讀性以及可擴充性。

大概寫了這麼3點,其實現在能想到的還有更多,但是由於我是個程序小咔,大局觀還是不是那麼強的,對於各種軟體工程中的問題,以及各種語言哲學所給出的解決方案,我就不照本宣科了,因為事實上,對於Perl,Python,Haskell等語言,以及Unix族的操作系統(我只用過linux和ios),對於這些東西的學習,我還只是停留在紙面或是更小的一部分,所以就不在這誤人子弟了。。


思路不對,越寫越難受


儘可能證明程序的正確性


我覺得,這個原因是,忽視了人心的複雜程度,解決問題的辦法不在於如何讓計算機滿足人的需求,而是應該盡量讓人去靠近計算機。

就是說,我的東西是好東西,但是只賣給識貨的。

這就好比,高精尖的領域,只適合高端的人,如果只是從俗的話,那麼產品也不會是好的。


這些只是常見的數據結構,理解的好卻寫不出來只表明你對抽象出來的這些結構概念了解,深入到實際問題,如果生搬硬套,寫出來了也是碰巧,學習數據結構和演算法最重要的是掌握思想方法,這樣實際問題你不僅能靈活運用,而且能構造出更好適用於當前問題結構,不過這些常見的結構也夠用了,還是要多練,深入到實際!純研究也要從實際中獲取靈感!


大海撈針→_→


唐詩三百首我都會讀,為什麼不會寫呢


專業書籍、小說、電影、法律條文、合同、制度哪種腦力勞動/創作沒有BUG?


簡單來說,要在一個0-1的世界裡模擬出真實的世界,你覺得複雜度如何?


1. 還有不常見概念不太好理解

2. 二分查找好理解吧,每年校招面試時能寫對沒bug的不多,但我相信他們是很清楚二分查找的原理的。聲稱了解其他演算法的,也難免不會寫出類似bug.


推薦閱讀:

自動安全檢測五大實例
golang channel阻塞與非阻塞用法
NBA首次舉辦編程馬拉松,深度數據已成球隊新寵
為什麼github不出中文版?

TAG:編程 | 計算機科學 |

分頁阅读: 1 2