Showing posts with label concept. Show all posts
Showing posts with label concept. Show all posts

Sunday, April 13, 2008

Two Ways to Solve a Problem

這些年下來,我反覆觀察到一個現象:程式員各有一套慣用的方法來克服自己遭遇到的問題,這些解題習慣可區分成兩種,工程師多只專精其一,只有少數能任意在兩者間自在地切換。

在很多情況下,無論程式員採用哪種作法,都可輕易把問題解掉;但是另有一些問題,卻不是這樣隨性而為就解得掉的--這就值得我們好好玩味了……

以 1..n 的正整數相加這個例子來說,我知道程式員應該利用現成的副程式,以爬說語來寫,應該要長成這樣:

n = 100
y = sum(range(1, n+1))

假裝我們沒有現成的,像 sum 這樣的副程式可用。那麼,一種可能的寫法如下:

y = 0
for i in range(1, n+1):
    y += i

這是標準的合成(Synthesis)法。以這個例子來說,如果不考慮時間複雜度要 O(n) ,這個方法其實沒什麼不好,畢竟它非常直覺,寫起來也很簡單。

大部分資訊背景的,甚至其他工程背景的,都傾向以這種「合成」的策略來克服問題。

由於這是個已經爛掉的例子,我們當然知道有個時間複雜度只要 O(1) 的作法:

y = (1+n)*n/2

這是典型的以分析(Analysis)手段來解題的例子。通常數學或物理等理科背景的人,比較慣用這種「分析」的手段來解決問題。

大部分的工程問題都牽連太廣、太複雜了,很難找到分析解;所以工程師們很習慣採用 trial and error 的合成策略,只求找到一個可行的作法。

這種「先兜出一個作法,看著它如何失敗,然後再兜另一個作法試試,不行的話再兜另一個……」的合成策略,陪伴我們度過無數個夜晚,也解決了不少問題,但如果每次「歪打」都沒有任何「正著」甚至「歪著」的跡象,這種策略就完全失靈了。

在合成策略無效或顯得白費功夫時,也許可以學著適應理科背景的慣用手法:「靜心分析問題,用數學精確地描繪出問題,建立模型,擴充內容,增大視界」,據此提供新的想法和嘗試的途徑。

推薦文選:

Tags: [] [] []

Tuesday, September 25, 2007

The Art of Design

為甚麼好的設計會來自於差的設計呢? ScottWhy Good Design Comes from Bad Design 提到攻讀 CMU Computer Science 博士時選了門介面設計課,第一堂課上他發現一位年輕人素描著隨身聽的各種變異版本,而且圖紙上已經堆積了三、四十種不同考量的版本了。 Scott 於是湊過去問這個小伙子「幹嘛費勁畫那麼多草稿?」,小伙子發楞了好一會才笑著回說:

