iT邦幫忙

2026 iThome 鐵人賽

DAY 26
0
Software Development

程式設計沒有告訴你的事:30 天破解每一個 Why系列 第 26

開始組裝 Mini Web Framework:第一步,先把巨大 Program.cs 拆掉

  • 分享至 

  • xImage
  •  

前面幾天,我們已經把 Framework 需要的很多核心概念都拆開來理解了。

有 HttpRequest。

有 HttpResponse。

有 Routing。

有 Handler。

有 Middleware。

有 Parameter Binding。

有 Result Conversion。

但現在真正回頭看專案,最大的問題反而變成:

這些東西最後要怎麼放回程式裡?

如果所有功能還是全部塞在 Program.cs,那即使功能都做出來了,也很難說我們真的做出了一個 Framework。

因為 Framework 的重點不只是:

程式可以跑。

而是:

不同責任要有清楚的邊界。

所以 Day26 的第一個目標,不是再加新功能。

而是正式開始重構專案結構。

今天想解決的問題就是:

怎麼把目前集中在 Program.cs 裡的工作,拆成比較合理的 Framework 元件?

一開始做 Server 時,Program.cs 其實很單純。

大概只是:

建立 TcpListener

Start

AcceptTcpClient

Read

Print

這種程度。

所以全部放在 Program.cs 完全沒問題。

但後來功能一路增加:

解析 Request

Routing

Handler

Response

404

HttpRequest

HttpResponse

Query

Headers

Body

Middleware

如果一直全部放在同一個地方,Program.cs 就會開始變成:

什麼都知道。

什麼都負責。

這樣其實會很難維護。

因為只要改一個功能,就可能影響其他功能。

所以今天的第一個重點是:

把「Framework 本身」和「使用 Framework 的程式」分開。

Program.cs 到底應該負責什麼?

理想上,Program.cs 不應該再直接處理底層 HTTP 細節。

它應該比較像 Framework 的使用入口。

也就是只做:

建立應用程式

註冊 Route

註冊 Middleware

啟動 Server

例如概念上可以變成:

建立 app

註冊 /hello

註冊 /products

啟動

而不是:

AcceptTcpClient

NetworkStream.Read

Split Request Line

Encoding

Write

這些細節。

換句話說:

Program.cs 應該負責「設定」

Framework 內部才負責「執行」。

第一個要拆出去的是什麼?

我覺得最適合先拆出去的是 Server。

因為目前 Program.cs 最底層的一大段工作其實都在做:

建立 TcpListener

等待 Client

讀取 bytes

把 Request 交給後續處理

這些都不是應用程式本身的商業邏輯。

所以可以先想像建立:

MiniWebServer

它負責:

Start

Listen

Accept

Read Request

Send Response

這樣 Program.cs 就不需要再碰太多 TcpListener 細節。

HttpRequest 繼續負責什麼?

HttpRequest 目前的定位可以維持:

描述這次 Request。

例如:

Method

Path

Version

Headers

Query

Body

以及:

Parse

所以:

Server

收到 Raw HTTP

交給 HttpRequest.Parse()

得到 HttpRequest

這樣 Server 不需要知道 Request Line 裡每一個欄位細節。

Router 又放哪裡?

Router 可以獨立負責:

註冊 Route

查找 Route

例如:

/hello

Hello Handler

/products

Products Handler

所以 Server 收到 HttpRequest 後:

HttpRequest

Router.Match(...)

找到 Handler

這樣 Server 也不需要自己一直 if / else。

HttpResponse 則繼續負責什麼?

HttpResponse 已經很適合負責:

StatusCode

StatusText

Headers

Body

Send()

所以最後:

Handler

產生 HttpResponse

HttpResponse.Send()

這樣 Response 的格式和 NetworkStream 寫入細節,就不用散落在其他地方。

那 Middleware 怎麼辦?

Middleware 目前先不用一次做很複雜。

Day26 的重點是先把主架構拆開。

所以可以先保留一個最小想法:

Request

Server

Middleware Pipeline

Router

Handler

HttpResponse

如果今天還沒把 Middleware 實作完整,也沒關係。

重點是先讓專案結構有空間可以放它。

專案結構可以先變成什麼?

目前可以先規劃成:

MiniWebFramework

Program.cs

HttpRequest.cs

HttpResponse.cs

Router.cs

MiniWebServer.cs

之後如果需要:

Middleware

ParameterBinder

ResultConverter

再逐步加入。

這次不是為了把檔案變多。

