iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
Software Development

下載器不是寫完就能跑:一個 HLS 分段式串流工具的架構與測試修練系列 第 7

Day 07:第一部回顧——爬蟲層的責任邊界,跟它不該負責的事

  • 分享至 

  • xImage
  •  

前言:爬蟲層到底該做到哪裡為止?

第一部這六天,講的都是「怎麼把爬蟲這一層設計得好維護」,但還沒明講一件事:爬蟲層的責任邊界劃在哪裡,超過這條線的事它不該碰

今日目標

  • 把前六天的內容收斂成一條清楚的責任邊界
  • 看清楚「爬蟲層不該負責的事」,避免職責蔓延
  • 為第二部(HLS 協定本身)預告接下來的責任交棒點

爬蟲層該負責的:把「不確定的外部頁面」轉成「確定的內部資料結構」

回顧這六天:Template Method 解決「不同來源結構不同,共用流程要怎麼共用」;Factory 解決「該用哪個實作,這個判斷要放哪」;正規表達式的案例解決「撈出來的資料要不要交給對應的解析器處理」;例外情境的案例解決「假設不成立時要有明確退路」;抽象化取捨的案例解決「這些設計值不值得現在做」。

這些全部指向同一件事:爬蟲層的責任,是把充滿不確定性的外部頁面,轉換成一份確定、結構化、可以被下一層信任的資料(在這個案例裡,就是「內容項目清單 + 對應的 M3U8 位置」)。

❌ vs ✅:責任蔓延 vs 責任收斂在轉換這一步

❌ 反例:爬蟲層順手做了下載

class Crawler:
    async def collect_and_download(self, url):
        items = await self.__parse_items(url)
        for item in items:
            await self.__download_m3u8(item.m3u8_url)  # 越界了

這樣寫,「解析頁面失敗」跟「下載失敗」這兩種完全不同性質的錯誤會混在同一個方法的例外裡,呼叫端沒辦法分開處理,測試也沒辦法只針對「解析邏輯對不對」單獨驗證,因為每次測試都得連帶處理下載這個外部依賴。

✅ 正例:爬蟲層只到「產出確定的資料結構」為止

class Crawler:
    async def collect(self, url) -> list[Item]:
        return await self.__parse_items(url)  # 只做到這裡

# 下載是另一層的責任
async def process(url, crawler: Crawler, downloader):
    items = await crawler.collect(url)
    for item in items:
        await downloader.download(item.m3u8_url)

為什麼這條邊界值得堅持

一旦爬蟲層越界去做下載,這一層的測試就會被迫連帶處理網路下載這個外部依賴,原本「驗證解析邏輯對不對」這種可以很快跑完的單元測試,會被拖慢、變得不穩定。把「轉換」跟「使用轉換結果」分成兩層,兩層才能各自被獨立測試——這正是第四部要講的測試策略能夠成立的前提。

今日重點回顧

  • 爬蟲層的責任:把不確定的外部頁面,轉成確定、結構化的資料
  • 責任蔓延的常見症狀:把下一步該做的事(下載、儲存)順手做掉
  • 責任邊界劃清楚,是後面測試策略能夠成立的前提

明日預告

第二部開始:進入 HLS 協定本身,先從索引清單(M3U8 playlist)的基本結構講起。


上一篇
Day 06:這層抽象值得嗎?三個來源 vs 十個來源,成本轉折點在哪
下一篇
Day 08:M3U8 索引清單的基本結構,不只是一份 URL 清單
系列文
下載器不是寫完就能跑:一個 HLS 分段式串流工具的架構與測試修練11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言