<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>State-Stream on Tarragon</title><link>https://tarrragon.github.io/blog/tags/state-stream/</link><description>Recent content in State-Stream on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Mon, 20 Jul 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/state-stream/index.xml" rel="self" type="application/rss+xml"/><item><title>State Stream（狀態流）</title><link>https://tarrragon.github.io/blog/ddd/knowledge-cards/state-stream/</link><pubDate>Thu, 16 Jul 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/ddd/knowledge-cards/state-stream/</guid><description>&lt;p>狀態流是持續發布「某份資料當前值」的觀測載體：新值蓋過舊值、只有最新值有意義、錯過中間值無代價——下一次快照涵蓋一切。與 &lt;a href="https://tarrragon.github.io/blog/ddd/knowledge-cards/domain-event/" data-link-title="Domain Event" data-link-desc="系統裡出現「為了讓某頁刷新而補發事件」或「監聽端掛全事件過濾器」時使用。domain event 是已發生的業務事實——過去式命名、發布後不可變、錯過代表事實遺失。">domain event&lt;/a> 的分界在消費者的問題：狀態流回答「現在是什麼」、event 回答「發生了什麼」。與 &lt;a href="https://tarrragon.github.io/blog/ddd/knowledge-cards/snapshot/" data-link-title="Snapshot" data-link-desc="歷史記錄是否應該凍結當時狀態時使用。Snapshot 是某一時刻的狀態複本——歷史不隨現在的資料漂移。">snapshot&lt;/a> 的差別在時間方向：snapshot 凍結某一刻、保證歷史不隨現在漂移；狀態流永遠指向現在、舊值被覆蓋是設計語意。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>狀態流是 &lt;a href="https://tarrragon.github.io/blog/ddd/knowledge-cards/observation-outlet/" data-link-title="Observation Outlet（觀測出口）" data-link-desc="repository 只有 pull 介面、衍生視圖靠補償刷新，考慮補「資料變了」的推送能力時使用。觀測出口是 pull 介面的 push 對應——能力橫跨三層、歸屬由各層的表達語言決定。">觀測出口&lt;/a> 的載體形態：觀測出口定義「資料變了、我能告訴你」這個能力歸屬哪一層、狀態流定義這個通知的語意——連續快照、不是離散事實。它的涵蓋面是寫入操作的集合：emit 掛在每個寫入方法尾端、新路徑必然經過、涵蓋不靠任何人記得發——與 domain event「業務語意決定發布點、逐事實設計」的涵蓋方式正交。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>系統缺狀態流出口時，補償的形狀是訊號：導航返回點出現手動 reload、為了讓某頁刷新而補發事件、監聽端掛全事件過濾器。事件被誤用成狀態流的完整判讀訊號表在 &lt;a href="https://tarrragon.github.io/blog/ddd/domain-event-vs-state-stream/" data-link-title="domain event 與狀態流" data-link-desc="為了讓某個畫面刷新而補發事件、或監聽端掛著全事件過濾器時使用。事件記錄離散事實、狀態流發布連續觀測——判準是消費者問「發生了什麼」還是「現在是什麼」；載體借用的代價是涵蓋面靠枚舉維持。">domain event 與狀態流&lt;/a>。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>狀態流承擔「畫面、快取、衍生視圖對資料當前值的觀測」，錯過的代價為零是它跟 event 不可互換的原因——需要逐筆事實（審計、下游流程）的消費者拿快照會斷檔。載體選用判準展開見 &lt;a href="https://tarrragon.github.io/blog/ddd/domain-event-vs-state-stream/" data-link-title="domain event 與狀態流" data-link-desc="為了讓某個畫面刷新而補發事件、或監聽端掛著全事件過濾器時使用。事件記錄離散事實、狀態流發布連續觀測——判準是消費者問「發生了什麼」還是「現在是什麼」；載體借用的代價是涵蓋面靠枚舉維持。">domain event 與狀態流&lt;/a>、實作選型（broadcast、初始值、dispose）見 &lt;a href="https://tarrragon.github.io/blog/work-log/flutter_streamprovider_wraps_repository_watch/" data-link-title="StreamProvider 包 repository watch stream — broadcast、初始值、dispose 實作點" data-link-desc="repository 要補 Stream 觀測出口、接給 Riverpod 消費時使用。訂閱模型選 broadcast 還是單訂閱、新訂閱者拿不拿得到當下狀態、controller 誰負責關——每個問題各有一個會靜默失效的預設答案。">StreamProvider 包 repository watch stream&lt;/a>。&lt;/p></description><content:encoded><![CDATA[<p>狀態流是持續發布「某份資料當前值」的觀測載體：新值蓋過舊值、只有最新值有意義、錯過中間值無代價——下一次快照涵蓋一切。與 <a href="/blog/ddd/knowledge-cards/domain-event/" data-link-title="Domain Event" data-link-desc="系統裡出現「為了讓某頁刷新而補發事件」或「監聽端掛全事件過濾器」時使用。domain event 是已發生的業務事實——過去式命名、發布後不可變、錯過代表事實遺失。">domain event</a> 的分界在消費者的問題：狀態流回答「現在是什麼」、event 回答「發生了什麼」。與 <a href="/blog/ddd/knowledge-cards/snapshot/" data-link-title="Snapshot" data-link-desc="歷史記錄是否應該凍結當時狀態時使用。Snapshot 是某一時刻的狀態複本——歷史不隨現在的資料漂移。">snapshot</a> 的差別在時間方向：snapshot 凍結某一刻、保證歷史不隨現在漂移；狀態流永遠指向現在、舊值被覆蓋是設計語意。</p>
<h2 id="概念位置">概念位置</h2>
<p>狀態流是 <a href="/blog/ddd/knowledge-cards/observation-outlet/" data-link-title="Observation Outlet（觀測出口）" data-link-desc="repository 只有 pull 介面、衍生視圖靠補償刷新，考慮補「資料變了」的推送能力時使用。觀測出口是 pull 介面的 push 對應——能力橫跨三層、歸屬由各層的表達語言決定。">觀測出口</a> 的載體形態：觀測出口定義「資料變了、我能告訴你」這個能力歸屬哪一層、狀態流定義這個通知的語意——連續快照、不是離散事實。它的涵蓋面是寫入操作的集合：emit 掛在每個寫入方法尾端、新路徑必然經過、涵蓋不靠任何人記得發——與 domain event「業務語意決定發布點、逐事實設計」的涵蓋方式正交。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>系統缺狀態流出口時，補償的形狀是訊號：導航返回點出現手動 reload、為了讓某頁刷新而補發事件、監聽端掛全事件過濾器。事件被誤用成狀態流的完整判讀訊號表在 <a href="/blog/ddd/domain-event-vs-state-stream/" data-link-title="domain event 與狀態流" data-link-desc="為了讓某個畫面刷新而補發事件、或監聽端掛著全事件過濾器時使用。事件記錄離散事實、狀態流發布連續觀測——判準是消費者問「發生了什麼」還是「現在是什麼」；載體借用的代價是涵蓋面靠枚舉維持。">domain event 與狀態流</a>。</p>
<h2 id="設計責任">設計責任</h2>
<p>狀態流承擔「畫面、快取、衍生視圖對資料當前值的觀測」，錯過的代價為零是它跟 event 不可互換的原因——需要逐筆事實（審計、下游流程）的消費者拿快照會斷檔。載體選用判準展開見 <a href="/blog/ddd/domain-event-vs-state-stream/" data-link-title="domain event 與狀態流" data-link-desc="為了讓某個畫面刷新而補發事件、或監聽端掛著全事件過濾器時使用。事件記錄離散事實、狀態流發布連續觀測——判準是消費者問「發生了什麼」還是「現在是什麼」；載體借用的代價是涵蓋面靠枚舉維持。">domain event 與狀態流</a>、實作選型（broadcast、初始值、dispose）見 <a href="/blog/work-log/flutter_streamprovider_wraps_repository_watch/" data-link-title="StreamProvider 包 repository watch stream — broadcast、初始值、dispose 實作點" data-link-desc="repository 要補 Stream 觀測出口、接給 Riverpod 消費時使用。訂閱模型選 broadcast 還是單訂閱、新訂閱者拿不拿得到當下狀態、controller 誰負責關——每個問題各有一個會靜默失效的預設答案。">StreamProvider 包 repository watch stream</a>。</p>
]]></content:encoded></item><item><title>Event-Carried State Transfer</title><link>https://tarrragon.github.io/blog/ddd/knowledge-cards/event-carried-state-transfer/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/ddd/knowledge-cards/event-carried-state-transfer/</guid><description>&lt;p>event-carried state transfer 是刻意讓 &lt;a href="https://tarrragon.github.io/blog/ddd/knowledge-cards/domain-event/" data-link-title="Domain Event" data-link-desc="系統裡出現「為了讓某頁刷新而補發事件」或「監聽端掛全事件過濾器」時使用。domain event 是已發生的業務事實——過去式命名、發布後不可變、錯過代表事實遺失。">domain event&lt;/a> 的 payload 攜帶足量的當前狀態、不只是「發生了什麼」的事實本身。目的是讓下游服務收到事件後就能拿到完整資訊、不必回頭同步查詢來源系統——payload 帶全量狀態在這裡是設計選擇，不是把事件當狀態通知的誤用。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>這個設計只在跨服務、跨信任邊界的情境下成立。同進程情境下，事件開始攜帶全量狀態通常是載體錯位的訊號——消費者真正要問的是「現在是什麼」，正確載體是 &lt;a href="https://tarrragon.github.io/blog/ddd/knowledge-cards/state-stream/" data-link-title="State Stream（狀態流）" data-link-desc="畫面刷新靠補償、或考慮拿既有事件當刷新訊號時使用。狀態流是持續發布「資料當前值」的觀測載體——新值蓋過舊值、錯過中間值無代價，回答「現在是什麼」。">state stream&lt;/a> 而非塞胖的事件；跨服務時「回頭查詢來源」本身有同步耦合的成本，event-carried state transfer 用胖 payload 換掉這個成本，是同一個訊號在不同信任邊界下的相反判讀，完整推導見 &lt;a href="https://tarrragon.github.io/blog/ddd/domain-event-vs-state-stream/" data-link-title="domain event 與狀態流" data-link-desc="為了讓某個畫面刷新而補發事件、或監聽端掛著全事件過濾器時使用。事件記錄離散事實、狀態流發布連續觀測——判準是消費者問「發生了什麼」還是「現在是什麼」；載體借用的代價是涵蓋面靠枚舉維持。">domain event 與狀態流&lt;/a>。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>事件的 payload 從「哪本書、什麼時間」這類事實欄位，長出「現在的全貌」這類當前狀態欄位，是判讀的觸發點；判讀不看 payload 胖不胖，看消費者是不是跟事件來源在同一個信任邊界——邊界內是錯位、邊界外是正當設計。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>event-carried state transfer 換來的是下游服務不必為了拿到完整資訊而同步呼叫來源，代價是事件 payload 的 schema 跟著狀態演進、下游要一起處理相容性。這個代價只有在真的省下跨服務同步查詢時才划算，同進程情境沒有這筆成本可省，應優先考慮 &lt;a href="https://tarrragon.github.io/blog/ddd/knowledge-cards/state-stream/" data-link-title="State Stream（狀態流）" data-link-desc="畫面刷新靠補償、或考慮拿既有事件當刷新訊號時使用。狀態流是持續發布「資料當前值」的觀測載體——新值蓋過舊值、錯過中間值無代價，回答「現在是什麼」。">state stream&lt;/a>。&lt;/p></description><content:encoded><![CDATA[<p>event-carried state transfer 是刻意讓 <a href="/blog/ddd/knowledge-cards/domain-event/" data-link-title="Domain Event" data-link-desc="系統裡出現「為了讓某頁刷新而補發事件」或「監聽端掛全事件過濾器」時使用。domain event 是已發生的業務事實——過去式命名、發布後不可變、錯過代表事實遺失。">domain event</a> 的 payload 攜帶足量的當前狀態、不只是「發生了什麼」的事實本身。目的是讓下游服務收到事件後就能拿到完整資訊、不必回頭同步查詢來源系統——payload 帶全量狀態在這裡是設計選擇，不是把事件當狀態通知的誤用。</p>
<h2 id="概念位置">概念位置</h2>
<p>這個設計只在跨服務、跨信任邊界的情境下成立。同進程情境下，事件開始攜帶全量狀態通常是載體錯位的訊號——消費者真正要問的是「現在是什麼」，正確載體是 <a href="/blog/ddd/knowledge-cards/state-stream/" data-link-title="State Stream（狀態流）" data-link-desc="畫面刷新靠補償、或考慮拿既有事件當刷新訊號時使用。狀態流是持續發布「資料當前值」的觀測載體——新值蓋過舊值、錯過中間值無代價，回答「現在是什麼」。">state stream</a> 而非塞胖的事件；跨服務時「回頭查詢來源」本身有同步耦合的成本，event-carried state transfer 用胖 payload 換掉這個成本，是同一個訊號在不同信任邊界下的相反判讀，完整推導見 <a href="/blog/ddd/domain-event-vs-state-stream/" data-link-title="domain event 與狀態流" data-link-desc="為了讓某個畫面刷新而補發事件、或監聽端掛著全事件過濾器時使用。事件記錄離散事實、狀態流發布連續觀測——判準是消費者問「發生了什麼」還是「現在是什麼」；載體借用的代價是涵蓋面靠枚舉維持。">domain event 與狀態流</a>。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>事件的 payload 從「哪本書、什麼時間」這類事實欄位，長出「現在的全貌」這類當前狀態欄位，是判讀的觸發點；判讀不看 payload 胖不胖，看消費者是不是跟事件來源在同一個信任邊界——邊界內是錯位、邊界外是正當設計。</p>
<h2 id="設計責任">設計責任</h2>
<p>event-carried state transfer 換來的是下游服務不必為了拿到完整資訊而同步呼叫來源，代價是事件 payload 的 schema 跟著狀態演進、下游要一起處理相容性。這個代價只有在真的省下跨服務同步查詢時才划算，同進程情境沒有這筆成本可省，應優先考慮 <a href="/blog/ddd/knowledge-cards/state-stream/" data-link-title="State Stream（狀態流）" data-link-desc="畫面刷新靠補償、或考慮拿既有事件當刷新訊號時使用。狀態流是持續發布「資料當前值」的觀測載體——新值蓋過舊值、錯過中間值無代價，回答「現在是什麼」。">state stream</a>。</p>
]]></content:encoded></item></channel></rss>