發表文章

軟體開發中的「無緒」

圖片
無緒 (Cluelessness) 由 Martin Rinard 提出。他在演講時指出: 在開發和維護軟體系統時,應該避免讓開發人員深入了解系統。 因為人的大腦可以處理的資訊有限。若要建立一個日益變大的應用程式,就必須學習「 如何讓每個開發人員在不了解整個應用程式的情況下,也能完成軟體開發 」。  “無緒” 並不是一個貶義詞。它用來區別兩種層次的理解水平。 1. 淺層理解 :指對事物的了解程度僅限於掌握使用方法即可。 2. 深層理解 :指對掌握了事物背後的原則、規律、原理。 在日常生活中的“無緒” 生活中我們通常只需要用到 淺層理解 。例如,刷牙不需要知道化學式。不需要理解冰箱原理就可以冷凍食品。當然,也有一些人需要了解更深入的內容。像是冰箱的維修人員就要了解較深入的領域知識。但即便如此,維修人員所需要的知識仍屬於 淺層理解 ,因為他們也不需要了解事物背後的每個小細節和原理。 當然也可以學習每件事物背後的知識原理,但是必要性與 CP 值通常不大。因此大多數人在日常生活中只需要 淺層理解  就足夠了。 軟體開發中的“無緒” 在軟體開發中,“無緒” 也表示大部分的時間中,開發人員只需要  淺層理解  就足以應付工作。這裡的  淺層理解  並不是指開發人員不需要懂得編寫程式。以下舉個例子來說明軟體開發中的  淺層理解  與  深層理解  之間的差異。 「電子商務網站」: 某天 PM 告知下一個專案是「電子商務網站」。那麼,實作這個網站有兩種做法: 實作方法一: 在專案初始階段,我需要打開 HTTP 協定的文件,解析 HTTP 傳輸格式、 研究如何實現 POST、GET 請求....等等。  此外還要閱讀 RFC 文件,並實現文件中的各項內容。  全部都搞定後才能開始打造「電子商務網站」。 實作方法二: 在專案初始階段,在作業系統中下載並安裝 Apache、PHP、MySQL,  設定妥當後即開始打造「電子商務網站」。 相信 實作方法二  才是大家熟悉開發的方式,因為現代軟體都是基於組件組裝出來的,沒有人需要獨自從頭到尾完成所有內容。在一個作業系統上安裝 Web 服務並開始編寫 HTML,對現在的開發人員來說是易如反掌。但事實上光是 Web 服務就已經複雜到極點,應該沒人敢說自己了解 Web 服務的所有內容。這

再談 SOLID 原則,Why SOLID?

系列文章 淺談物件導向 SOLID 原則對工程師的好處與如何影響能力 再談 SOLID 原則,Why SOLID? SRP 單一職責原則,定義、解析與實踐 物件導向設計原則:開放封閉原則,定義、解析與實踐 Why SOLID? 在 前一篇文章 中介紹 SOLID 對一個工程師的影響,這裡再稍微補充一下為什麼軟體開發會需要 SOLID 原則? 軟體複雜的本質 專案經常會歷經「商業邏輯調整」和「快速且多變的需求」,這都不是開發環節所能控制的,但是一個專案會「遇到困難」常常是因為  糟糕的程式設計  和其他技術層面導致。 其中  糟糕的程式設計  又可分成三個因素: 程式碼變更 Bug 修復 複雜度控制 在添加功能前應該  閱讀代碼並細心設計 ,但實際上更常發生的是,開發者選擇 直接在程式碼上面堆疊新的程式碼 。 新舊版本  和  意圖不同  的程式碼錯綜複雜之下,會讓專案難以在不引發連鎖反應的情況下增加功能。最後新的功能引入 Bug,從而導致另一個 Bug,然後一個接著一個,這樣的事情不斷發生。 在  沒有做過可擴展性設計的程式碼  上進行擴展功能,常常是火上加油! 那為什麼不把程式「設計」成可擴展就好了呢? 開發者知識普遍不足 一個充滿外行人的產業 開發者們來自不同的背景,且有大量不同的方式去解決問題,但是一個開發者應該具備什麼樣的知識體系,並沒有一個廣泛的共識。 更不幸的是,許多開發者在學校裡面學到的知識是過時的,學校提供的程式設計課程並未給學生做好準備。這些課程通常只關注程式語言的功能,但是 ... 掌握一門程式語言並不能使你成為軟體開發者,正如掌握一門自然語言並不能使你成為作家 學校所教的知識,並不是大部分軟體開發者的工作內容。 開發者也許能編寫一個可運行的程式碼,但若要 回頭去擴展程式碼卻 常 常 是艱難且冒險的 。 軟體開發過程中,開發者需要做出無數個選擇,加上每個開發者用不同的方法解決問題,助長了難以維護、難以擴展的程式碼。最終讓  系統設計的思想溝通  變得困難( 工程師必須花費大量時間閱讀程式碼 )。 不論是開發者還是管理者都需要對  軟體複雜的本質  做管理。為了編寫出更容易應對變化的程式碼,我們必須填補基礎認知方面的空白。 導入設計原則 若有一些

