Refit
在古老的時代,國王要把詔令送往四方,往往需要派出一位信使。但這位信使總得記住每一段路線、每一條小徑,甚至還要自己翻譯當地的語言。每一次派遣,不僅耗費心力,也總有出錯的風險。
程式世界裡的我們,也常常面臨相同的窘境。每次要呼叫第三方 API,就得重複 HttpClient、手動處理序列化與反序列化,還要加上各種 Retry、Logging。久而久之,這些細節就像一張張散落的地圖,讓信使負擔沈重。
而 Refit 的出現,就像給我們一套「信使專屬的傳令書」。只要定義好任務(Interface),信使便能自動遵循指令,把訊息送達遠方,並且用我們熟悉的語言回報結果。從此,我們不必再煩惱翻譯、路線和格式的細節,只需專注於該傳遞的訊息本身。
他讓我們能夠以 Interface 來定義 怎麼串接第三方 API 。
所以我們不需要直接使用 HTTPClient,而是定義一個 Interface,Refit 會將 Interface 的方法包裝起來,處理 HTTP 請求並將 Response 數據序列化為 Interface 中指定的類型,還可以組上自製的 HttpMessageHandler 以及處理 ...
HttpClientFactory
在浩瀚的網路之海,每一次 API 呼叫,就像派出一位無聲的信使。他背著我們的訊息,穿越纜線與雲層,去敲響遠方伺服器的大門。而我們該如何訓練這些信使?如何確保他們既不迷路,也不在途中耗盡力氣?這就是 HttpClientFactory 存在的理由。
📨 A. 方法內各自 CreateClient(匿名信使)每次出征時,我們都臨時徵召一位信使,並告訴他要去的目的地與身份證明。信使們雖然每次看似「新生」,但其實都共享一條秘密通道(Handler Pool),因此不會因為頻繁占用多個港口。但缺點是每次都要重複交代路線與口令,若忘了,就會讓信使迷途。
12345678910111213141516171819202122232425262728293031public void ConfigureServices(IServiceCollection services){ services.AddHttpClient(); services.AddRazorPages();}public class LineService : ILineService ...
Socket Exhaustion - 當臨時的港口被耗盡
在浩瀚的網路之海,每一次 API 呼叫,就像放出一位無聲的信使。他揹著我們的訊息,穿越纜線、翻越路由器,終於抵達遠方的伺服器。然而,這段旅程並非沒有代價。
當信使啟程時,作業系統會替他分配一個「臨時的港口」(ephemeral port),讓他能安全啟航。但若我們過於頻繁地呼喚、過於急切地派遣信使,這些港口就會一個接一個被佔滿。直到最後,新信使無處登船——這就是 Socket Exhaustion 的隱憂。
📨 TCP 4-tuple要出海,信使需要四件通關憑證:
假設我們今天上 Google 首頁,其實就是建立一條 TCP 連線,這條連線會用到這「四件東西」來唯一識別這條通道:
項目
說明
你的 IP(來源 IP)
例如:192.168.1.100
你的 Port(來源 Port)
⚠️ 是作業系統隨機分配的,例如 51234
伺服器的 IP(目的 IP)
例如:142.250.190.46
伺服器的 Port(目的 Port)
✅ 這通常是 80(HTTP)或 443(HTTPS)
這四個合起來叫做:TCP 4-tuple就像護照、簽證、船票與碼 ...
Socket
在這個時代,我們打下一行簡單的程式碼,資料便能穿越海底電纜、飛越路由器之間的節點,抵達遙遠的伺服器。這一切對我們來說只是「一次 API 呼叫」,卻在背後上演著一段浩瀚的旅程。
想像有一位無聲的信使,他從你的程式出發,手中捧著訊息,沿著電纜與協定鋪展的道路一路前行。途中他會經過城市的路由器、跨越國界的骨幹網路、穿梭雲端的防護牆,最終抵達遙遠的伺服器大門。完成使命後,他又沿著相同的路徑回返,把遠方的回應帶回到你眼前。
這位信使,就是 Socket。他是隱形的橋樑,是程式與世界的通道。在鍵盤與螢幕的另一端,他靜靜地,卻堅定地奔走於無形的網路之海。
📨 Socket 是什麼?Socket 可以理解為「程式」與「網路」之間的連接點(endpoint)。它讓你的程式能透過 IP 和 Port 與外界通訊,發送或接收資料。
舉例來說:
當你寫了一個 Web Server,你會讓它透過一個 Socket 在 80 port 上「監聽」(listen)。
瀏覽器想連到你的網站時,會建立一個 client socket,去「連線」你的 server socket。
而 Port 是區分 ...
Redis -
鎖定一般的快取流程(單純快取)
步驟是這樣的:
先去 Redis 找資料 X,有的話直接回傳。
如果 Redis 沒有,就去主資料庫拿資料。
拿到後再放回 Redis。
回傳給使用者。
看起來很正常吧?但問題在於 「快取缺席」的那一瞬間。
問題場景
假設同一時間有 1000 個人同時來查詢資料 X。
如果資料庫只要 80ms 就能回傳,這 1000 個人雖然 Redis 沒資料,但資料庫還能勉強頂住(同時湧入 80 個請求,壓力還算可控)。
如果資料 X 需要計算 8 秒(8000ms),那麼在 Redis 還沒被「補上」之前,這 1000 個人都會同時衝進資料庫,結果資料庫要處理 8000 個請求 × 8 秒 = 64000 秒 CPU 時間。這時候你的資料庫直接爆炸,整個系統癱瘓。
這就是為什麼你約會的時候還要拿筆電救火的原因:表面上流程合理,但遇到高併發 + 重運算,會出現「快取雪崩」的災難。
進階的快取流程(加鎖)
改良的方法是「加鎖」,步驟是這樣:
先去 Redis 找資料 X,有的話直接回傳。
如果沒有,就先拿到「資料 X 的鎖」,確保只有我能進去查主資料庫。
...
Redis -
StackExchange.Redis它是由 Stack Exchange 團隊(就是經營 Stack Overflow 的那群人)開發維護的所以這個套件名字就叫做 StackExchange.Redis。
🧠 本質上,它就像是你(.NET 程式)跟 Redis 這個外部系統中間的一個翻譯官,透過這個翻譯官,對 Redis 下指令、讀寫資料、訂閱事件、操作快取。
🔧 StackExchange.Redis 幫我們做了哪些事?
建立連線(像 ConnectionMultiplexer.Connect(…))
存資料(像 db.StringSet(“key”, “value”))
取資料(像 db.StringGet(“key”))
訂閱/發布消息(Pub/Sub)
效能最佳化(自動管理連線、批次處理、壓縮)
ConnectionMultiplexerConnectionMultiplexer 是一個管理 Redis 連線的「總管」,幫你處理所有連線、發送指令、接收資料、訂閱事件等等。它會幫你:
建立一條或多條 TCP 連線到 Redis 伺服器
管理這些連 ...
Redis - 專注於低延遲的收費站
Redis單執行緒會不會撐不住高併發與其他服務相比🍂 併發問題與 Optimistic lock🍂 樂觀鎖🍂 我真的需要 WATCH + MULTI 嗎🍂 多條件一致性🍂 庫存到底該放 Redis 還是 SQL想像一條高速公路,如果有太多交流道、紅綠燈、車子搶道,雖然看起來能同時容納很多車,但實際上常常塞爆,而 Redis 的設計是,入口很多 + 收費站只有一個,但每台車過站只要 0.001 秒,除非突然來了一台「超寬超慢的車」,這麼設計是因為,Redis 幾乎只做單純的操作,例如 : 從記憶體拿資料、在記憶體改資料,並且結構非常單純(key → value),他不需要管 join、constraint、transaction 等複雜邏輯,所以它可以保證「每個操作都很短、可預期」
Redis 把所有資料放在記憶體裡,所以車子(請求)一旦進來,就能以極快的速度通過。這種設計讓 Redis 在需要低延遲的場景裡,成為最可靠的快取層。它不追求資料永遠存在(Persistence),而是保證當下的快與穩真正會壓垮 Redis 的不是請求數,而是「單一請求做太多事」,Redis 怕的不 ...
OOP vs SD
https://ithelp.ithome.com.tw/m/questions/10211504
物件導向設計 (OOD) 通常是比結構化設計 (SD) 更好的選擇。物件導向設計是一種軟體設計方法,它強調將系統分解為可重用的、相互協作的物件。這使得軟體更易於理解、擴展和維護。
現在RD的分工都很細,在開發或維護大型系統(或應用程式)的過程中,每個人可能只負責一個小部分功能,而且需求經常會因應市場環境(或老闆的喜好)不斷的變更(甚至變更到發布的前一天晚上還在變更),如果沒有用物件導向的方式來組織各個模組,那在工作的協同上勢必會遇到一大堆bug。
抽象化的過程是讓程式碼更貼近人的思維,並不會讓程式碼變複雜,反而是變得更容易理解且更好維護才是,如果你的物件導向會讓你的程式碼變複雜,那應該好好思考一下你寫的code真的是物件導向嗎?
物件導向的設計還會使效能下降 為甚麼這樣說
封裝與間接層 (Indirection)
在物件導向裡,資料和行為綁在一起,所以往往需要多一層方法呼叫。
例如:
order.Total = order.CalculateTotal();
在結構化設計可能 ...
Plugin2
https://medium.com/%E9%96%92%E8%AB%87%E8%BB%9F%E9%AB%94%E6%9E%B6%E6%A7%8B/%E9%96%92%E8%AB%87%E8%BB%9F%E9%AB%94%E6%9E%B6%E6%A7%8B-plug-in-ed2cbce7464a
https://code-maze.com/csharp-plugin-architecture-pattern/
plugin1 1plugin1 2
Plugin + Factory + Strategy 遊戲機與卡帶
paymentPlugin Pattern(外掛模式)卡帶實作Factory Method Pattern(卡帶管理員模式)Reflection 遊戲機的讀卡頭執行遊戲flowsumary在開發金流或第三方整合系統時,一定會預期到金流是無止盡在擴充的,今天要支援 LinePay,下個月要加上 ApplePay,後天客戶希望有 GooglePay、PayPal
如果每增加一種支付方式都要打開主程式去修改,就好比一台遊戲機的遊戲被寫死在機器裡,每次想玩新遊戲,就得整個流程要再改一次,想想就覺得很可怕
好的設計主軸是 遊戲機本身保持穩定,玩家只要插上不同的卡帶,就能享受不同的遊戲
必須要接受支付方式一定會一直增加,LinePay、ApplePay、GooglePay 不會是最後一個,只會是個開始,因此把「會變的部分」獨立出來,不同支付流程、API、驗簽方式,我們把它全部抽成「外掛模組(Plugin)」,而主程式只負責呼叫介面,它不關心甚麼 Pay,只知道「你是一個 Payment Plugin」,並且透過工廠(Factory)拿對卡帶,根據設定或參數,決定要載入哪一個 Plugin 實作, ...








