Skip to content

Releases: tomoemon/go-decision-pattern

v0.1.4

Choose a tag to compare

@tomoemon tomoemon released this 13 Oct 11:14
a38e1f4

Go 1.27 の昇格したフィールドの書き方に、規約と flow ツールを合わせた。

規約の本文(rule/decision-pattern.md)が変わったので、規約バージョンは v0.1.4 になる。本文だけを取り込んでいる場合も取り込み直す。

規約: その段で確定させる事実は昇格したフィールドで書く

Go 1.27 から、埋め込んだ struct のフィールドを composite literal に直接書ける。go fix(modernize の embedlit)は入れ子のリテラルをこの形に書き換えるので、規約の例をこちらに揃えた。

// これまで
return XxxNeedBlock{
    xxxFactsArticle: xxxFactsArticle{ArticleID: article.ID, AuthorID: article.AuthorID},
}

// これから(Go 1.27 以降)
return XxxNeedBlock{
    ArticleID: article.ID,
    AuthorID:  article.AuthorID,
}
  • 型の定義では、これまでどおり事実の struct を埋め込む
  • 前段から引き継ぐ事実は、これまでどおり xxxFactsArticle: s.xxxFactsArticle と struct ごと渡す
  • Go 1.26 以前は入れ子のリテラルで書く

exhaustruct による書き漏らしの検出も、この書き方に合わせて説明を直した。引き継ぎの漏れは struct 1 つの欠落として、その段で確定させる事実の漏れは足りないフィールドとして出る。

flow: 昇格したフィールドで書いた事実が終端のラベルに載っていた

終端のラベルからは埋め込んだ事実を除いているが、判定がキーが埋め込みのフィールド名のときにしか効いていなかった。昇格したフィールドで書くと事実がラベルに載り、事実の値が経路ごとに違うと、同じ結末の終端が別々のノードに割れていた。

これまで:  n1(["Decided<br/>- UserID: id<br/>- Done: true"])
これから:  n1(["Decided<br/>- Done: true"])

入れ子で書いた場合の出力は変わらない。

Full Changelog: v0.1.3...v0.1.4

v0.1.3

Choose a tag to compare

@tomoemon tomoemon released this 05 Sep 01:11
45b4d7a

flow ツールの変更。図の既定を判断ノード形式にし、条件が出ない箇所を直した。

規約の本文(rule/decision-pattern.md)は変えていない。規約バージョンは v0.1.1 のままなので、本文だけを取り込んでいる場合はこの版で取り込み直す必要はない。

図の既定が判断ノード形式になった

-shape を省いたときの描き方が state から decision に変わる。

go tool decision-pattern flow ./domain/...              # 判断もノードにする(既定)
go tool decision-pattern flow -shape=state ./domain/... # 従来の、状態だけをノードにする図

state は経路の条件を辺のラベルに畳むので、分岐が深いほどラベルが「かつ」で連なって伸びる。同じ判断に複数の経路から入る形も経路ごとに複製されるため、合流として読めない。どちらも形式の性質で、実装では縮まらない。判断をノードにすればラベルは枝の名前 1 つで済み、同じ判断は 1 ノードにまとまる。

これまでの既定 (state)
n0 -- "article.Status == StatusDraft かつ article.Body == #quot;#quot;" --> n2

これからの既定 (decision)
q0 -- "no" --> q1
q1 -- "yes" --> n2

状態と状態の関係だけを俯瞰したいときは -shape=state で従来の図が出る。それぞれの出力そのものは変えていない。

switch を素通りする case の条件が出るようになった

case が 1 つでも脱出しないと、switch を抜けた先の条件を丸ごと捨てていた。本体が空の case、break だけの case、return せずに処理だけする case がこれに当たる。

switch k {
case kindA:
case kindB:
	return B{}
}
return C{}
これまで                          これから
start0 -- "k == kindB" --> n0     start0 -- "k == kindB" --> n0
start0 -- "それ以外"   --> n1     start0 -- "k != kindB" --> n1

抜けた先に着くのは「脱出する case のどれにも当たらなかった」とき。枝が値で排他なら、素通りする case の否定を積まず、脱出する case の否定だけを積めばそれが正確な条件になる。

既定が判断ノード形式になったことで、この修正の効果が大きい。条件が付かない遷移はひし形を通らない裸の線になるので、開始点から無条件の行き先が 2 つ生えているように見えていた。

条件を出さない形もある。連言では表せないためで、internal/flow/README.md の制約に書いた。

  • fallthrough(次の case へ行くので switch の先へは進まない)、panic、抜けない for、goto
  • case の中で一部だけ return する形
  • case 式が定数でないタグ付き switch。実行時に重なりうるので上から順の評価になる
  • タグなし switch と if 連鎖。枝が順序を持つ

Go 1.27 が要る

go.mod の go ディレクティブを 1.27 に上げた。1.24.0 は依存が要求する下限を go mod tidy が書いたもので、パッチまで含むため CI のツールチェインがそのパッチに固定されていた。

規約の本文だけを取り込んでいる場合は関係ない。ツールを go get -tool で入れている場合は Go 1.27 以上が要る。

取り込み方