淺談物件導向 SOLID 原則對工程師的好處與如何影響能力

系列文章 淺談物件導向 SOLID 原則對工程師的好處與如何影響能力 再談 SOLID 原則,Why SOLID? SRP 單一職責原則,定義、解析與實踐 物件導向設計原則:開放封閉原則,定義、解析與實踐 物件導向 SOLID 原則對工程師的好處與如何影響能力 前言 為了感謝部落格一直以來都有人在閱讀,讓我一直有經營下去的動力。所以想寫一個系列 學習 SOLID 原則 2 年後的心得文章。這心得文章包含自己使用 SOLID 兩年的總結,並且以自己的理解簡化 SOLID 原則,希望幫助新手工程師縮短「SOLID 原則是文字天書」的時間。 從第一次接觸 物件導向 SOLID 原則  至今已經兩年了,一開始覺得「SOLID 原則是文字天書」,到現在 Coding 時常融入 SOLID 的思想來「設計」程式。 所以 SOLID 原則到底是什麼? 》SOLID 原則其實是物件導向「設計層面」的思維與定律。 大學時期程式設計課程中所學的物件導向,其實只是在介紹程式語言有提供  物件導向的哪些特性 ,卻 從未有人教導如何透過物件導向的特性撰寫程式碼 ,甚至沒人告訴你為什麼要用物件導向開發程式。 然而 SOLID 原則就是物件導向開發的指導方針,若以多個角度來看這些原則,會發現 SOLID 已經指出  物件導向的優點   以及 程序式程式碼隱晦的缺點 。但這不代表物件導向沒有缺點,要是沒有妥善運用 SOLID 原則的話,物件導向對專案的傷害絕對不比  程序式程式碼  低!但這留給後續的文章來解釋,首先來看看 SOLID 的好處與重要性。 SOLID 原則對專案的好處?  SOLID 原則對專案的影響很大,當專案一點一滴的導入 SOLID 原則的程式碼,不少複雜的程式碼慢慢被簡化,被 簡化的程式碼可以降低複雜度,讀懂程式碼的時間從原本需要花 20 分鐘閱讀,到只需要花費 2 分鐘閱讀 。縮短閱讀時間對專案來說是一件好事, 一般來說工程師「閱讀程式碼」的時間常常大於 「 新增/修改程式碼」的時間 ,畢竟要先讀懂才能動手嘛,因此  縮短閱讀 程式碼 時間 等於 縮短 「 新增/修改程式碼」 程式碼的時間 。 優點:降低程式碼複雜度 => 縮短閱讀程式碼的時間 => 減少維護專案程式碼的時間 你可能會覺得,為什麼 S

自學技巧,與難易度相關的讀書技巧

圖片
與難易度相關的讀書技巧: Tips 1: 若一直花時間讀太簡單的書,表示沒有累積新知識,只是在浪費時間 。 讀書目的是累積知識量、增進新觀念。 這時應該挑戰困難、進階一點的書。 Tips 2: 若 看不懂作者部分的內容,表示你跟作者仍不在同一個知識水平 。 這時需要找別的資源(網路文章、別的書籍)補充知識。 Tips 3: 若 看不懂作者一半的內容,表示跟作者的知識水平相差太多 。 這時應該放下手上的書,先學習 前置知識 再回來挑戰。 Tips 4: 不要讀到不懂詞彙的就立刻停下來查資料 。 應先快速讀過整本書、章節,讓大腦快速建立 書中的知識概念、詞彙關係 。 大腦建立起 詞彙關係 後,再回來查資料會更容易理解。 其他: 學習新知識的過程總是辛苦… ​

自學選書技巧、推薦程度說明