I don't know what a good idea looks like until I've seen the bad ones.
經過時日洗煉, Scott 後來也體會到當初認為多餘的作法,其背後的精神,他提到:
Each new idea I sketched out was more informed than the last. Each bad idea illustrated some important aspect of the problem that I hadn't thought about before. Out of every five or six ideas, I'd have one or two that might be feasible.
I learned the right way to present ideas–you have to show the other candidates in order to help support the good ones.
When the design student showed me his sketches, he was showing me that he was a designer. All creative, talented people recognize the value of process, and have no concerns about revealing to others that it takes many bad ideas to obtain good ones.
這讓我想到 C++ 的老爸 Bjarne Stroustrup 也曾經提到:
At the start of an ambitious development project, we do not know the best way to structure the system. Often, we don't even know precisely what the system should do because particulars will become clear only through the effort of building, testing, and using the system. How - short of building the complete system - do we get the information necessary to understand what design decisions are significant and to estimate their ramifications?
-- ref. The C++ Programmming Language, p710
這段 William 翻譯如下:
偉大的軟體開發專案開始之初,我們並不知道什麼才是最好的系統組織方式,甚至連應該做出什麼樣的系統都不知道;因為唯有透過打造、測試、使用系統的過程,一切才會明朗。如果尚未打造系統,該如何才能獲得必備資訊以事先瞭解有哪些重要的設計決定?
-- ref. 中譯本, p930
至此,應該不難體會:無論是要創造一個好的設計或成就一項偉大的專案,非常重要的就是要畫出許多「草稿」、進行多項測試及「實驗」。
知道要「作實驗」是個好啟發,卻不夠充分,因為我知道只有能很容易進行實驗的情況下,來談多作實驗才顯得實際。實驗容易進行,人們才有耐性多嚐試,一次又一次、反覆、輕快地測試各個主意,如此,設計才有機會趨於完善。這也是為甚麼大家開發軟體時會找個合用的 framework 來執行 Unit Testing
人們進行設計時,常常將一個大系統拆成一塊一塊,然後一次一小塊,個別考量。每一小塊都琢磨得差不多了,再把它們組一組,最後「啪」一聲,整個系統就完成了 :)
唉,事情要是都那麼順利那就好了。實際上我們會遇到許多困難,例如:怎麼把一團模糊的設計概念拆卸成小塊?每一小塊要如何進行設計,將來才兜得起來?每個小塊怎麼兜成一個整體才會穩固?為了無礙進行實驗、兜出想要的設計,還得想法子讓每個小塊都易於抽換。
一個個小塊,就是我們慣稱的一個個模組,而模組設計的目標就是讓每個模組要
  • 夠獨立,不會互相干擾。
  • 夠彈性,滿足抽換的需求。
例如設計自走車時,我們不將輪子的輪軸跟馬達的傳動軸直接連起來,而是在兩者中間放個聯軸器(a shaft coupling)的裝置,如此抽換馬達或輪子時都可以省許多功夫。
又例如設計電子元件時,要求有高輸入阻抗(Zin),及低輸出阻抗(Zout);前級元件的輸出阻抗(Zout)要遠低於後級元件的輸入阻抗(Zin),兩者最好相差十倍以上(以達成最大電壓傳輸),如此我們可以致力於前後級個別的設計,不用憂心它們訊號彼此干擾。
也許剛好自己較熟這塊,總覺得軟體的模組設計花招更多,以 OO 領域來說,相關準則有:
  • Open-Closed Principle
    • Software entities should be open for extension, but closed for modification
    • Principle of Encapsulation of Variation
  • Liskov Substitution Principle
  • Dependence Inversion Principle
    • Abstractions should not depend upon details. Details should depend upon abstractions.
    • Program to an interface, not an implementation
  • Composit/Aggregate Reuse Principle
  • Law of Demeter -- Least Knowledge Principle
    • Only talk to your immediate friends. Don't talk to strangers
  • Interface Segregation Principle
優秀的程式師總是在思索、尋求「一勞永逸」的作法。學習時不妨從具體案例開始;學成應用時,要改而著重背後的精隨,才不會被細節淹沒。這些年下來,我體會到這個精隨就是「因應變化而設計(Design for Change)」。
要明白 Design for Change ,這裡強烈推薦翻翻 Refactoring 裡提出的壞味。個人認為其中又以下列兩個壞味最為深刻:

Friday, November 04, 2005

Improving The Design of Existing Code

標題都這樣下了,當然要祭出《Refactoring》這部經典囉!

這本書問世到現在,重構已經是成熟的軟體技術了,對程式員來說,裡面的東西就如同空氣和水般,融入每天的編程中。

