<?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>程式碼區塊 on Tarragon</title><link>https://tarrragon.github.io/blog/tags/%E7%A8%8B%E5%BC%8F%E7%A2%BC%E5%8D%80%E5%A1%8A/</link><description>Recent content in 程式碼區塊 on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Tue, 29 Sep 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/%E7%A8%8B%E5%BC%8F%E7%A2%BC%E5%8D%80%E5%A1%8A/index.xml" rel="self" type="application/rss+xml"/><item><title>散文裡夾了一段程式，就把程式與逐行解釋移進區塊；推導留在散文</title><link>https://tarrragon.github.io/blog/report/code-fragments-in-prose-make-readers-reassemble/</link><pubDate>Tue, 29 Sep 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/report/code-fragments-in-prose-make-readers-reassemble/</guid><description>&lt;p>散文段落的職責是推導，程式碼區塊的職責是讓讀者整段看、整段複製。一段散文把同一段查詢或指令的零件——條件、子句、關鍵字、執行計畫的輸出——一個個用行內程式碼嵌進句子，讀者就得一邊讀推導、一邊在腦中把那些零件組回原本的程式，而組回來的程式在頁面上從來沒有完整出現過。修法是分兩層：&lt;strong>程式與只屬於某一行的解釋進區塊，寫成那一行旁邊的註解；跨行的推導與它對論證的意義留在散文。&lt;/strong>&lt;/p>
&lt;h2 id="失效的形態">失效的形態&lt;/h2>
&lt;p>一篇 SQL 教材說明靜態分析判得出哪一種錯法，原文是一整段散文，行內程式碼十幾處：&lt;/p>
&lt;blockquote>
&lt;p>「不等於五」的錯法是它判得出來的例子。&lt;code>WHERE 評價.星等 &amp;lt;&amp;gt; 5&lt;/code> 對外連接補上 &lt;code>NULL&lt;/code> 的列判成未知，那些列全數被 &lt;code>WHERE&lt;/code> 濾掉，所以 &lt;code>LEFT JOIN&lt;/code> 為了保留沒有評價的訂單而補出來的列一列都留不住：這段查詢與把 &lt;code>LEFT JOIN&lt;/code> 改成 &lt;code>JOIN&lt;/code> 的版本在任何資料上都回同一批列。……PostgreSQL 的 &lt;code>EXPLAIN&lt;/code> 對「不等於五」那段查詢印的是 &lt;code>Hash Join&lt;/code>，對正解印的是 &lt;code>Hash Left Join&lt;/code>。……評價表的訂單編號在建表時沒有宣告 &lt;code>NOT NULL&lt;/code>，表結構已經說了那一欄可能是 &lt;code>NULL&lt;/code>，而子查詢只要交出一個 &lt;code>NULL&lt;/code>，&lt;code>NOT IN&lt;/code> 對每一列都判不成真。&lt;/p>&lt;/blockquote>
&lt;p>這一段講的是兩段查詢、兩份執行計畫、一份建表語句，五段程式沒有一段完整出現，全部拆成零件散在句子裡。每一句單獨看都正確，讀者要做的卻是把 &lt;code>WHERE 評價.星等 &amp;lt;&amp;gt; 5&lt;/code>、&lt;code>LEFT JOIN&lt;/code>、&lt;code>Hash Join&lt;/code> 分別放回它們所屬的那段程式，再回頭理解句子在說什麼。&lt;/p>
&lt;p>改寫後，散文只留推導（這段查詢寫了外連接而篩選條件讓補出來的列留不住、等價由三值邏輯決定、最佳化器改寫時不產生警告），兩段查詢與它們的 &lt;code>EXPLAIN&lt;/code> 並列在一個區塊，每一行的註解寫這一行判成什麼、這份計畫代表什麼；建表語句與 &lt;code>NOT IN&lt;/code> 查詢並列在另一個區塊，因為風險由兩者合起來決定。&lt;/p>
&lt;h2 id="跟既有規則的衝突與調和">跟既有規則的衝突與調和&lt;/h2>
&lt;p>&lt;code>compositional-writing&lt;/code> 的〈示範指令〉原本寫「推導與機制：註解裝標籤，機制寫散文」。照字面，上面那段的每一句都是機制，應該留在散文——那正是失效的來源。規則要分的是&lt;strong>解釋的作用範圍&lt;/strong>：只屬於某一行的解釋（這一行做什麼、這個值判成什麼、這行輸出代表什麼）離開那一行就要讀者自己對回去，所以寫成那一行的註解；跨行成立的道理與它對論證的意義沒有單一的一行可以附著，所以寫散文。&lt;/p>
&lt;p>同一處另有一條「錯誤用法不進區塊」，理由是區塊是可以複製的位置。錯法本身是主題的時候（診斷、錯法與正解的對照）這條不適用：錯的寫法要完整出現才讀得出它錯在哪，處置是進區塊、用上方整行註解標明它是錯的、與正解並列。&lt;/p>
&lt;h2 id="偵測">偵測&lt;/h2>
&lt;p>計數掃得到候選：去掉程式碼區塊之後，一個散文段落裡的行內程式碼達到十處以上。在全站教學內容跑一次有 57 段，linux、backend、llm 最多。&lt;/p>
&lt;p>計數分不出兩種情形，命中之後逐段問：&lt;strong>這些行內程式碼拼起來，是不是一段讀者該整塊看的程式（一個查詢、一條指令、一段輸出）。&lt;/strong> 各自是獨立名字的不必移——欄位名、函式名、設定鍵、檔案路徑被當成名詞提到；一整串工具名被列舉的，是清單的問題，改成條列或表格。&lt;/p>
&lt;h2 id="全站掃過一次之後">全站掃過一次之後&lt;/h2>
&lt;p>候選段落 45 段（去區塊後單段行內程式碼十處以上、且在檔案裡唯一），分四批交給改寫者，判定要改 16 段，主 session 退回一段、實際改 15 段；不改的多數是欄位名、列舉值、設定鍵、按鍵這類各自獨立的名字，以及已經整條寫在行內的單一指令。&lt;/p>
&lt;p>改寫者回報了幾種規則原先沒寫到的形態，下面三種的處置已寫進 &lt;code>demonstrating-commands.md&lt;/code>：同一段程式已經在前後文的區塊裡（逐行解釋併進既有區塊的註解，不重貼）；原文只描述了程式、沒給完整寫法（區塊只放原文給得出的部分，選項清單與測試結果用 &lt;code>text&lt;/code> 區塊，不補指令）；幾條沒有操作對象的短指令（&lt;code>chmod 440&lt;/code> 各給不同的檔而原文沒寫檔名，放進區塊會變成跑不起來的指令，這一段退回不改）。&lt;/p>
&lt;p>最值得記的是另一種：&lt;strong>把散文裡的零件搬回區塊之後，程式與散文對不上。&lt;/strong> 一篇 Firestore 安全規則的散文寫「&lt;code>update&lt;/code> 兩者都要看」（寫入前的 &lt;code>resource.data&lt;/code> 與寫入後的 &lt;code>request.resource.data&lt;/code>），而上方骨架的 &lt;code>allow update, delete&lt;/code> 只檢查了寫入前的 &lt;code>ownerId&lt;/code>——擁有者可以把 &lt;code>ownerId&lt;/code> 改成別人，這是一個授權漏洞。散文把程式拆成零件的時候，兩者的矛盾沒有位置並排出現；逐行解釋要寫成那一行的註解時，註解與它旁邊的條件對不上。修法是把骨架的 &lt;code>update&lt;/code> 與 &lt;code>delete&lt;/code> 拆開，&lt;code>update&lt;/code> 加上寫入後的檢查。這跟 &lt;a href="https://tarrragon.github.io/blog/report/unnamed-halves-are-unextracted-variables/" data-link-title="切開一個集合之前先寫切分的依據，再替每一塊命名；「一部分」「另一半」是還沒抽出來的變數" data-link-desc="文章用「一部分交得出去」「交不出去的那一半」「那一側」指稱一個被切開的集合，讀者說不出每一塊是什麼、為什麼這樣切時回來讀">#367&lt;/a> 命名時發現寫反的論斷是同一種現象：排版與命名都逼作者把一個原本可以不決定的對應寫死。&lt;/p>
&lt;h2 id="計數掃不到的形態散文描述了一段頁面上沒出現的程式">計數掃不到的形態：散文描述了一段頁面上沒出現的程式&lt;/h2>
&lt;p>同一篇的第二輪改寫找到另一種形態，行內程式碼每段最多五處，十處的門檻掃不到。這一種&lt;strong>描述一段頁面上從沒出現的程式&lt;/strong>；〈失效的形態〉那段靜態分析的例子則是把現成的程式拆成零件。這一種的例子：「訂單 101 多一則三星之後，同一段回的是 101」（改過資料的那個版本沒寫出來）、「補 &lt;code>OR 評價.星等 IS NULL&lt;/code> 也修不掉」（補上條件的那段查詢沒寫出來）、「&lt;code>NOT IN&lt;/code> 展開之後是『不等於 101，而且不等於 &lt;code>NULL&lt;/code>』」（展開式用散文轉述）、「同一句換成 &lt;code>NOT EXISTS&lt;/code> 回的仍然是 102」、「替 101 再加一則評價之後把訂單接上評價再加總……總額變成 1100」。讀者要自己寫出那段程式才驗證得了句子，而寫的人也沒有被逼著寫出來：最後一例寫成程式時才要決定連接是 &lt;code>LEFT&lt;/code> 還是內連接——內連接在原本的資料上加總是 300，不是句中的 800；同一篇另一處提到「五張訂單加七則評價」的反例資料，那份資料在頁面上根本不存在，寫出來、跑過之後才發現原文列的資料狀態與三種錯法需要的對不上。&lt;/p>
&lt;p>偵測靠句型：資料變體（「多一則……之後」「再加一則……之後」）、改寫變體（「換成 X 回」「補 X 也修不掉」）與展開式（「展開之後」「展開成」）。&lt;code>rg '(多|加|再加|刪掉?|改成)[一兩]?[則列筆張個][^。]{0,20}之後|換成[^。]{1,20}回|展開(之後|成)|也修不掉'&lt;/code> 在那一篇的改前版本命中全部五段；全站教學內容 89 檔 113 處，是候選不是判決——描述的變體已經寫在鄰近區塊裡的、或只是一句敘事的不必動。&lt;/p>
&lt;p>處置是把那段程式與那份資料寫出來、實際跑一次，各資料變體的結果寫成區塊註解（&lt;code>-- 共用資料：102&lt;/code>、&lt;code>-- 訂單 101 多一則三星之後：101&lt;/code>），散文只留這些結果對論證的意義。這跟上面「原文只描述了程式、沒給完整寫法時不補」的差別在能不能跑：改寫者手上沒有環境時，補出來的程式讀起來可以執行而從來沒被跑過；作者能跑的時候，寫出來並跑過就是修法，而跑的這一步常常就是找到錯的那一步。&lt;/p>
&lt;p>SQL 分類其餘 23 篇接著逐篇檢查一次（與抽變數一起查），改了 138 處，多數是這一種：「換成 X 回」「改放 &lt;code>WHERE&lt;/code>」「多一張訂單之後」「給出兩個不同的計畫」這類句子描述的程式都寫成了區塊，而句型 pattern 只抓到其中一小部分——「換成 &lt;code>JOIN&lt;/code>，結果一個字都沒有變」「若換成 INNER」「加上引號之後」都不在 pattern 裡，要逐篇讀。寫成程式跑過之後對出十幾處內容錯，每一處在散文裡都讀得通：自連接找每組最大值時「在子查詢裡加一句 &lt;code>IS NOT NULL&lt;/code>」攔不住金額是 &lt;code>NULL&lt;/code> 的那一列（要寫在外層）；&lt;code>CREATE INDEX ON 顧客(姓名 COLLATE NOCASE)&lt;/code> 在 SQLite 是語法錯誤；&lt;code>NO ACTION&lt;/code> 允許同一交易裡先刪父列，只在約束宣告成 &lt;code>DEFERRABLE&lt;/code> 時成立；一段 MySQL 範例的 &lt;code>INSERT&lt;/code> 給了三個值而表有四欄；權限範例照頁面順序執行時 &lt;code>GRANT&lt;/code> 由剛切換過去的角色自己發出而被拒絕；「漏掉分區」的錯版固定少報，其實取決於同一天兩列誰排在前面，換個排法就同時多報與少報；「兩則錯誤訊息各自寫出了理由」而實際的訊息只說了不准。&lt;/p>
&lt;h2 id="論述基礎與限制">論述基礎與限制&lt;/h2>
&lt;p>依據是一段改寫與一次全站掃描（45 段候選、15 段改寫），加上同一篇第二輪找到的五段描述式形態；描述式的句型 pattern 只在那一篇上驗過命中率，全站 113 處候選還沒逐處判定。十處是取來縮小候選的門檻，不是判定條件：五處行內程式碼就拼成一段查詢的段落一樣違規，二十處檔案路徑的段落可能合規。&lt;/p>
&lt;h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/literal-operand-hides-the-change-point/" data-link-title="示範指令的引數要說明，寫成字面值的那些最不像需要說明" data-link-desc="文章的指令讀者照抄跑得起來、換成自己的路徑或套件時卻不知道要改哪裡、也看不出兩種寫法差在哪時回來讀">#360 示範指令的引數&lt;/a>——那一張管區塊裡的字面值有沒有說明；本卡管該進區塊的程式有沒有進去。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/unnamed-halves-are-unextracted-variables/" data-link-title="切開一個集合之前先寫切分的依據，再替每一塊命名；「一部分」「另一半」是還沒抽出來的變數" data-link-desc="文章用「一部分交得出去」「交不出去的那一半」「那一側」指稱一個被切開的集合，讀者說不出每一塊是什麼、為什麼這樣切時回來讀">#367 切開一個集合之前先寫切分的依據&lt;/a>——同一段改寫先做的那件事：先替「靜態分析」命名，再把它判得出什麼示範出來；本卡處理的是那個示範怎麼排。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/report/positioning-decides-form-before-any-rule-applies/" data-link-title="定位決定體例，而共用的寫作規範會把一個 surface 的體例搬到另一個上" data-link-desc="同一套寫作規範同時服務 agent 指令、人類教材與程式碼註解時，用來判斷某一條規則該不該套在手上這份稿件上">#302 定位決定體例&lt;/a>——那一張記下規則的觸發條件比判斷標準先生效；「推導與機制寫散文」照字面觸發在逐行解釋上，是同一種失效。&lt;/li>
&lt;/ul>
&lt;h2 id="判讀徵兆">判讀徵兆&lt;/h2>
&lt;ul>
&lt;li>一個散文段落裡，同一段查詢或指令的條件、子句與輸出分散在好幾句的行內程式碼裡。&lt;/li>
&lt;li>讀者要回到上方的區塊或自己拼湊，才知道句子裡的 &lt;code>WHERE ...&lt;/code> 是哪一段查詢的哪一行。&lt;/li>
&lt;li>執行計畫或指令輸出只以行內程式碼出現，旁邊沒有產生它的那段程式。&lt;/li>
&lt;li>散文寫「多一則……之後回的是」「換成 X 回」「展開之後是」，而頁面上沒有那段程式或那份資料。&lt;/li>
&lt;/ul>
&lt;h2 id="case">Case&lt;/h2>
&lt;p>2026-09-29，SQL 教材 SQL.13〈「問對了沒有」的判定：靜態分析、約束與反例資料〉的靜態分析段。使用者指出「這裡程式碼跟文字夾雜是不好的做法，純文字解說的部分留在文章段落中，程式碼內容跟對應的解釋應該用 code 區域用註解的方式呈現，不然現在難以閱讀」。&lt;/p></description><content:encoded><![CDATA[<p>散文段落的職責是推導，程式碼區塊的職責是讓讀者整段看、整段複製。一段散文把同一段查詢或指令的零件——條件、子句、關鍵字、執行計畫的輸出——一個個用行內程式碼嵌進句子，讀者就得一邊讀推導、一邊在腦中把那些零件組回原本的程式，而組回來的程式在頁面上從來沒有完整出現過。修法是分兩層：<strong>程式與只屬於某一行的解釋進區塊，寫成那一行旁邊的註解；跨行的推導與它對論證的意義留在散文。</strong></p>
<h2 id="失效的形態">失效的形態</h2>
<p>一篇 SQL 教材說明靜態分析判得出哪一種錯法，原文是一整段散文，行內程式碼十幾處：</p>
<blockquote>
<p>「不等於五」的錯法是它判得出來的例子。<code>WHERE 評價.星等 &lt;&gt; 5</code> 對外連接補上 <code>NULL</code> 的列判成未知，那些列全數被 <code>WHERE</code> 濾掉，所以 <code>LEFT JOIN</code> 為了保留沒有評價的訂單而補出來的列一列都留不住：這段查詢與把 <code>LEFT JOIN</code> 改成 <code>JOIN</code> 的版本在任何資料上都回同一批列。……PostgreSQL 的 <code>EXPLAIN</code> 對「不等於五」那段查詢印的是 <code>Hash Join</code>，對正解印的是 <code>Hash Left Join</code>。……評價表的訂單編號在建表時沒有宣告 <code>NOT NULL</code>，表結構已經說了那一欄可能是 <code>NULL</code>，而子查詢只要交出一個 <code>NULL</code>，<code>NOT IN</code> 對每一列都判不成真。</p></blockquote>
<p>這一段講的是兩段查詢、兩份執行計畫、一份建表語句，五段程式沒有一段完整出現，全部拆成零件散在句子裡。每一句單獨看都正確，讀者要做的卻是把 <code>WHERE 評價.星等 &lt;&gt; 5</code>、<code>LEFT JOIN</code>、<code>Hash Join</code> 分別放回它們所屬的那段程式，再回頭理解句子在說什麼。</p>
<p>改寫後，散文只留推導（這段查詢寫了外連接而篩選條件讓補出來的列留不住、等價由三值邏輯決定、最佳化器改寫時不產生警告），兩段查詢與它們的 <code>EXPLAIN</code> 並列在一個區塊，每一行的註解寫這一行判成什麼、這份計畫代表什麼；建表語句與 <code>NOT IN</code> 查詢並列在另一個區塊，因為風險由兩者合起來決定。</p>
<h2 id="跟既有規則的衝突與調和">跟既有規則的衝突與調和</h2>
<p><code>compositional-writing</code> 的〈示範指令〉原本寫「推導與機制：註解裝標籤，機制寫散文」。照字面，上面那段的每一句都是機制，應該留在散文——那正是失效的來源。規則要分的是<strong>解釋的作用範圍</strong>：只屬於某一行的解釋（這一行做什麼、這個值判成什麼、這行輸出代表什麼）離開那一行就要讀者自己對回去，所以寫成那一行的註解；跨行成立的道理與它對論證的意義沒有單一的一行可以附著，所以寫散文。</p>
<p>同一處另有一條「錯誤用法不進區塊」，理由是區塊是可以複製的位置。錯法本身是主題的時候（診斷、錯法與正解的對照）這條不適用：錯的寫法要完整出現才讀得出它錯在哪，處置是進區塊、用上方整行註解標明它是錯的、與正解並列。</p>
<h2 id="偵測">偵測</h2>
<p>計數掃得到候選：去掉程式碼區塊之後，一個散文段落裡的行內程式碼達到十處以上。在全站教學內容跑一次有 57 段，linux、backend、llm 最多。</p>
<p>計數分不出兩種情形，命中之後逐段問：<strong>這些行內程式碼拼起來，是不是一段讀者該整塊看的程式（一個查詢、一條指令、一段輸出）。</strong> 各自是獨立名字的不必移——欄位名、函式名、設定鍵、檔案路徑被當成名詞提到；一整串工具名被列舉的，是清單的問題，改成條列或表格。</p>
<h2 id="全站掃過一次之後">全站掃過一次之後</h2>
<p>候選段落 45 段（去區塊後單段行內程式碼十處以上、且在檔案裡唯一），分四批交給改寫者，判定要改 16 段，主 session 退回一段、實際改 15 段；不改的多數是欄位名、列舉值、設定鍵、按鍵這類各自獨立的名字，以及已經整條寫在行內的單一指令。</p>
<p>改寫者回報了幾種規則原先沒寫到的形態，下面三種的處置已寫進 <code>demonstrating-commands.md</code>：同一段程式已經在前後文的區塊裡（逐行解釋併進既有區塊的註解，不重貼）；原文只描述了程式、沒給完整寫法（區塊只放原文給得出的部分，選項清單與測試結果用 <code>text</code> 區塊，不補指令）；幾條沒有操作對象的短指令（<code>chmod 440</code> 各給不同的檔而原文沒寫檔名，放進區塊會變成跑不起來的指令，這一段退回不改）。</p>
<p>最值得記的是另一種：<strong>把散文裡的零件搬回區塊之後，程式與散文對不上。</strong> 一篇 Firestore 安全規則的散文寫「<code>update</code> 兩者都要看」（寫入前的 <code>resource.data</code> 與寫入後的 <code>request.resource.data</code>），而上方骨架的 <code>allow update, delete</code> 只檢查了寫入前的 <code>ownerId</code>——擁有者可以把 <code>ownerId</code> 改成別人，這是一個授權漏洞。散文把程式拆成零件的時候，兩者的矛盾沒有位置並排出現；逐行解釋要寫成那一行的註解時，註解與它旁邊的條件對不上。修法是把骨架的 <code>update</code> 與 <code>delete</code> 拆開，<code>update</code> 加上寫入後的檢查。這跟 <a href="/blog/report/unnamed-halves-are-unextracted-variables/" data-link-title="切開一個集合之前先寫切分的依據，再替每一塊命名；「一部分」「另一半」是還沒抽出來的變數" data-link-desc="文章用「一部分交得出去」「交不出去的那一半」「那一側」指稱一個被切開的集合，讀者說不出每一塊是什麼、為什麼這樣切時回來讀">#367</a> 命名時發現寫反的論斷是同一種現象：排版與命名都逼作者把一個原本可以不決定的對應寫死。</p>
<h2 id="計數掃不到的形態散文描述了一段頁面上沒出現的程式">計數掃不到的形態：散文描述了一段頁面上沒出現的程式</h2>
<p>同一篇的第二輪改寫找到另一種形態，行內程式碼每段最多五處，十處的門檻掃不到。這一種<strong>描述一段頁面上從沒出現的程式</strong>；〈失效的形態〉那段靜態分析的例子則是把現成的程式拆成零件。這一種的例子：「訂單 101 多一則三星之後，同一段回的是 101」（改過資料的那個版本沒寫出來）、「補 <code>OR 評價.星等 IS NULL</code> 也修不掉」（補上條件的那段查詢沒寫出來）、「<code>NOT IN</code> 展開之後是『不等於 101，而且不等於 <code>NULL</code>』」（展開式用散文轉述）、「同一句換成 <code>NOT EXISTS</code> 回的仍然是 102」、「替 101 再加一則評價之後把訂單接上評價再加總……總額變成 1100」。讀者要自己寫出那段程式才驗證得了句子，而寫的人也沒有被逼著寫出來：最後一例寫成程式時才要決定連接是 <code>LEFT</code> 還是內連接——內連接在原本的資料上加總是 300，不是句中的 800；同一篇另一處提到「五張訂單加七則評價」的反例資料，那份資料在頁面上根本不存在，寫出來、跑過之後才發現原文列的資料狀態與三種錯法需要的對不上。</p>
<p>偵測靠句型：資料變體（「多一則……之後」「再加一則……之後」）、改寫變體（「換成 X 回」「補 X 也修不掉」）與展開式（「展開之後」「展開成」）。<code>rg '(多|加|再加|刪掉?|改成)[一兩]?[則列筆張個][^。]{0,20}之後|換成[^。]{1,20}回|展開(之後|成)|也修不掉'</code> 在那一篇的改前版本命中全部五段；全站教學內容 89 檔 113 處，是候選不是判決——描述的變體已經寫在鄰近區塊裡的、或只是一句敘事的不必動。</p>
<p>處置是把那段程式與那份資料寫出來、實際跑一次，各資料變體的結果寫成區塊註解（<code>-- 共用資料：102</code>、<code>-- 訂單 101 多一則三星之後：101</code>），散文只留這些結果對論證的意義。這跟上面「原文只描述了程式、沒給完整寫法時不補」的差別在能不能跑：改寫者手上沒有環境時，補出來的程式讀起來可以執行而從來沒被跑過；作者能跑的時候，寫出來並跑過就是修法，而跑的這一步常常就是找到錯的那一步。</p>
<p>SQL 分類其餘 23 篇接著逐篇檢查一次（與抽變數一起查），改了 138 處，多數是這一種：「換成 X 回」「改放 <code>WHERE</code>」「多一張訂單之後」「給出兩個不同的計畫」這類句子描述的程式都寫成了區塊，而句型 pattern 只抓到其中一小部分——「換成 <code>JOIN</code>，結果一個字都沒有變」「若換成 INNER」「加上引號之後」都不在 pattern 裡，要逐篇讀。寫成程式跑過之後對出十幾處內容錯，每一處在散文裡都讀得通：自連接找每組最大值時「在子查詢裡加一句 <code>IS NOT NULL</code>」攔不住金額是 <code>NULL</code> 的那一列（要寫在外層）；<code>CREATE INDEX ON 顧客(姓名 COLLATE NOCASE)</code> 在 SQLite 是語法錯誤；<code>NO ACTION</code> 允許同一交易裡先刪父列，只在約束宣告成 <code>DEFERRABLE</code> 時成立；一段 MySQL 範例的 <code>INSERT</code> 給了三個值而表有四欄；權限範例照頁面順序執行時 <code>GRANT</code> 由剛切換過去的角色自己發出而被拒絕；「漏掉分區」的錯版固定少報，其實取決於同一天兩列誰排在前面，換個排法就同時多報與少報；「兩則錯誤訊息各自寫出了理由」而實際的訊息只說了不准。</p>
<h2 id="論述基礎與限制">論述基礎與限制</h2>
<p>依據是一段改寫與一次全站掃描（45 段候選、15 段改寫），加上同一篇第二輪找到的五段描述式形態；描述式的句型 pattern 只在那一篇上驗過命中率，全站 113 處候選還沒逐處判定。十處是取來縮小候選的門檻，不是判定條件：五處行內程式碼就拼成一段查詢的段落一樣違規，二十處檔案路徑的段落可能合規。</p>
<h2 id="跟其他抽象層原則的關係">跟其他抽象層原則的關係</h2>
<ul>
<li><a href="/blog/report/literal-operand-hides-the-change-point/" data-link-title="示範指令的引數要說明，寫成字面值的那些最不像需要說明" data-link-desc="文章的指令讀者照抄跑得起來、換成自己的路徑或套件時卻不知道要改哪裡、也看不出兩種寫法差在哪時回來讀">#360 示範指令的引數</a>——那一張管區塊裡的字面值有沒有說明；本卡管該進區塊的程式有沒有進去。</li>
<li><a href="/blog/report/unnamed-halves-are-unextracted-variables/" data-link-title="切開一個集合之前先寫切分的依據，再替每一塊命名；「一部分」「另一半」是還沒抽出來的變數" data-link-desc="文章用「一部分交得出去」「交不出去的那一半」「那一側」指稱一個被切開的集合，讀者說不出每一塊是什麼、為什麼這樣切時回來讀">#367 切開一個集合之前先寫切分的依據</a>——同一段改寫先做的那件事：先替「靜態分析」命名，再把它判得出什麼示範出來；本卡處理的是那個示範怎麼排。</li>
<li><a href="/blog/report/positioning-decides-form-before-any-rule-applies/" data-link-title="定位決定體例，而共用的寫作規範會把一個 surface 的體例搬到另一個上" data-link-desc="同一套寫作規範同時服務 agent 指令、人類教材與程式碼註解時，用來判斷某一條規則該不該套在手上這份稿件上">#302 定位決定體例</a>——那一張記下規則的觸發條件比判斷標準先生效；「推導與機制寫散文」照字面觸發在逐行解釋上，是同一種失效。</li>
</ul>
<h2 id="判讀徵兆">判讀徵兆</h2>
<ul>
<li>一個散文段落裡，同一段查詢或指令的條件、子句與輸出分散在好幾句的行內程式碼裡。</li>
<li>讀者要回到上方的區塊或自己拼湊，才知道句子裡的 <code>WHERE ...</code> 是哪一段查詢的哪一行。</li>
<li>執行計畫或指令輸出只以行內程式碼出現，旁邊沒有產生它的那段程式。</li>
<li>散文寫「多一則……之後回的是」「換成 X 回」「展開之後是」，而頁面上沒有那段程式或那份資料。</li>
</ul>
<h2 id="case">Case</h2>
<p>2026-09-29，SQL 教材 SQL.13〈「問對了沒有」的判定：靜態分析、約束與反例資料〉的靜態分析段。使用者指出「這裡程式碼跟文字夾雜是不好的做法，純文字解說的部分留在文章段落中，程式碼內容跟對應的解釋應該用 code 區域用註解的方式呈現，不然現在難以閱讀」。</p>
]]></content:encoded></item></channel></rss>