圖片
自學時常要 K 書培養知識,但是在資訊大爆大的時代,書籍的數量跟網路文章一樣多,品質也參差不齊。因此選書需要謹慎,若不仔細挑書就容易變成浪費時間。 平時選書會透過「 題材/範圍、深度、作者文筆、翻譯品質 」來決定要不要購買或花時間讀下去: 題材/範圍: 快速讀過目錄,檢查書本內容是不是圍繞在你有興趣的主題。 深度: 快速翻閱書籍內容,檢查書本的深度/難易度是不是符合你現在的需求。若深度太淺、太簡單則表示你不需要花太多時間閱讀這本書。反之深度太深、太困難,表示應該花時間學習前置知識。 作者文筆: 此項決定知識的吸收效率。快速檢查大小章節的前後順序,以及內文是否與章節有關聯。 作者若有系統性的把書籍章節、內文結構設計妥當,由淺入深。則閱讀書籍速度跟吸收知識都會很快。 若作者沒辦法有結構、系統性得組織知識,在閱讀書籍時,你必須時常前後反覆翻閱,並搭配網路搜尋文章補充知識,把破碎的知識從書中整理到腦海裡。 翻譯品質: 程式相關的書籍,多半是國外原文翻譯的書,若翻譯品質很差,輕則看得出戲(有些翻譯與句很怪,根本不像中文),重則扭曲作者原意,誤導讀者學習不對的觀念。 若遇到翻譯品質差的書籍,可以改換簡體書看(換譯者)或者搭配原文書一起看。 ​

單元測試的藝術

圖片
The Art of Unit Testing: with examples in C#, 2/e 書本連結 摘要: 本書涵蓋了撰寫單元測試的基本知識,包含如何撰寫單元測試、使用隔離(模擬)框架,以及讓它們變得可維護、可讀、可被信任。並且講解在真實世界撰寫、管理和維護單元測試的最佳實踐。 心得: 第一、二章: 作者示範一個良好的單元測試應該具備哪些條件。 第三、四章: 作者以設計單元測試的角度,引用 Working Effectively with Legacy Code 的接縫技術講解如何透過接縫技術建立偽物件,讓單元測試的受測對象(SUT)可以隔離依賴,達到快速、獨立原則。 接縫技術是針對 Legacy Code 無法執行單元測試的處理手段 ,由本書的角度來學習接縫技術,會覺得為什麼要繞一大圈只為了產生偽物件(Stub/Mock)。因此建議直接去看 Working Effectively with Legacy Code 如何使用接縫技術讓多種情境的 Legacy Code 可執行單元測試。 第五章: 使用模擬(Mock)框架來取代三、四章節的接縫技術。 覺得此章節的安排不太洽當, 接縫技術是針對 Legacy Code 無法執行單元測試的處理手段 ,作者卻以取代接縫技術的角度來介紹模擬框架,可能讓讀者誤以為接縫技術是過時的測試手段。 也許是本書出版的年代較早 (1/e: 2009、2/e: 2013),但現今的測試框架搭配模擬框架已經相當普及。若要講解模擬技術時,應該直接講解模擬框架即可,把接縫技術跟模擬技術分開講應該會更好!。 第七、八、九、十、十一章節: 介紹開發團隊在實務中如何進行單元測試,包含如何安排單元測試的檔案、舊系統引入單元測試的策略、如何讓單元測試好維護..等等。 若您的團隊還不了解怎麼進行單元測試,則相當推薦閱讀這些章節。 總結: 本書的深度不深,作者把讀者設定為單元測試的新手,從 0 開始講解單元測試,書中的內容大多是針對不良測試案例的叮嚀。 推薦給想學習單元測試又對單元測試不了解的工程師,本書將單元測試應該具備的概念都教完了,讀過後應該能少走不少歪路。 適合讀者:對單元測試不了解的工程師 可學習議題:單元測試技術 延伸學習:測試驅動開發(TDD)、行為

CodeIgniter 框架擴展:HMVC