我只是手癢,上來把這部經典裡面的名句摘錄一番,日後也好隨時端詳端詳:

  • 如果你發現自己需要為程式添加一個特性,而程式碼結構使你無法很方便地那麼做,那就先重構那個程式,使特性的添加比較容易進行,然後再添加特性。
  • 重構之前,首先檢查自己是否有一套可靠的測試機制。這些測試必須有自我檢驗(self-checking)能力。
  • 重構技術係以微小的步伐修改程式。如果你犯下錯誤,很容易便可發現它。
  • 任何一個傻瓜都能寫出計算機可以理解的程式碼。唯有寫出人類容易理解的程式碼,才是優秀的程式員。
  • 重構(Refactoring)(名詞):對軟體內部結構的一種調整,目的是在不改變「軟體之可察行為」前提下,提高其可理解性,降低其修改成本。
  • 重構(Refactor)(動詞):使用一系列重構手法,在不改變「軟體之可察行為」前提下,調整其結構。
  • 事不過三,三則重構。(Three strikes and you refactor)
  • 不要過早發佈(published)介面。請修改你的程式碼擁有權政策,使重構更順暢。
  • 程式碼的壞味道。(Bad smells in Code)
    1. Duplicated Code
    2. Long Method
    3. Large Class
    4. Long Parameter List
    5. Divergent Change
    6. Shotgun Surgery
    7. Feature Envy
    8. Data Clumps
    9. Primitive Obsession
    10. Switch Statements
    11. Parallel Inheritance Hierarchies
    12. Lazy Class
    13. Speculative Generality
    14. Temporary Field
    15. Message Chains
    16. Middle Man
    17. Inappropriate Intimacy
    18. Alternative Class with Different Interfaces
    19. Incomplete Library Class
    20. Data Class
    21. Refused Bequest
    22. Comments
  • 當你感覺需要撰寫註釋,請先嘗試重構,試著讓所有註釋都變得多餘。
  • 確保所有測試都完全自動化,讓它們檢查自己的測試結果。
  • 一整組(a suit of)測試就是一個強大的臭蟲偵測器,能夠大大縮減搜尋臭蟲所需要的時間。
  • 頻繁地執行測試。每次編譯請把測試也考慮進去,每天至少執行每個測試一次。
  • 每當你接獲臭蟲提報(bug report),請先撰寫一個單元測試來揭發這隻臭蟲。
  • 編寫未臻完善的測試並實際執行,好過對完美測試的無盡等待。
  • 考慮可能出錯的邊界條件,把測試集中火力在那兒。
  • 當事情被大家認為應該出錯時,別忘了檢查彼時是否有異常如預期般地被拋出。
  • 不要因為「測試無法捕捉所有臭蟲」,就不撰寫測試碼,因為測試的確可以捕捉到大多數臭蟲。

Monday, July 18, 2005

[分享] 程式員的個人特質

  上次有預告說要寫一篇探討程式設計師人格特質方面的論述,就趁現在補上吧!
  無奈現在無法好好靜下心來構思內容。只好大部分都直接摘自《Code Complete》一書的論述,沒經過太多反芻。請原諒我的偷懶 =.="
~~
【智力與謙卑】
  要成為一個好的程式設計師,通常和智力沒有太大的關係。因為要能完全掌握一個程式,就得要有無限的腦容量,以吸收所有細節,並同時理解。而這對平凡的人類而言,是不可能的事情。所以
『如何將您的智力集中發揮,遠比你天生的智力高低重要多了!』
  Edsger Dijkstra 在 1975 年 Turing Award 演講時發表了一篇《The Humble Programmer》的文章。他認為大多數程式設計師都瞭解腦袋瓜的有限容量,因而採取一些補救措施。最優秀的程式設計師也就是那些最能體認人類腦力何其之小的人;相反的,那些不願承認自己腦袋瓜不夠大的人,往往就變成了最差勁的程式設計師。
【求知慾】
  一旦我們體認人類智力的渺小後,大家就會瞭解到要有效地設計程式,就要找出一些方法來彌補智力的不足。
  在成長為優秀的程式設計師的過程中,對於科技知識的求知慾一定是第一優先的事。...
  1. 建立對於發展程序的自覺
  2. 試驗
  3. 閱讀各種問題的解決方法
  4. 從成功的專案中學習
  5. 閱讀手冊
  6. 閱讀書籍及期刊
...
【智識誠實】
  一個成熟的專業程式設計師有一個很重要的特質,就是智識誠實,這可以表現在下列幾個方面:
  1. 絕不假裝您是某方面的專家
  2. 毫不遲疑地承認自己所犯的錯誤
  3. 嘗試去瞭解編譯器所產生的警告訊息,而不是略過不管
  4. 完全瞭解自己所撰寫的程式,而不是只丟給編譯器試看看有沒有錯誤
  5. 提供符合實際狀況的專案狀態報告
  6. 提供符合實際的時程預估,並能在管理階層要求縮短時程時據理力爭
