寫程式碼容易,程式設計並不容易
當我的程式設計生涯開始的時候,我認為“程式設計很簡單……怎麼會需要去學校學習呢?”但經過學習和實踐,我瞭解到程式設計很難。
自我評價對我自己來說一直都很重要,因為在一天結束的時候,不管別人怎麼想,自己的想法都很重要。我會在評價中思考強項、弱項、學習、訓練和個人成長。這個過程讓我反思、理解並思考成為一個程式設計師究竟意味著什麼。
教育:編碼?程式設計?關鍵性的抨擊?
我在技術領域的第一份工作主要是通過 HTML、CSS 和 JavaScript 操作一些元素並建立視覺效果。在這段時間裡,我沒有真正想到自己是一個程式設計師,對於這個問題,我從來沒有想要成為一個真正的程式設計師。不久以後我想使用 NodeJS、PHP 和 MySQL 做更多事情,這時候我開始考慮這個問題。把我作為程式設計師的所有巨集偉想法加起在一起,我在第一份工作中把自己當作一個小小的“軟體工程師”,一直都在積極地制定方案。
“經驗告訴我,我會頗具氣勢地拍、打和敲擊鍵盤,但那並不是程式設計。”
程式設計需要思考和理解各種資料型別、結構,並理解程式語言賴以構建服務的技術。差異主要在於完成特定任務時所使用的流程。重點不在於資料型別、設計模式、演算法型別、效能或任何與程式碼和應用程式質量相關的內容。相反,它被納入了實際的工作機制和技藝之中,這往往需要耗費大量的時間,最終變成一隻難以維護的巨獸。一直執行輸出到不同地方,並積極地測試輸出,直到它非常類似於一個功能。如果有什麼事情給我一種程式設計的感覺,但我在實際操作中並沒有做到將想法付諸行動。
思考資料
資料結構是我感受到教育不足的一個方面。資料結構背後的想法是,你有不同的方法去儲存、提取、排序和搜尋資料。最初當我開始程式設計,我從來沒有想過各種資料的任務與資料型別的效能。對需要儲存、排序或遍歷的任何事物,通常預設使用陣列(包括雜湊、json、字典,以及鍵-值資料集的其他術語
從電腦科學的角度看,集合、堆疊和佇列對我來說是很有趣的,但在 Ruby 程式語言中看到一些實際操作之後,對我來說並不那麼吸引人。在我看來,堆疊和佇列是一樣的,它們允許你從資料的末端獲取資訊,佇列的例外情況是,你只能按照它們加入的順序獲得這些項。當我開始想象這一點時,我想把東西放在一個列表中,等待處理,減少可在後臺執行的任務的開銷。事實上在高層次的程式語言如 Ruby 中對此付諸實踐,並沒有多大意義,因為它基本上是在往陣列中 push(後追加)或 unshift(前新增)元素。
比如,Ruby 中的棧可以像下面的程式碼一樣簡單。
123456789101112131415161718192021222324 | class Stack # init stack def initialize = Array.new() end # put a new item at the end of the stack def push(x) .push x end # get the last item in the stack def grab .pop end # is the set empty true false bool def empty? .empty? endend# implemented stacks = Stack.new<Stack:0x48b66454=["a","b","c"]>putss.grab# "c" putss.grab# "b" putss.grab# "a" s.grab.inspect# nil |
佇列和上面建立的資料型別基本上是一樣的,Ruby 已經有一個類了。
12345678910 | # ruby Queue Classq=Queue.newq<<'a'q<<'b'# Tests Examples using Queueputsq.length# prints 2 putsq.pop# prints aputsq.length# prints 1 putsq.pop# prints b putsq.length#prints 0 |
它的簡單性是基於一個非常簡單的陣列,這本身就體現了它的美。我看到自己在命令列指令碼中使用棧或佇列,但我不確定還可以在別的什麼地方使用它們。
二叉搜尋樹在處理搜尋資料的時間和速度上吸引了我。我經常發現從資料中獲取資料非常容易,但在陣列中搜索需要花大量時間。這就是為什麼需要二叉搜尋樹,我非常喜歡哈佛的這段視訊。雖然我並沒有使用這些東西來做過什麼,但是非常想用它們來實現點東西,然後將之與原生 Ruby 的陣列方法進行比較,看看二叉樹比普通的陣列或雜湊快多少。我在關於二叉權勢的研究中試圖找到實際的用例,於是發現了這些有意思的文章。
- 數值搜尋 — 來源於 Zach Kemp
可維護性
我的第一個 Web 應用在可維護性方面可笑極了。沒有編碼規範,沒有設計模式,沒有對定義的方法進行整理,沒有使用名稱空間,也沒有物件和模型。如果一定要我去修復缺陷(肯定會有),與其去找實際導致缺陷的方法,還不如重寫來得快些。
設計拙劣導致亂糟糟的程式碼。
我難以處理的問題之一是條件巢狀和迴圈巢狀。這些迴圈中存在大量的 if 語句和驗證,但這個問題本身來源於一個系統性的問題,即不清楚怎樣恰當地組織和拆分程式的不同部分。我曾嘗試著在一個巨大的方法中處理所有事情,不關心哪些程式碼可以重用,也沒建立一個模組來擴充套件物件和方法的功能。為了節省篇幅,下面的程式碼擷取自真實的程式碼。
123456789101112131415161718 | print" <h3> Display Weekdays: </h3> ";// Looping in a view ... should have been factored diffforeach($imageRecords["display"]as$=>$displayRecords){// WTF is this a nested foreach foreach($displayRecords as$value=>$dispRecord){$tempWeekdayValuesArray=array();if($value==="weekdays"&&!isnull($dispRecord)){// 3rd nested foreach WTF!foreach($dispRecord as$weekday=>$weekbool){// :( condition foreach day ::SHAME::if($weekday=="monday"&&$weekbool==1){// logic removed }}}}} |
我不會把責任推到別人身上,這段壞程式碼是我寫的,我會承認這一點,然而其中一些本來可以通過程式碼導師、或者通過程式碼審查和“拉”請求來加以緩解。回顧這段程式碼,我感到慚愧,但這是一件好事,因為它表明了我作為一個開發人員的成長程度。自由在某些意義上是一個問題,但不是在其他方面。例如,對這個專案我被限制於使用 LAMP 技術棧,這是不容協商的,但與此同時,這真的是唯一的限制。我沒有使用設計模式,遵循任何風格指南, 使用程式碼分析器,或遵循程式碼公約的任何政策。這就建立了一個系統,你可以自由地使用自己的裝置,並且如果你還沒有了解應用程式的長期性和錯誤修復,那麼它會損害你的最終結果。
我已經真正體會到了文字編輯器的好處,在你編寫程式碼時它會給出提示(指出潛在的錯誤)從而為你節省很多時間,同時我也開始欣賞與程式設計相關的一些美好細節。一個寫得很好的程式碼庫,會遵循文件標準、清晰的約定和風格指南,閱讀起來就像一封電子郵件或一篇網文那樣流暢。(當然,有時候使用的程式語言本身就更好)總地來說,我也發現我很喜歡這本書中的許多原則, 。
測試驅動開發
在我看來,測試驅動開發的好處足以證明其優點,但我明白,並不是每個人都同意測試為程式碼庫提供任何價值。我不會爭論測試的有效性,但我確實想分享它如何幫到我。在實際建立程式碼之前,為程式碼編寫整合測試和單元測試已經在很多方面幫到我。它幫助我編寫更整潔的程式碼,高效地編寫程式碼,並幫助我解決了我遇到麻煩的問題。
編寫更整潔、更高效的程式碼與程式設計中的許多事情有交叉。可讀性、效能和編碼時間是 TDD 幫到我的主要方面。我發現我能編寫程式碼,不必重構(多次)使其可以上生產線或進入版本控制庫。它不僅幫助我減少了 bug,而且幫助我減少了跟蹤和修復 bug 所花費的時間。修復 bug 時,我發現我可以接受預期的輸入或輸出,編寫一個與之匹配的測試,然後努力使該測試和所有其他測試通過。這樣可以消除 bug,並確保程式碼實現其預期的目的。
在開始編寫實際的方法或物件之前,TDD 可以幫助我組織思路。在更復雜的功能中,它可以幫助我將功能分解成其需要正常工作的集。也就是說,邊界條件就是邊界條件,並且在最初建立程式碼時往往更難於考慮到邊界情況。最終我覺得測試驅動開發有助於使我成為更好的程式設計師。