而是為了讓每個檔案只負責一件主要事情。

MiniWebServer 負責:

Server lifecycle。

HttpRequest 負責:

Request。

HttpResponse 負責:

Response。

Router 負責:

Routing。

Program.cs 負責:

使用 Framework。

這樣責任就開始清楚很多。

Framework 和 Application 開始分開

這一步其實很重要。

因為前面我們做的程式,大多是:

Framework 實作

應用程式邏輯

全部混在一起。

例如:

/hello

/products

這些其實是 Application 的 Route。

但:

TcpListener

Request Parsing

Response Formatting

這些則是 Framework 的工作。

今天開始要把兩者分開。

也就是:

Application

告訴 Framework 有哪些 Route

Framework

負責收到 Request 後找到 Route 並執行

這個角色分離,會讓整個專案更像真的 Framework。

為什麼這樣才像 Framework?

因為 Framework 的使用者不應該需要知道:

底層 TCP 怎麼運作。

他只需要知道:

我要註冊什麼 Route。

例如概念上:

MapGet("/hello", ...)

真正收到 Request 後:

Accept Client

Parse Request

Match Route

Invoke Handler

Send Response

全部由 Framework 處理。

這就是 Framework 的價值。

把複雜度藏在內部。

只把必要的介面留給使用者。


以前的我:

Program.cs

整個 Server

現在的我:

Program.cs

Framework 使用入口

Framework 內部
├── MiniWebServer
├── HttpRequest
├── Router
└── HttpResponse

這代表 Program.cs 不再等於 Framework。

它只是:

使用 Framework 的地方。

真正 Framework 的能力,開始移到自己的 Class 裡。


今天最大的發現是:

「做出 Framework」和「做出可以跑的 Server」不是完全一樣的事情。

一個可以跑的 Server,可以全部寫在一支 Program.cs。

但 Framework 需要額外思考:

哪些細節應該被隱藏?

哪些 API 應該暴露?

哪個元件負責哪件事?

使用者應該怎麼操作?

這些問題才真正開始碰到 Framework Design。

最後成品的第一步,不是立刻加入更多功能。

而是先把目前巨大 Program.cs 裡不同責任拆開。

讓 Server、Request、Router、Response 都各自有清楚的位置。

接著才有辦法在後面幾天把 Middleware、Binding、Result Conversion 等功能慢慢接回來。

🛠 與 Mini Web Framework 的關聯

Day26 開始,專案要正式從:

一支可以跑的 Server 程式

變成:

一組可以被使用的 Framework 元件。

方向可以先變成:

Program.cs

設定 Framework

MiniWebServer

啟動 TCP Server

HttpRequest

解析 Request

Router

找 Handler

HttpResponse

送 Response

最後整個流程:

Browser

MiniWebServer

HttpRequest

Router

Handler

HttpResponse

Browser

這會成為最後幾天整合的基礎。

今天的實作目標

今天實作時,我不打算一次完成所有 Framework 元件。

Day26 的目標只需要做到:

第一,把 Server 相關程式從 Program.cs 移出去。

第二,建立 Router 類別。

第三,讓 Program.cs 開始變簡單。

第四,確認 /hello、/products、404 仍然正常。

也就是:

重構前功能正常

拆檔案

重構後功能仍然正常

這就是 Day26 最重要的驗證。

因為今天不是在增加功能。

而是在改善 Framework 的結構。

結尾

前面 25 天,我一直在問:

Framework 為什麼需要這個?

為什麼需要那個?

到了 Day26,問題終於開始變成:

我真的要怎麼把它做出來?

今天第一步不是寫更多功能。

而是把前面累積在 Program.cs 裡的責任重新整理。

Server 做 Server 的事。

Request 做 Request 的事。

Router 做 Routing。

Response 做 Response。

Program.cs 則開始只負責告訴 Framework:

我要哪些 Route。

我要怎麼啟動。

如果這一步可以完成,代表我們不再只是在:

寫一個 Server。

而是真的開始:

設計一個 Framework。


當 Server、Request、Router、Response 都拆開之後,下一個問題就是:

它們真的可以順利合作嗎?

Framework 收到 Request 後,怎麼把:

HttpRequest

Router

Handler

HttpResponse

真正串成一條可以運作的流程?


上一篇
Framework 的核心零件都有了,最後到底該怎麼把它們組起來?
下一篇
把 Router、Handler、Response 接起來:Framework 的核心流程終於成形
系列文
程式設計沒有告訴你的事:30 天破解每一個 Why30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言