...
【溝通與合作】
  優秀的程式設計師所要學習的就是團隊合作,這自然包含了『撰寫具可讀性的程式碼』。對電腦來說,程式寫得在怎麼難看都無所謂,可是人在這方面就比不上電腦。所以在撰寫程式的時候,時時得記住,將來會有某人必須維護您的程式,因此
『您必須將您撰寫的程式,當作是與將來那個人的溝通橋樑』
而不是只讓電腦懂就可以。
『任何一個傻瓜都能寫出電腦可以理解的程式碼。
 唯有寫出人類容易理解的程式碼,才是優秀的程式員。』
【創造力與拘束力】
...
【惰性】
...
~~

  嗯嗯,就摘錄到這,剩下的,就要靠各位自己的『求知慾』了 :-)
--
The art of programming is the art of organising complexity.
-- Dijkstra, 1930-2002
--
Tags: [] [] [] []

Monday, January 28, 2002

Literate Programmin

  Literate Programming 之所以被提出來,其出發點是基於,程式被人們閱讀的次數遠遠超過它被執行的次數,且程式員花在看懂程式的時間也往往比耗在撰寫程式碼的時間多得多,所以想辦法讓程式容易讓人看懂就成為一個重要的議題。

  最早的作法是為程式加上註解,以幫助人們閱讀,但是註解很容易就和程式碼漸行漸遠,產生不一致的情形,演變成有註解比沒註解還慘。況且程式和註解交雜在一起,欠缺層次感,就算註解和程式碼形影相隨,也不容易讓程式員很快就掌握整個程式的梗要。

  一些軟體工程的過程雖也為程式碼產生了一些說明文件,以資人們參考之用。但這些說明文件常常跟最後的程式碼南袁北徹。就算程式員很盡心地維持了這些文件和程式碼的一致性,說明文件也往往只提供很高階的描述,再詳細一些的描述還是繳了白卷。

  有一種作法,是在註解內添加規定的標記符號,然後用了如 javadoc 或 DOC++ 等工具,將這些特定的註解說明抽取出來,當成程式的說明文件。這種作法雖然帶來很大的方便性,但其背後的基本精神還是以告訴電腦如何作的程式碼為主,給人們看的註解說明為輔。

  高德納先生認為,既然這些程式讓人看懂比讓電腦執行重要,何不乾脆以撰寫說明文件的方式,來撰寫程式,這就是 Literate Programming 的由來。它是以撰寫說明文件為主,編程為輔的方式來完成程式設計。

  我們可以對 Literate Programming 的 source code 抽取出格式化的說明文件,如 (La)Tex 或 PDF 等格式;也可以從中抽取出可供編譯器編譯的程式碼...

Monday, December 10, 2001

軟體系統的秩序起源--《建築的永恆之道》評介之續篇

  這一回,就如之前規劃的,來聊聊“軟體構築”。更精確地說,是軟體系統中,秩序的來源。

  大體上,這篇文章會由我認知到這些想法的時間先後來描述:

