發表文章

目前顯示的是有「IoC」標籤的文章

使用IoC與DI有何意義? (四) 使用IoC與DI提高可測試性

圖片
這一系列的文章,持續維持著一年更新一篇的進度,😛。 今天適逢良辰吉日,我們再次來談談,如何透過IoC與DI增加系統的可測試性。 關於單元測試(Unit Test) 我們知道,有單元測試的存在,我們得以放膽的修改程式碼,無須擔心程式碼的頻繁異動將造成意料之外的副作用。 也因此,有一些團隊追求著程式碼單元測試的覆蓋率。 然而,高覆蓋率的單元測試並不意味著就會有更高品質的程式碼,反而真正重要的是,如何為我們系統中的核心邏輯、重要的核心函式,適當的添加單元測試。 所以,我們接下來要來談一談,如何透過IoC與DI增加程式碼的可測試性。 關於可測試性 你大概也已經知道,我們可以透過Visual Studio為特定的method來建立單元測試。特別是重要的商業邏輯運算函式、或是API,都是單元測試非常能發揮功能的好對象。 然而,你可能會發現有些程式碼似乎難以測試,例如底下這個例子: Console.Write("請輸入金額(USD):"); var amount = int.Parse(Console.ReadLine()); //100 Console.Write("請輸入人數:"); var people = int.Parse(Console.ReadLine()); //5 Financy f = new Financy(); var CostByPeople = f.SplitMoney(amount, people); Console.Write(CostByPeople); 上面這段程式碼看起來簡單,實際上,也真的很簡單😎。 SplitMoney()是一個計算旅遊消費金額分攤的函式。 假設,你和一夥人出國旅遊,在路邊店家吃了一餐,總共100美元,你想計算每個人要負擔多少台幣,就可以使用這個函式。呼叫SplitMoney()時,傳入『美金總金額』和『人數』兩個參數,它就幫你算出一個人要付的台幣金額。 假設我們要針對這個函式進行單元測試,乍看之下似乎並不難,但我們看SplitMoney()的具體內容: public class Financy { public double SplitMoney(double USDAmount, int People) { var currenc...

使用IoC與DI有何意義? (三) 在 Console 程式中使用DI