圖片
CodeIgniter 框架擴展:HMVC Hierarchical((階層式的))-Model-View-Controller(HMVC)模式,也可以叫做 Layered MVC。 為什麼需要 HMVC 單層 MVC 的限制 原 MVC 架構中只有單層 MVC ,單層 MVC 的設計本身沒問題,但隨著系統功能漸變多變複雜時,程式碼卻只能塞進單層 MVC 裡面,程式碼很快就會變得  巨大、縱錯複雜、互相耦合、難以維護 。試想一下,一個 Controller 內有 7、8 千行程式碼會容易維護嗎。 原 CodeIgniter MVC 架構(單層 MVC)示意圖: application |- controllers |- controllersA.php |- controllersB.php |- ...(所有 Controller 都只能放在同一層) |- models |- models1.php |- models2.php |- ...(所有 Model 都只能放在同一層) |- views |- views1 |- index.php |- footer.php |- ... |- views2 |- index.php |- footer.php HMVC 帶來的解決方案: 擴展 MVC 架構, 讓 MVC 底下可以再擴充一層或多層子 MVC ,讓單層 MVC 變成階層式 MVC,而這些擴充出來的 MVC,又稱作為模組、模塊(Modules)。 使用模組好處是: 使每個功能都可以獨立出來 因模組變得獨立,降低各個功能模組之間的耦合性 提高程式碼複用性 每個模組都有自己的 MVC 結構 HMVC 架構示意圖: CodeIgniter HMVC 擴展模組後,其結構(階層式 MVC)如下: application |- modules |- moduleA

重構的定義與目的

重構定義: 在不改變軟體外部行為的前提下,改變其內部結構,使其更容易理解且易於修改。 目的: 重構的主要目的就是為了提升程式碼品質、 提升程式碼的可讀性 ,以及為了日後有新需求的變化時,程式碼可以 更容易修改或是擴充 (提高可維護性)。 優點: 1. 改進程式碼的設計: 消除重覆的程式碼,每個小功能被歸責到適當的物件中,讓程式碼的職責更清楚就會更容易維護。 將雜亂無序的程式碼,重構成一連串的 精心設計 的流程,讓程式碼更容易擴充。 2. 程式碼更容易被理解: 重構簡單的講,就是整理程式碼,可以透過 Clean Code 的規範 來整理程式碼,提升可讀性。 想想程式碼過一段時間後的第二個讀者,而且這個人常常是你自己。 3. Debug 更容易: 重構的過程中,會透過單一職責原則,依照程式碼的工作責任將程式碼整理至責任相同的類別中。有責任清楚的物件,就能更快釐清問題點,除錯速度自然能夠提升。 什麼時候可以開始重構? 事實上,重構並不是一項需要額外撥出時間來進行的工作, 重構應該是在你的開發過程中持續在發生的事情 。 重構的活動,最理想的情況,就是透過持續不斷的整理,掃除那些有礙程式可讀性及可維護性的程式碼,讓程式碼持續盡可能地保持在一定健康的狀態。 既然重構是一個持續進行的活動,但又不是特意安排、特別撥出時間來做的工作,那麼,在什麼樣明確的時間點,應該觸發重構的進行呢?基本上, 重構的活動應該伴隨著我們一般開發過程中的主要活動來進行。這些主要活動包括了:增加新功能、修正錯誤、以及程式碼審查的時候,還有三次法則 。 三次法則: 同樣的事做三次,犯了 Don’t Repeat Yourself 原則,表示重複的邏輯該被重構成唯一且適當的物件或函式了。 新增功能時重構: 當我們試著增加新功能時,便有可能發現舊有的程式碼可以進行一些調整,而達成了必須重構所想要達成的目的。 但如果你在增加功能的時候,發現原設計就足以優雅地讓你將新功能擴充上去,那麼,這意謂著,還不太需要做什麼重構。 除錯時重構: 除錯的時候,你不僅會接觸到舊有的程式碼,而且,你通常得搞懂它真正的運作邏輯,當你真的懂了之後,就會知道如何用更清晰、簡潔的方式來改寫這段程式碼。 總結: 很多架構良好的程式,

如何處理已經 Push 的 Commit Message!

圖片
這種已經推(push)上來的沒辦法更改 Commit Message 跟內容  怎麼辦! 這種情況我會直接重切一條新的分支,重寫 Commit,底下是主要步驟: 把這幾次 Commit 的異動暫存(stash)起來 從開發前的 Commit 切新分支(for 重寫 commit 用) 把暫存(stash)的檔案套用到新分支 開始重寫 Commit 做完 Commit 就把新切出來這條分支上傳回自己的 Repo,重發 Merge Request。 第一次做可能不熟,所以底下是每個步驟截圖: 步驟看起來很多,但做熟的話其實就只有幾個主要步驟而已,會越做越快! 1. 把這幾次 Commit 的異動暫存(stash)起來 2. 從在開發前的 Commit 切新分支(for 重寫 commit 用) 3. 把暫存(stash)的檔案套用到新分支 4. 開始重寫 Commit ​

Gitlab 合併請求 Merge Request 是什麼?