~~

   大部分的程式員,只要從事過幾個軟體系統的構築,在經過多次日以繼夜與軟體臭蟲纏鬥的歷練之後,相信很容易就能體認什麼叫做 garbage in garbage out--電腦是個沒有自己想法的傻蛋,它只會依計行事,它只能根據程式員編撰的指令列表,逐一地執行指令,不多也不少。

  「軟體系統的秩序是程式員從外頭強加進來的」

  這就和每一個精密的人造製品,如鐘錶、手機、電腦等一樣,也如同每座偉大的建築物般,不用費太多想像,就可以知道其幕後必有設計者設計出這些東西。

   X    X    X    X    X    X

  只要構築過幾個中型以上的軟體系統,就會發現,我們很難真正對這些系統的每一個細節都顧慮到:

  隨著軟體系統規模的加大,緊接而來的複雜度滋長,是非常可怕的,所以每個優秀的程式設計師都很能體認,人類的腦容量在面對大型軟體系統時顯得十分卑微。
  但是一個又一個重量級的軟體系統還是被完成了!難道就只靠善盡一些分析、設計的方法、流程等軟體管理方法。就能維持住我們挹注到系統中的秩序?人們真的就只靠自己對每一個細節的精確掌握就防堵了因開發過程中導致的“軟體熵”快速滋長?
  晚近的軟體工程都非常強調軟體構築是一個反覆的過程:分析一些後再設計一些或撰一些程式碼;設計一些後,在撰碼之前,也可能再作分析的工作;撰過一些碼了,也可能再去作分析、設計的工作。整個過程充滿著意外、挫折、驚喜與學習。

  「軟體系統與其建構者在互動中而滋長出秩序」

  雖然很多人也許不願意承認,但軟體系統中的秩序並非只是單純地由程式師從外界引入。即使在構築的過程,軟體系統也透過人和外界環境產生豐富的互動。有時陷入混亂;有時軟體的完成,甚至還有水到渠成之感呢。

   X    X    X    X    X    X

  在生物學上,有一個貫穿這個學門的通則,這對生物學這門充滿例外和驚奇的領域來說,的確是十分罕見的,這項一般性原理就是 Darwin 所提出的《天擇》

  「軟體系統的秩序也可經由“天擇”產生」

  天擇是生物演化的機制,而由John H. Holland 所提出的遺傳演算法作了第一次在電腦上實現天擇演化的示範。
  現在,天擇已經被借用到許多軟體系統裡,以解決一些關於設計、模式識別及特徵搜尋等問題。並將這門研究統稱為“演化式計算”。

  演化式計算解決問題的方式和傳統軟體如作業系統的設計方式雖然有很明顯的差距。但他們對於軟體系統秩序的來源,都較傾向於“由外而內”。
  傳統軟體系統的秩序是程式員由外界給定的;演化式軟體系統的秩序是經由天擇選出後再注入系統的,而挑選的標準大致還是程式員由外指定的。

   X    X    X    X    X    X

  在許多情況下,我們對問題沒有一個明確的解法,而演化式計算的方法又顯得太過緩慢及浪費計算資源。

  有一個做法是,先找出系統中的交互關係,據以建立軟體模型,然後讓這個模型設計自己,使解答經由“自我組織”的方式“突現”出來。

  對我而言,軟體秩序中最難有直覺性認知的來源就是這種被 Kauffman 稱為自在的秩序(order for free)的自我組織原理。

  「自我組織也可為軟體系統產生自發的秩序。」

  非常複雜的系統通常具備收斂性的變化流程:恆定性或微擾下的穩定性背後之基本原理,也是許多複雜系統的自然特徵。

  自我組織是自然界中最普遍的秩序原理,對物理學家而言,一點也不陌生。而天擇及自我組織聯手造就了生命系統的秩序。

  英國神學家Paley曾想像有個人,在路上撿到了一只錶,這人發現「在事物裡有一個秩序原理,這個原理將這個錶的零件安排成目前的形式」根本不可能。因為「他從來沒見過由秩序原理製造的錶;也不能想像所謂秩序原理究竟是什麼,除非指的是鐘錶匠的智慧。」
  Kauffman的錶是從內部經“自在的秩序”設計出來的。Paley 的錶是由外部的鐘錶匠設計的。Darwin的錶是以時間過程中純粹偶然事件的累積設計的。

~~

  呵!遲了一個禮拜才整理出來,實在是最近比較忙,一不小心時間就從指縫溜了過去。

  所幸,還是整理出來了,對自己雖有個交代,內文脈絡卻顯得不大連貫。倉促行文,諸位看官就把它當作消遣,看看就好 :p

Saturday, May 12, 2001

