Showing posts with label dependency_injection. Show all posts
Showing posts with label dependency_injection. Show all posts

Tuesday, February 16, 2021

Clojure 程式開發的依賴注入

Clojure 的世界裡,常用的依賴注入 (dependency injection) 手法主要有五種:

  • 依賴注入應用於函數 (function) 
  • 依賴注入應用於命名空間 (namespace)
  • 依賴注入應用於攔截器 (interceptor)
  • 依賴注入應用於網站處理器 (web handler)
  • 依賴注入應用於 Java program 的物件工廠 (factory)

這五種手法都頗為重要:

  • 第一種非常的常見,可以算是基本的要求。
  • 第二種,在使用 REPL workflow 就會應用到,Luminus 搭配的 mount 就是例子。
  • 第三種可以提高程式碼的可讀性、可預測性。因為條件限制 (constraints) 多,可讀性就變好。通常是將 web handler 之後會依賴的 component 透過攔截器注入到 request 裡。
  • 第四種可以看成是第三種的變型:在生成 web handler 的時候,注入依賴。
  • 第五種則應用於 Clojure/Java interoperation 。當要利用 java library 的時候,有時候既有的 java library 有預留可以注入的 factory pattern 。這時候,如果覺得既有的 java library 不夠好用,想做一些微調整的話,就可以考慮使用 Clojure 的關鍵字 reify 去生成新的 factory 來給 java library 使用。於是,Clojure wrapper 包覆的 java library 就是有微調過的版本。

Tuesday, September 4, 2018

Testability/Dependency Injection in Clojure

在 OOP 語言的時候,因為要處理「可測試性」的問題,常常需要去考慮 dependency injection。但是, Clojure 已經有了 with-redefs 這種可以將任意的 function 都變成 software seams 的 language syntax 了,還需要特別寫 DI 嗎?

上網查了一下,各家有各家的說法,我個人比較認同的說法是這樣子:
原則上不太需要用 DI 去處理 external dependency 的問題,用 with-redefs 即可以。然而,如果某個外部資源它有 life cycle management 的問題,最好要用 component 或是 mount 來處理。

要達成 Testability 不一定要用 DI。有一篇文章 Testing the Clojure way 指出了這一點:
如果在 C# 之類的靜態語言,要做出類似 with-redefs 的語意的話,則需要用 preprocessing seams 的技巧來替換 dependency

再從另一個觀點來看,在 let over lambda 一書指出 let over lambda 其實就是 object 。而 lambda over let over lambda 可以看成是 anonymous class 。順著這個邏輯去想, dependency injection 也可以視為是 higher order function 的一種語意應用。

Thursday, October 12, 2017

在 Golang 裡使用類似 Clojure 的 with-redefs 技巧

在寫 Golang 的 unit test 的時候,我覺得很不方便的一點就是沒有辦法像 clojure 一樣,利用 with-redefs 將 symbol 重新定義,讓本來有外部依賴的函數可以很快地被測試。但是,公司的資深工程師 Mike 教了我一招。

基本的概念就是這樣子:
1. 在 Golang 裡,可以被重新定義的東西就是 global variable 。
2. 如果要測的某個函數,它本身沒有寫好依賴注入之類的東西,又恰好呼叫了一個有 complex dependency 的函數。就把這個有 complex dependency 的函數用 global variable 來加上一層間接性。

Thursday, August 18, 2016

依賴注入 - dependency injection

寫單元測試時,常常會遇到一問題,原始的程式碼本身的結構,難以加入單元測試。

最近我遇到了一個問題,我寫的程式會呼叫 git clone ,而 git clone 在網路環境不佳時,甚至會執行超過24小時,將程式的 go routine 整個卡住。所以解法就是需要將 golang 的外部指令呼叫,改成有 timeout 的。

要加上這個 timeout 並不難,困難點是,要如何測試這個功能?因為其實要模擬出 git clone 長時間執行的環境,並不是很簡單的事。

解法是這樣子:
加上這個功能時,必須將這個「為指令加上 timeout 功能」實作成一個獨立的函數,使它的功能獨立,並不「依賴」於 git clone 。換言之,「 git clone 」對應的指令,會成為這個函數的輸入變數(input argument),由外部「注入」。於是這個功能就可以獨立地來寫單元測試來測。測試它的時候,就可以用「 sleep 500 」對應的指令,來做為它的輸入變數(input argument)

原始程式碼的修改
新增的程式碼和單元測試