圖片
這一篇的重點在介紹,如何在Console App中使用DI,但我們的重點卻不是 Console,而是 “使用DI”。 看完 前面 兩篇,你應該要想到一個問題,如果PageModel或MVC的Controller,被呼叫的時候,.net core的DI服務會自動幫我們把Startup.cs中指定好的類別實作,自動注入PageModel(或Controller),那Console中的Main()也會嗎? 好比說,如果我把程式寫成底下這樣: 我在Main()中能夠讀到 _SalaryFormula 的值嗎? 猜猜看? … … … 答案是===> 不會。 原因很簡單,因為Console App的進入點是靜態的 Main()函式,它根本就是一切的源頭,是應用程式被Launch起來的時候,最最最開始的入口,根本 不會有人去幫你 run 上面 5-8行的建構子,所以理所當然的也沒有注入這回事。 那…為何 PageModel可以? 為何MVC的Controller可以? 原因也不難,因為當用戶點選(或連結到)某一個頁面(或某一個Routing)的時候,該頁面(PageModel或Controller)所觸發的那隻程式(Onget() 或 Action),根本就不是整個程式的進入點。它(頁面)是"被"人家執行的。這個執行者不是用戶,是由 asp.net 的框架本身host的。 其實,整個 .net 應用程式的入口一直都是 Program.cs。 請看底下這個MVC Web應用程式的Program.cs: 事實上,Program.cs才是一切程式的進入點,而上面的Host,則是幫我們運行(Launch)起 asp,net web應用程式的背後推手。(未來有空我們再談這個類別) 一直以來,是有一個host幫我們承載每一個頁面的。當asp.net的某個頁面被呼叫,每一個controller被觸發,都不是該class被用戶主動觸發,而是『被』呼叫,被誰呼叫呢? 就是框架本身。正確的流程應該是,某個頁面(或說網址)被呼叫到時,asp.net框架中的底層(middleware, routing…etc.)得知該request,接收該http request的各種參數之後,幫我們new出我們所寫的程式碼(類別),然後把相關參數(像是Que...

使用IoC與DI有何意義? (二) asp.net core中的DI服務

圖片
看過了 前面 的介紹,在瞭解了DI的背景需求與前提,以及採用介面來降低對特定物件實作的相依性之後,我們接著來看,怎麼使用asp.net core中的DI服務進行功能抽換。 事實上,早在約莫十年前,坊間就有很多DI框架或套件,例如我之前上課介紹過的Unity Application Block,他是一組DI Container(容器)套件,可以幫助我們更輕易地實現動態注入。而asp.net core則是把DI設計為服務,讓我們在程式碼當中,也可以輕易享有相關的功能。 在軟體開發的領域當中,你慢慢會發現到,真正困擾你的不是寫(新)程式,而是改(舊)程式。在我們開發系統的過程當中,我們會希望盡可能維持原始程式碼的不改變,就能夠加入新功能。原因很簡單,拿 先前 提過的例子,你只是想要修改薪資計算公式,而不是換掉整套HR系統,然後你剛才接手這個系統不久,這時候你不會想看完這套HR系統的整套原始程式碼,才能增加一個小小的薪資計算公式。 另外,你很有可能碰到運氣更差的狀況,就是你手邊根本沒有原始程式碼。 你不過就只是想改一下薪資計算的公式啊?(因為政府剛調整了最低薪資…) 記得Martin Fowler在 重構 一書中說過這麼一段話: 你回頭想,果真是如此,如果程式碼寫得夠好,你根本不需要看完所有程式碼,甚至也無須擁有整套程式碼,就能夠依照需求在系統中添加新功能。 所幸, 前面 我們已經為動態注入奠定好了基礎,請看底下這個Razor Page頁面: (我們之所以從 前面 的Console App改用Razor Page,是為了要展示asp.net core中的DI之故,請務必看過 前面這篇 才能理解底下情境) 上面這個頁面是 .net core 的 Razor Page Model,如果你不熟這個架構,只會MVC,那你就暫時把它當作某個Controller來看好了,後面我們會介紹Console和MVC模式下的DI。 它的執行結果如下: 頁面被載入的時候,會運行到OnGet()方法,其中的程式碼計算出的薪資是 28800,問題來了,OnGet(…)程式碼當中沒有看到誰去new了那個計算薪資的 _SalaryFormula 類別啊? 那這個實行個體是哪裡來的? 莫非是從建構子(上面程式碼第4行)傳入的? 是的,你猜對了。 整個asp.net core框架都支援套DI服務,不管是Web...

使用IoC與DI(Dependency Injection)有何意義? (一) 它到底是甚麼?

圖片
其實我們在好幾年前,就已經談過DI(Dependency Injection)這個主題。當時這類議題被視為進階的開發概念,但如果你最近開始使用 .net core,大概已經發現DI如今已變成.net core中的基本要求。 事實上,從事教育訓練這麼多年的觀察下來,不難發現其實還是有相當多的開發人員不真的很明白,到底DI對於軟體開發有何意義? 它能帶來什麼價值? 這一篇希望能夠用一個較為具體的實例,對初學者解釋到底什麼是DI,以及它能帶來的效益。 結論 先說結論,對開發人員來說,使用DI能夠帶來 提高 可測試性(testability) 以及 提高 可擴充性 的價值,同時降低相依性,讓程式碼便於維護。 在 asp.net core當中DI如今已是基本方案,asp.net core 是以 服務(DI Services) 的形式把DI這個機制實現在框架當中。讓開發人員不管是用 razor page, MVC, 或是其他開發方式,都可以(幾乎是必須)採用DI服務。 我們很久以前就說過,『框架』本身其實就是一種限制、一種引導,誘導開發人員往某一種方向去開發程式。而如今 asp.net core 把DI納作框架的一部分,就是在引導開發人員在開發時走向某一個路線。 什麼路線呢? 就是高可測試性、低耦合以及高可擴充性,如果兩相比較,我覺得asp.net core中的DI可以為開發人員實現高可測試性這個目的的可能性大概會更高一些,估計是因為最近幾年,unit test已經成為開發領域的某種潮流。 什麼是物件相依性 但不管如何,.net core已經把DI視為基礎,而你要理解這一切,得先搞清楚什麼是物件的相依性。 我常在上架構設計課程時說,職責分離這個設計概念很容易理解,誰都知道不同職責的模塊或物件就該分離,問題是怎麼決定誰的職責是甚麼? 到底誰又該跟誰分離? 等到有一天你真的開始設計,就會發現理解是一回事,真的明白到能夠動手設計又是另一回事… 看個例子,我們先來了解一下背景需求。 假設,我們打算為企業建構一個薪資計算的功能,已知薪資計算會依據三個參數,分別是本月上班時數(WorkHours),時薪(HourlyWage),以及請假時數(PrivateDayOffHours)。 也就是說,倘若Eric本月上班 19天,每天8小時,時薪200,本月請假1天,每請假一天倒扣200元,則E...