軟體開發的時程與風險

  上次談了“嵌入式軟體”,這次就談談也出現在《數位式競爭》的“軟體專案失敗常見的原因──時程估計錯誤”:

  「軟體專案的完成時間在開發的初期不只是難以估計,理論上是不可能估計的」。相信這句話在這一陣子以來,大家的體會都很深了吧!

  但是許多公司不能接受這樣的事實。主管們要求在一開始就要有明確的時程和成本估計。但是時程估計的誤差要減少,有賴於事前對專案作明確的“定義”和嚴謹的“分析”。並已經真正著手作部分的“設計”。不然,時程錯估的情形是必然發生的。

  導致錯誤的時程預估方法背後的原因有:

  1. 過分熱觀的軟體開發者。
  2. 增加人手不一定管用──開發工作不能隨意切割,因軟體程式彼此關係緊密,許多開發工作必須連貫地完成。
  3. 低估了完成軟體產品所需的努力──許多軟體服務公司一直犯一個重複的錯誤,以為在為幾個客戶開發了幾個功能類似的軟體系統後,就可以把以前開發的成果,轉變為一個標準產品,同時為數十位客戶提供相同的功能。他們錯了。
  4. 管理階層不顧現實的期望──一廂情願的期待本身就是一個陷阱,管理階層往往還故意利用過度樂觀的期望對開發人員施壓。
  5. 過度壓縮的時程──不務實的時程也許能激勵某些人拼命工作,但是軟體開發人員是分析能力極強、而且非常聰明的一群人。假如開發時程脫離現實,結果就是沒人把它當一回事。
  6. 功能偷渡現象──沒有人會強迫營建商,在屋頂已經蓋好以後,再去重建地下室。但在軟體業裡,這卻是司空見慣的事。

  當然,在專案開始前,最少要先對客戶的需求有一個模糊的概念,並且將其寫下來。然後很重要的是要評估專案的“風險”。常見的風險可以分成“需求風險”、“技術風險”、“技能風險”和“政治風險”:
  • 需求風險──很明顯地,最大的風險是做出不是顧客需要的軟體系統。
  • 技術風險──是否選對符合需要的技術?不同的部分能不能整合在一起?
  • 技能風險──是否有完成工作所需的人員和專家?
  • 政治風險──是否有政治力量介入而且會嚴重影響到專案?

  在認清風險後才可以決定是否繼續進行這個專案──比較不成功的軟體服務公司毫無選擇地承接專案,但表現優異的公司平均拒絕了40%上門的生意。

  哈!哈!這一回的內容大都是由《數位式競爭》一書中“偷”過來的,建議您可以翻閱一下本書...
Tags: [] [] []

Monday, January 29, 2001

程式設計的箴言──擷取自《Writing Solid Code》

這一陣子以來,公司瀰漫在一片除錯的淵藪當中,很多人都顯得心力交瘁,我自己也被攪得焦頭濫額。這不禁讓人想起一句品管上的名言:品質是內建的,不是外加的(Quality is build-in, not add-on.)──這時讀來,倍感切心。