圖片
Gitlab 合併請求(Merge Request ) 一般在團隊開發的時候,為了避免工程師直接對主要 Repo 進行修改,會要求工程師從 專案的主要 Repo 複製一份這個專案的副本(Fork)回來工程師的電腦進行開發/除錯。 工程師開發完成後,如果要把電腦上最新版本的程式碼上傳回 專案的主要 Repo ,就必須對 專案的主要 Repo 發送一個 合併請求 ,請 專案的主要 Repo 管理員進行程式合併。 當合併請求發送出去後, 專案的主要 Repo 管理員可以在管理頁面上看見你的合併請求,這時管理員會進行一次 Code Review,管理員覺得程式沒問題,就會將工程師的程式合併回主線。 若管理員覺得這段程式碼有問題,也可以 Close 這次的 Merge Request 。 另外 Merge Request 等同於 Github 的 Pull Request   - 可參考:  與其它開發者的互動 - 使用 Pull Request(PR) 上述流程如下圖: ​

Git 開發流程

圖片
Git 實際開發流程 真實開發的時候,除了有 Gitlab 上面的  主要 repo 、 自己的 repo 以外,還會有一份在本機開發的 本地 repo , 這份 本地 repo 是從 自己的 repo Clone 回來的。 注意 :底下步驟 1 除了從主線 pull 最新版本的程式回來,也可以直接從主線切一條分支出來做開發(推薦後者) 推薦後者(直切從主線切出一條分支出來做 issue)的原因是: 實務上開發的過程中,一個工程師可能會同時掛多個 issue。假設突然出現一個緊急的 issue 時,你可以從主線再切一條新分支,用來處理緊急的 issue。把緊急的 issue 處理完成後,在切回原本開發的 issue 分支繼續原來的工作!這是前者辦不到的。 以下是 Git 實際開發的流程: 一般要開始做 issue 前,就會先從主線拉(pull)一份最新版本的程式(code base)回來做開發, 開發的過程可能會有多個檔案被異動,也可能經歷多次 commit。 開發完成後,為了避免與別人 push 回主線的程式碼發生衝突,一定會先做一次 Pull, 注意: 做 Pull 時 Git 會自動幫你 Merge,這時會有以下幾種情況發生 : Git 自動 Merge 成功,不發生衝突。 Git 自動 Merge 失敗,發生衝突,需要你手動處理衝突。 不管有沒有發生衝突,Merge 完後都會有一次合併程式的 Commit((合併程式也算異動))。 做完 Pull & Merge 後,就可以把最新的 commit 推(push)回主線,完成本次 issue 的提交。 ​

Git Commit Message 這樣寫會更好,替專案引入規範與範例

圖片
Commit Message 跟寫程式註解還蠻像的, 最好可以寫下「為什麼」你要作這樣的異動, 而不是單單只記錄下你做了「什麼」異動。 Commit Message 最好兼俱 Why 及 What,讓日後進行維護人員更快進入狀況。 Commit Message 這樣寫會更好: 做 issue 的時候,不應該一次 Commit 所有異動!應該獨立 Commit 每個不同意義的異動,這樣 commit 訊息才會跟異動的程式碼有關聯。 每次 Commit 都是針對異動的檔案做說明:Why & What。這樣的 Commit Message 能讓日後的維護人員更快進入狀況 每次 Commit 都加上 issue 編號,方便追蹤相關的程式異動原因。 若 Commit Message 寫得妥當,在閱讀追蹤程式碼的意圖會相當容易。如果只把 Git 當作版本控制,隨意撰寫 Commit Message 就太可惜了! 不能只把 Git 當作程式碼的 FTP,要把 Git 當作歷史查閱的工具才拿發揮 Git 的功能。 好與不好的真實案例 用一個小插曲證實 Commit 訊息的重要性 上面 PPT 是我在工作中遇到的兩個案例,範例中包含「好的 Commit Message」與「不良的 Commit Message」。 在範例中可見: 良好的 Commit Message: 如何在「一年後」讓維護人員進入狀況 不良的 Commit Message: 如何在「一個月內」讓維護人員找不出程式異動的原因 。 Commit Message 之規範 在撰寫 Git 與 SVN 等版本控制軟體 Commit Message 時,可以參照國外 AngularJS 團隊的規範: AngularJS Git Commit Message Conventions 以下為這套訊息規範的展示與說明: Commit Message 規範範例: Commit Message 規範範例解析: Commit Message 規範組成: Header: < type > ( < scope > ): < subject > - type: 代表 commit 的類別:feat, fix, docs, sty