規約の本文は変わっていないので、ツールを使っている場合だけ上げればよい。

go get -tool github.com/tomoemon/go-decision-pattern/cmd/decision-pattern@v0.1.3

版を固定しない取り込みは main から取る。

curl -o .claude/rules/decision-pattern.md \
  https://raw.githubusercontent.com/tomoemon/go-decision-pattern/main/rule/decision-pattern.md

この版の本文もこのリリースに添付してある(v0.1.1 と同じ内容)。タグ時点の内容を 1 つの URL で取りたい場合に使える。

v0.1.2

Choose a tag to compare

@tomoemon tomoemon released this 04 Sep 16:08
1de4830

flow ツールの修正。図に出ていなかった分岐条件を出るようにし、判断をノードにする出力形式を足した。

規約の本文(rule/decision-pattern.md)は変えていない。規約バージョンは v0.1.1 のままなので、本文だけを取り込んでいる場合はこの版で取り込み直す必要はない。

遷移ラベルの条件が正確になった

条件が乗らない箇所が 4 つあり、排他な遷移が並列に見えていた。

変更前
n0 -- "article.Status != StatusDraft" --> n1
n0 -- "article.Body == #quot;#quot;" --> n2      ← 下書きであることが乗っていない
n0 -- "それ以外" --> n3

変更後
n0 -- "article.Status != StatusDraft" --> n1
n0 -- "article.Status == StatusDraft かつ article.Body == #quot;#quot;" --> n2
n0 -- "article.Status == StatusDraft かつ article.Body != #quot;#quot;" --> n3

乗っていなかったのは次の 4 つ。いずれも「書き方を変えると同じ判断が違う図になる」形で出ていた。

  • early return のあとに続く文(else を書いた場合は元から乗っていた)
  • タグなし switch の先行 case の否定
  • default を持たない switch を抜けた先
  • 型 switch を抜けた先

あわせて、脱出判定を Go 仕様の terminating statement に寄せた。break を脱出と数えていたため、case の中で break した経路が図から消えていた。条件の否定も AST を見て作るようにした。文字列操作では !(x == 1) || (y == 2) の括弧を誤って剥がし、構文として壊れたラベルが出ていた。

判断をノードにする -shape=decision

条件を正確にした結果、ラベルが「かつ」で連なって図が横に広がる。これは状態だけをノードにする形式の性質で、経路上の条件を辺に詰め込む以上避けられない。

分岐そのものをひし形のノードにする形式を足した。辺のラベルは枝の名前だけになり、同じ分岐は 1 ノードにまとまる。サンプルで幅 1975px が 911px になった。

go tool decision-pattern flow -shape=decision ./domain/...

ヘルパー関数の中の判断に複数の経路から入る形が、合流として描ける。-shape=state(既定)の出力は変わらない。

詳細は #3 に書いた。

取り込み方

規約の本文は変わっていないので、ツールを使っている場合だけ上げればよい。

go get -tool github.com/tomoemon/go-decision-pattern/cmd/decision-pattern@v0.1.2

版を固定しない取り込みは main から取る。

curl -o .claude/rules/decision-pattern.md \
  https://raw.githubusercontent.com/tomoemon/go-decision-pattern/main/rule/decision-pattern.md

この版の本文もこのリリースに添付してある(v0.1.1 と同じ内容)。タグ時点の内容を 1 つの URL で取りたい場合に使える。

v0.1.1

Choose a tag to compare

@tomoemon tomoemon released this 31 Aug 06:05

適用基準の 2 つの除外を明確にした。判断の内容は変えていない。

変更

  • 「取得キーの集合が空になる」の除外に適用範囲を書いた。呼ぶ取得の操作は変わらず、渡すキーの数だけが変わる場合に限る。取得するかどうかが判断で変わり、その取得がキーの集合を取らない形(ある主体に紐づく一覧、集計、存在確認)なら、空のキーに畳めないので Decision にする
  • 「判断と取得の往復が 1 回で終わる」の除外に境界を書いた。取得するかどうか自体が変わる場合は「取得の操作が 1 つに固定されている」に当たらない。キーの型では「取らない」を表せず、Option にすると判断が interpreter 側に戻る
  • 候補が空のときのガードの扱いを 1 段落足した。interpreter 側にガードを置いても、空のキーのまま呼んでもよい。ガードは性能上のもので、設計原則が domain に出すことにしている「判断を伴う取り出し」には当たらない

きっかけは #1 に書いた。判断の結果によって後続の取得を行うかどうかが変わるケースで、除外に当たるかどうかで読み手によって結論が割れた。

取り込み方

版を固定しない取り込みは main から取る。

curl -o .claude/rules/decision-pattern.md \
  https://raw.githubusercontent.com/tomoemon/go-decision-pattern/main/rule/decision-pattern.md

ツールで版を固定している場合は、上げてから書き出し直す。

go get -tool github.com/tomoemon/go-decision-pattern/cmd/decision-pattern@v0.1.1
go tool decision-pattern rule -path "domain/**/*.go" -o .claude/rules/decision-pattern.md

この版の本文はこのリリースにも添付してある。タグ時点の内容を 1 つの URL で取りたい場合に使える。