於是這次就延續上次的“程式設計的箴言”,不過換了一本關於“除錯”的書:

  1. 啟動所有編譯器中的預警功能。
  2. 利用lint找出那些編譯器所找不到的錯誤。
  3. 如果您有單元測試工具,請好好利用。
  4. 請同時保有“偵錯版”及“上市版”。
  5. 請利用assert維護巨集來確認函式引數的正確性。
  6. 避免讓程式產生未定義的行為,不然就在這些地方加上維護敘述,以免有人誤用了這些未定義的結果。
  7. 適時地加上註解,以免浪費別人的時間來看懂您的維護敘述。
  8. 不要直接利用假設的狀況,否則請加上維護敘述來檢查這些條件。
  9. 利用維護敘述找出不該在正常情況下發生的現象。
  10. 不要為求包容意外的狀況而忽略了潛在的錯誤。
  11. 利用不同的演算法來協助您確認程式的結果。
  12. 避免產生隨機行為,並且讓錯誤無所遁形。
  13. 清除不能使用的記憶體空間,以免誤用了它的資料而不自知。
  14. 程式中如果有些行為太少發生了,就強迫它多發生幾次。
  15. 多保留一些系統資訊,有助於進行更嚴謹的除錯。
  16. 徹底建立子系統的檢查程序,並且盡可能地去使用它。
  17. 小心地設計測試條件,從各種可行的方法中慎選最好的。
  18. 致力寫出無形的,而且完整的測試。
  19. 不要以發行時的標準來苛求偵錯版本,偵錯能力是必須犧牲速度及程式大小換來的。
  20. 不要等到錯誤發生,才被迫去逐步追蹤程式。
  21. 逐步追蹤您的程式。
  22. 逐步追蹤程式的時候,請多注意資料的流向及內容。
  23. 以原始程式指令為單位無法知道所有執行的細節,面對重要的程式碼最好以組合語言指令為單位來逐步測試。
  24. 讓程式的介面為程式師把關,使他們不至於忽略錯誤的情況,更不要因為傳回值的設計不良而造成錯誤。
  25. 不時地檢查、並且去除函式介面裡的缺失。
  26. 不要以一個函式來包含多項功能;盡可能讓每一個函式只完成一項獨立的功能,這樣有助於我們做更完整的引數檢查。
  27. 清楚地定義函式的引數,不要弄得模稜兩可。
  28. 確定函式的輸入值都是正確的,以避免函式傳回“輸入錯誤”的訊息。
  29. 讓一般的程式師都能由函式的定義看出函式的呼叫方法,並且避免使用布林值來當引數。
  30. 用註解來強調函式中潛在的危機。
  31. 利用定義明確的資料型別。
  32. 隨時注意變數會不會產生溢位或不足位的現象。
  33. 寫程式的時候要盡量依照原始的設計,任何無心的偏差都可能造成始料未及的錯誤。
  34. 盡量使每一個步驟都只用一段程式來完成。
  35. 盡量不用if敘述來處理例外的狀況。
  36. 避免層層疊疊的使用?:運算子。
  37. 盡量使同一類的特殊狀況只用一段程式處理──將相同的條件敘述合成一條。
  38. 避免採用程式語言的危險慣例。
  39. 若非必要,不要任意將不同類的運算混在一個式子裡。萬一必須將不同的運算放在一起使用,就用括號來標明運算的順序。
  40. 避免呼叫會傳回錯誤碼的函式。
  41. 不屬於自己的記憶體,就不要使用。
  42. 不要去使用已經被我們釋放的記憶體空間。
  43. 不要把用來傳輸出結果的記憶體拿來當成作業時的暫存空間。
  44. 不要以 static(或整體性)的空間來傳資料。
  45. 不要讓我們的函式變成“寄生蟲”。
  46. 不要濫用程式語言的特性。
  47. 將 C 的原始程式寫短,編譯出來的執行碼不見得就會有效率。
  48. 寫程式要盡量讓一般人看懂。
  49. 錯誤不會自己“跑掉”。
  50. 發現錯誤立即修正,莫待將來付出更慘痛的代價。
  51. 不能只是解除錯誤的表象,要除掉病因才能真正解決問題。
  52. 除非為了讓軟體更成功,非修改不可。否則不要隨便“整理”程式。
  53. 不要增添沒有必要的功能。
  54. 任何一項功能都要付出代價。
  55. 不要容許沒有必要的彈性。
  56. 不要盲目地從一堆“嘗試”中去找答案;將時間用來找尋“最正確”的方法。
  57. 每完成一小部份,就先回頭測試一遍。不管進度是不是落後,一定要徹底地將程式測試過。
  58. 不能只靠測試小組來除錯。
  59. 不要錯怪測試人員存心找麻煩。
  60. 建立自己適用的優先順序,並確實地依照這個標準來做取捨。
  61. 不要讓同一個錯誤有再次出現的機會。

好了,總共六十一條,終於整理出來了,希望對各位有所幫助。想要知道更詳盡內容的話,強力建議諸位直接去翻閱本書。

Tags: [] [] [] []

Sunday, January 28, 2001

程式設計的箴言──擷取自《資料結構與程式設計》

前一陣子轉貼了《教堂與市集》的格言後,大家的反應還滿正面的,於是就趁年假,再為大家剪貼一下《資料結構與程式設計》中的箴言:

  1. 將資料專門化和抽象化的過程,是先於資料結構的選擇和程式的撰寫。
  2. 一個具體的問題描述是與一千個尚未運用的抽象概念等值的。
  3. 永遠小心謹慎地給予變數及函式合宜的名稱,並提供充分的說明。
  4. 盡量使你的文件(document)簡潔但具描述性。
  5. 花在閱讀程式的時間永遠比撰寫程式來得多。
  6. 切勿見樹不見林。
  7. 每一個函式只做一個工作,且須將其做好。
  8. 每一個函式必須隱藏部分東西。
  9. 盡量使得關連性簡單,盡可能避免使用全域(global)變數。
  10. 不要引起副作用(side-effects)。
  11. 盡可能地,提前做好除錯與測試。
  12. 測試資料之品質遠較數量重要。
  13. 程式測試可用以顯示錯誤之存在,而非其不存在。
  14. 對於每一小型模組採用玻璃箱(glass-box )測試;對於程式中較大段落,則採用黑箱測試(black-box)。
  15. 大部分的程式以百分之九十的時間處理百分之十的指令。
  16. 找出關鍵的百分之十,並全力使其更具效率。
  17. 絕不在規格說明確定及完整前開始編寫程式。
  18. 瞭解你的問題,對每一個函式定義精確的前置條件及後置條件。
  19. 盡可能地使演算法簡單。
  20. 如有疑問時,選擇簡單的方法。
  21. 選擇演算法時,將時間與空間的邊際效應列入考慮範圍。
  22. 絕不怕重新開始:下一次可能會是既精簡又容易。
  23. 確定你完全瞭解問題。
  24. 如需改變問題的項目,明確解釋所做的變動。
  25. 匆忙行事,事後後悔;倉促地撰寫程式就會永遠地除錯。
  26. 重新開始多半比對舊程式打補釘容易得多。
  27. 要經常計劃建造原型(prototype )及丟棄它;不論事前規劃如何,你都得如此做的。
Tags: [] [] [] []

程式的再利用(Reuse)

  在工作會議上, Steve 曾提到 Reuse ...

  就一個程式設計師而言,增進程式碼與設計的“再利用”程度是一個值得關切的議題。所以,這次就來探討一下程式的再利用。

  有關程式再利用的觀念性論述,個人覺得以 C++ 之父 Bjarne Stroustrup 的見解最為精闢完備,所以以下就引述其看法:

  基本上,“再利用”是一種“社會現象”。唯有當別人的軟體有以下特質時,我才會去用它們:

  1. 可用:在談「再利用」之前,必須先「可以用」才行。
  2. 可理解:程式結構、註解、文件、教學資料是很重要的。
  3. 可與其他軟體合作無間。
  4. 有人支援(或是我自己願意擔下來;不過通常我都不會願意)
  5. 夠經濟(我能夠和其他使用者共同分擔開發及維護成本嗎?)
  6. 能被我找到。

  再利用文化的必要條件是要有人專門負責這種共享任務。在小組織裡面,通常要有一個人刻意或無意地成為共同程式庫及文件的維護者;在大一點的組織裡,通常要有一個特設小組或部門專門負責匯集、建立、文件化、宣傳、維護這些可被大家引用的軟體庫。

  軟體系統會大略反映出製造它的組織文化,如果該組織文化沒有促進與獎勵合作分享的“機制”,軟體亦不大可能有合作共享的性質。

  優良的傳統文件製作雖屬必要,但仍不夠。元件小組還要提供教學等資訊讓潛在的使用者易於找出可用元件並瞭解為什麼它們有用。

  元件小組成員應該盡量與軟體開發小組密切合作,如此才能充分知曉他們的需求、讓他們知道其他不同的應用軟體有哪些潛在的可再利用機會可資引用。

  很重要的一點是,“再利用”境界是“精心設計”的結果:在設計之初就立下目標要達到可再利用性、根據經驗一再精鏈元件、致力找尋可再利用的既存元件。

  “再利用”並不是憑空而來,並不是隨隨便便動用特定語言功能或程式技巧即可獲致。更遑論只是輕率地完成一支程式就想要“再利用”。


--

如果組織文化把程式員都當成傻瓜看待,那麼很快地,程式員都會樂於當個傻瓜。

--
Tags: [] [] []