every Tech Blog

株式会社エブリーのTech Blogです。

Go 1.26で変わるgo fix

記事サムネイル
Go 1.26で変わるgo fix

この記事は every Tech Blog Advent Calendar 2025 の 26 日目の記事です。

はじめに

開発本部でデリッシュキッチンアプリ課金ユーザー向けの開発を担当しているhondです!
先日2026年2月にリリース予定のgo1.26のRelease Candidate 1であるgo1.26rc1がリリースされました。もうrc1は確認できたでしょうか?確認がまだの方はこちらから確認できるのでぜひ!
今回はGo 1.26でgo fixが大幅に変更されるとのことだったのでそちらについて説明しようと思います。

go fixとは

go fixはGo 1リリースにて破壊的変更を含む古いAPIを特定し、新しいものに修正するツールとして追加されました。 go fixによって大まかな修正はできるため、私たちはコアな部分の修正に集中できるようになっていました。
Go 1リリースの際はgo fixでの修正対象は多くGo 1のRelease NotesUpdating: Running go fixと調べるだけでも14件ヒットし、ソースコードを確認すると37件ものルールがあることが確認できます。その後もgo fixのルールは追加削除が繰り返されていきましたが、Goがメジャーバージョン内での後方互換性を担保しているので最近はなかなか変更が行われず使わないコマンドとなっていました。

Go 1.26での変更点

github.com

Go 1.26ではcmd/go: fix: apply fixes from modernizers, inline, and other analyzersにてgo fixが大幅に変更される旨のProposalがAcceptされました。

この変更の背景は、元のissueであるcmd/fix: remove all functionalityとGopherCon 2025でのAlan Donovanの発表(Analysis and Transformation Tools for Go Codebase Modernization)から確認できます。具体的には以下の3点が挙げられています。

  • 「go fixとは」でも触れた既存go fixの機能であるcontextbuildtagの修正が不要になったこと
  • コードレビュー時間の短縮や開発者の教育のためにモダン化が必要だったこと
  • AI/LLMが生成するコードの品質改善のためにモダン化が必要だったこと

これらの背景を踏まえ、modernize//go:fix inlineのようなGoのコードのモダン化を目的とするアナライザーをgo vet同様にgo fixでも利用可能にすることがこのProposalの目的となっています。
go vetgo fixの使い方は似ていますが、あくまでgo vetはアナライザーを用いて静的解析した診断結果を報告するツール、go fixは検出した問題をアナライザーが提案する修正案に修正するツールという使い分けになるようです。

以降では、Go 1.26のgo fixで利用可能になるmodernizeinlineについて詳しく説明します。

modernizeとは

pkg.go.dev

modernizegolang.org/x/tools/go/analysis/passes/modernizeで公開されているアナライザーのスイートです。Goのコードを最新の構文や標準ライブラリの機能を利用して、より簡潔でモダンな形式に修正することを目的としています。

現在24個のアナライザーが登録されており、その中から代表的なものを紹介します。Go 1.26で追加されるerrors.AsTypeのアナライザーも既に登録されています!

Analyzer 説明
any interface{}anyに修正する
errorsastype errors.AsをGo 1.26で追加されたerrors.AsTypeに修正する

使い方

以下のコマンドでmodernizeを実行することができます。

$ go run golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest -fix ./...

また、特定のアナライザーを有効・無効化することも可能です。

# anyアナライザーを有効化
$ modernize -any=true -fix ./...

# anyアナライザーを無効化
$ modernize -any=false -fix ./...

基本的には修正を適用しても動作が変わらないよう設計されていますが、bloopのように完全に動作を保証できないアナライザーもあり、それらはデフォルトでは無効化されています。

実行例

以下では実際にanyアナライザーを使ってinterface{}anyに修正してみます。

修正前のコード:

package main

import "fmt"

type OldInterface interface{}

func main() {
    old := OldInterface(1)
    fmt.Println(old)
}

コマンド実行:

$ go run golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest -fix ./...

出力(差分):

 import "fmt"
 
-type OldInterface interface{}
+type OldInterface any
 
 func main() {
        old := OldInterface(1)

このように、interface{}anyに自動で修正されたことが確認できます。

inlineとは

pkg.go.dev

inlinegolang.org/x/tools/go/analysis/passes/inlineで公開されているパッケージで、inlinegofixdirectiveの2つのアナライザーが含まれています。

inlineアナライザーは//go:fix inlineコメントディレクティブに基づいて修正を行います。主に非推奨になった関数や定数を新しいものに置き換えるために使用され、ioutil packageなどで利用されています。

具体的な使い方は以下の通りです。

  • 関数の場合:修正したい関数をラップした関数を作成し、その関数にコメントディレクティブを加えることで修正が可能です。
//go:fix inline
func Square(x int) int { return Pow(x, 2) }
  • 定数の場合:修正したい変数を左辺に、修正後の変数を右辺に記述し、コメントディレクティブを加えることで修正が可能です。
//go:fix inline
const Ptr = Pointer

使い方

以下のコマンドでinlineを実行することができます。

$ go run golang.org/x/tools/go/analysis/passes/inline/cmd/inline@latest -fix ./...

また、goplsを用いているIDE上では対象をホバーすることでも修正が可能です。

実行例

以下では、OldFunctionNewFunctionを定義し、OldFunctionNewFunctionに修正する際の例を示します。

修正前のコード:

package main

import "fmt"

func main() {
    OldFunction()
    NewFunction()
}

//go:fix inline
func OldFunction() {
    NewFunction()
}

func NewFunction() {
    fmt.Println("NewFunction")
}

コマンド実行:

$ go run golang.org/x/tools/go/analysis/passes/inline/cmd/inline@latest -fix ./...

出力(差分):

 import "fmt"
 
 func main() {
-       OldFunction()
+       NewFunction()
        NewFunction()
 }

このように、OldFunctionNewFunctionに修正されるのが確認できます。

IDEでの修正

コマンドを使わずに、IDE上で対象をホバーすることでも修正が可能です。

IDEでホバーした時の画像

Quick Fixを選択すると、修正候補が表示されクリックすることで修正が可能です。

Quick Fixを押した時の表示

新しいgo fixでできること

ここまで説明したmodernizeinlineは、Go 1.26からはgo fixを実行するだけで適用できるようになります。今までは破壊的変更を修正するためのツールだったgo fixが、Goのコードをモダン化していくためのツールへとシフトしました。

実際にgo1.26rc1を使ってgo fixを実行してみます。

$ go1.26rc1 fix ./...

modernizeの結果:

 import "fmt"
 
-type OldInterface interface{}
+type OldInterface any
 
 func main() {
        old := OldInterface(1)

inlineの結果:

 import "fmt"
 
 func main() {
-       OldFunction()
+       NewFunction()
        NewFunction()
 }

このように、go fixを実行するだけでコードをモダン化された状態に持っていくことができます。コード品質の担保がより容易になるため、pre-commitフックやCI、AI/LLMの出力後に適用するルールとして定義するのが良さそうです!

まとめ

私自身go fixを使う機会がなかったので、今回のアップデートで既存のgo fixとモダン化の為のツールとして進化したgo fixを会社のコードに適用するいい機会になりました。既存のgo fixでの修正点は一部のcontextのみでしたが、新しいgo fixを実行したところ1249の修正点が確認されました。10年もののサービスという事もありこれらのコードを全て手動で特定し、修正していくとなると莫大な労力を要するので公式からこのようなツールが出ていることはとても有り難いなと思いました。
上記で修正されたのはmodernizeに定義されたアナライザーやそれぞれのpackageにて//go:fix inlineが定義されているものですが、//go:fix inlineに関しては普段の開発でも非推奨化したがバージョン互換性担保の観点で削除できないコードを管理する際にとても有用なので積極的に利用して行きたいです。
AIはどうしても既存のコードベースに品質が左右されてしまうので新しくなったgo fixを用いて、継続的な品質改善が重要だと感じました。また、公開されたコードベースを元にAIは学習していくので今後の自分を含めたGopherがAIを通してより良いコードを書くためにも積極的にモダン化を行おうと思います。
ここまで読んでいただきありがとうございます。Go 1.26でgo fixがどう変わるか迷っている方の助けになれたら幸いです!

AIワークフロー設計と軌道修正の振り返り

この記事は every Tech Blog Advent Calendar 2025 の25日目の記事です。

目次

はじめに

こんにちは。2025年4月にソフトウェアエンジニアとして新卒入社した黒髙です。普段はデリッシュキッチンの開発に携わっています。

デリッシュキッチンにはレシピだけでなく、料理に関する情報をまとめた記事レシピ特集など、多様なWebコンテンツがあります。コンテンツディレクターの業務効率化の一環として、ユーザーニーズを満たすコンテンツ作成をAIでサポートする試みを、私は設計から実装までを一貫して担当しました。

当初はAIに創造的なコンテンツ生成を任せようと意気込んでいたのですが、実運用では想定外の課題が次々と顕在化し、最終的にはルールベースの制約(ガードレール)を多く追加することになりました。

以下画像は、実際に生成されたアボカドサーモンの魅力を引き出すレシピ集 | デリッシュキッチンのコンテンツの一部です。

ページの一例

実際に自動生成して公開しているコンテンツは、セレクション一覧からもご覧いただけます。

また、記事生成に関わる処理の全体像は次の通りです。AIワークフローの詳細は後述します。

処理の流れとアーキテクチャ

本記事では、AIワークフロー設計で何を期待し、何が起き、どのように軌道修正したかを振り返ります。LLMや生成AI活用の文脈では基本的な話も含みますが、現場で使えるものにするためにどう整えていったのかの判断を中心にまとめます。

設計から軌道修正まで

本章では設計段階から運用に至るまで、AIワークフローに関する部分の振り返りを行います。

1. 何を目指していたか

理想は、AIがWebページの構成を考え、分析結果に応じて組み替えられることです。ただし今回は、早期にコンテンツを公開することを優先したPoC(初期検証フェーズ)として、ページ構成を「見出し+説明文+レシピリンク集」の繰り返しに限定しました。

- 見出し1
  - 見出し1の説明文
  - 見出し1のレシピリスト
    - レシピA
    - レシピB
    - レシピC
- 見出し2
...
(以下繰り返し)

当初は、ニーズ分析→見出し・説明文の生成→関連レシピの検索までをAIが一貫して行うことを目指しました。具体的には、次の5ステップのLLMパイプラインを設計しました。

当初のワークフローと具体例

また、初期検証をできるだけ早く進めるため、デリッシュAIで利用しているレシピ一覧を埋め込みベクトルに変換したテーブルを使いました。

2. 運用して顕在化した問題

数パターンのキーワードで試したところ、課題は残るものの、記事として形になることは確認できました。そこでバックエンド/フロントエンドを実装し、キーワード一覧をもとにバッチで自動生成を開始しました。

ところが「キーワードに沿ったレシピが選ばれているか」の観点の公開前レビューでは、公開できる記事が想定より少ない結果になりました。さまざまな入力パターンを事前に十分検証し、試行段階で見えていた課題にこの時点で対処しておくべきでした。

具体的な問題としては以下のようなものがあります。

検索クエリの生成が安定しない

今回のフローでは画像の通り、見出しに基づいたレシピ検索クエリをLLMに生成させています。例えば 簡単に作れるごぼうと牛肉レシピ を入力しても、簡単レシピ簡単牛肉 のように意図が欠けたクエリになることが稀にありました。結果として後続のLLMにも意図したリクエストを送れず、適切な記事が生成できない問題がありました。

見出しに合うレシピが必ず存在するかどうかはわからない

検索キーワード ごぼう 牛肉 から ごぼうと牛肉のローストビーフ のような見出しが生成されても、デリッシュキッチンにそのようなレシピがあるとは限りません。具体的に絞り込む見出し提案に従った結果、レシピが登場しないといった問題が発生しました。

条件に合わないレシピが含まれてしまう

例えば 簡単に作れるごぼうと牛肉のレシピ に対して、味付け簡単! 牛すじとごぼうの塩麹煮 のような適切なレシピが出る一方で、簡単で本格的な味! 豚バラ肉とごぼうの和風煮 といった、響きは似ているものの材料が欠けているレシピも混ざることがありました。

3. 問題の原因

プロンプトの肥大化

デリッシュキッチンでは、信頼性の高いコンテンツ品質を維持するため、多くの制作ルールが存在しています。以下は一例ですが、実際には数十個程度の記載NG項目があります。

- 健康・栄養に関する過度な表現禁止: ダイエット, ヘルシー ... 
- 食欲・体調への直接効果を謳う表現禁止: 食欲, 体力, 元気 ... 

料理系コンテンツでは連想語がNGになることも多く、AIにとって制約の強い要求です。さらに、これらをすべてのステップで指示していたため、禁止事項を追加しても一度で要求を満たし切れないことがありました。

不要な思考(ニーズ分析)を挟んでいた

ニーズに合致した構成にするためにStep 1としてニーズ分析を入れましたが、禁止事項を守らせることや、ヒットするレシピ数を担保するために無難な見出しに寄せる要件とは相性が悪く、逆にノイズになっていました。

ベクトル検索に対して除外の前後処理を入れていなかった

レシピ検索としてベクトル検索とコサイン類似度によるスコアリングを用いていましたが、関係のないレシピも検索結果に含まれてしまう問題が発生していました。ベクトル検索は意味的な類似性を捉えるのには優れていますが、それ単体で材料として実際に使われているかどうかを判定することはできません。

根本にあった認識の甘さ

これらの問題に共通していたのは、以下の点に対する認識の甘さでした。

  • 運用では検証段階より多種多様なキーワードを扱うこと
  • LLMによる不安定な出力が次段階の生成内容にも影響をもたらすこと

当初は創造的なWebサイト構築を漠然と想像していましたが、実際に必要だったのはAIが生成した記事をできるだけ早く公開し、生成から公開までのサイクルを回しながら検証を進めることでした。

しかし、少数のキーワードではそれなりに記事が生成できたことで安心してしまい、安定運用できるかという観点が抜け落ちたまま次の開発に進んでしまっていました。

4. どう軌道修正したか

問題を踏まえて、以下のような軌道修正を行いました。

以前のステップ 変更点
1. キーワードのニーズ分析 削除
2. 小見出し生成 LLMによるテンプレート選択
3. 検索キーワード抽出 ルールベースで生成
4. コンテンツ生成 変更なし
5. レシピ検索 OpenSearch + LLM-as-a-Judgeの追加

ニーズ分析のステップを排除

前述の通り、ノイズとなっていたStep 1(キーワードのニーズ分析)を削除しました。 将来的には分析データが揃い次第、数値に基づくニーズ分析を復活させ、LLMによる構成検討も行いたいと考えています。

見出しの自由生成・クエリ生成を排除

  • 対象を絞り込まない抽象的な見出しにしたいこと
  • 禁止ワードを含めたくないこと

を踏まえると、見出しのパターンはある程度限られてくることが分かりました。ヒットするレシピを安定して出すために、LLMに自由生成させるのではなく、見出し候補を用意して選択してもらう方針に転換しました。

SUBHEADING_OPTIONS = [
    {"kind": 1, "template": "簡単に作れるxxのレシピ"},
    {"kind": 2, "template": "xxとxxの絶妙な組み合わせ"},
    {"kind": 3, "template": "xxを使ったアレンジレシピ"},
    {"kind": 4, "template": "新しいxxの料理アイデア"},
    # ...
]

KIND_KEYWORD_MAPPING: dict[int, str] = {
    1: "{keyword} 簡単",
    2: "{keyword} 組み合わせ",
    3: "{keyword} アレンジ",
    4: "{keyword} アイデア",
    # ...
}

また、見出しに基づくクエリ生成もLLMに任せるのをやめ、(検索キーワード+見出しの特徴)をルールベースで組み立てる方針に戻しました。HyDE(Hypothetical Document Embeddings)のような手法も検討しましたが、1見出しに最大9個のレシピを網羅的に取得したい要件には合わないと判断し、簡易的で汎用的なクエリで対応することにしました。

レシピをベクトル検索からOpenSearch利用に変更

構想段階の試用では、デリッシュAIの基盤を一部利用したベクトル検索が手軽で都合が良かったので採用していました。

しかし、ワークフローを見直し、扱うキーワードや見出し表現をある程度固定化した結果、検索に求める要件も変化しました。

以下の理由から、レシピ検索機能で既に用いているOpenSearchを利用する方針としています。

  • 多くの対象キーワードにおいて、通常検索の方が期待したレシピが安定してヒットすること
  • レシピ検索機能で用いられているシノニム辞書をそのまま活用できること
  • 数パターンに固定化した見出し表現においては、ベクトル検索の強みである意味的類似度の必要性が相対的に薄れたこと

なお、今後扱うキーワードの幅や要件が変わった場合には、再びベクトル検索を含めた見直しを行う余地があると考えています。

LLM-as-a-Judgeの導入

更なるガードレールとして、レシピが見出しの意図に合っているかを審査するステップを追加しました。この判定を導入することで、条件に合わないレシピをより厳格に除外できることが期待できます。

    {
      "recipe_id": "206162500360602656",
      "accept": true,
      "reason": "タイトル・材料に「牛すじ(牛肉)」とごぼうが含まれており、サブ見出しの「ごぼう 牛肉 簡単」に合致します(味付けが簡単な点も明記)。調理手順は煮込み工程があるものの、小見出しの意図と矛盾していません。"
    },
    {
      "recipe_id": "163718318442676716",
      "accept": false,
      "reason": "ごぼうは使われていますが、主な肉材が豚バラ肉であり、小見出しが想定する『牛肉』と一致しません。"
    },

まとめると、フローは次の通りです。

ワークフロー

初期段階では1記事あたり3〜10件以上の修正指摘が発生していたものが、これらの改善によって修正指摘が0件のケースが大半となり、あっても1〜2件程度に収まるようになりました。

5. 前提条件の見直し

ワークフローの見直しを進める中で、そもそもどのキーワードを生成対象とすべきかという前提条件にも課題があることが分かりました。

当初は、食に関連するキーワードを一律に処理していましたが、キーワードによって求められる判断や前処理の難易度が大きく異なることが次第に明らかになりました。

例えば カニ レシピ では、カニカマを許容するかどうかの意思決定が必要で、LLMには難しいです。また、酒のあて のように抽象度の高いキーワードでは、どの切り口で掘り下げるかという追加設計が求められます。

こうした性質の異なるキーワードを同一の前提でAIワークフローに流していたことが、後段のLLM-as-a-Judgeや人手レビューの負荷を高め、全体の不安定さにつながっていました。

ひとまずは、AIワークフローの前段としてキーワードの取捨選択を行い、判断コストが高そうなものや、追加設計が必要なものは対象外とする方針で生成していきます。

振り返りから見えたワークフロー設計の勘所

これまでの試行錯誤を振り返ると、技術的な工夫以上にワークフロー設計そのものの考え方が重要だったと感じています。

ステップごとに切り分けて進める

今回のようにLLMの出力結果が後続の処理に大きく依存するワークフローでは、各ステップが単体で正しく機能するかをまず確認する必要があります。想定動作・実装方針・失敗時のハンドリングまで詰めたうえで次に進むことが、品質担保と手戻り削減の観点で重要であると感じています。

AIに任せる部分・ルールベースにすべき部分を見極める

本取り組みを通じて、LLMに任せる部分/任せない部分を明確にすることが、ワークフロー全体の安定性に直結することが分かりました。

特に意識したのは、次の3点です。

  • 決定的に定義できる処理は、LLMに任せない
  • 出力の揺れが後段に大きく影響する箇所では、強いガードレールを設ける
  • 曖昧さを許容できる工程のみ、LLMの生成能力を活かす

このように役割分担を整理したことで、LLMにすべてを任せる構成から、壊れにくいパイプラインへと移行できました。

運用を見据えたガードレール設計

最終目標(ユーザーニーズを満たすコンテンツ制作の工数をできるだけ減らすこと)自体は当初から変わっていません。一方でビジネス側には、まず記事を公開し、ランキングの変化を見ながら改善したいという目的がありました。そのためには、改善サイクルを回せるだけの安定した記事生成が前提になりますが、創造性を高める工夫を優先してしまったことが手戻りの原因でした。

今後の取り組みと展望

今回生成している記事は、文章の整合性や、検索キーワードに紐づくレシピになっているかという点では、一定の信頼性を確保できています。一方で、訪問ユーザーのニーズを満たすコンテンツとしては、まだ伸びしろがあると感じています。

一例ですが、以下を検討しています。

  • Self-ReflectionによるLLMの自動改善サイクルの導入
  • 幅広い検索キーワードに対応するルーティングの追加
  • ベクトル検索の再利用とレシピのスコアリング
  • レシピページ以外のアセット活用(記事、特集、カテゴリページ)
  • トレンドや訪問ユーザーのログを活用した記事の再生成

これらの改善により、更に品質の高い記事生成を目指していきます。

参考文献

Swift 6.2 @Observableの変更をAsyncSequenceで監視する

この記事は every Tech Blog Advent Calendar 2025 の 24日目の記事です。

はじめに

Swift 5.9で導入された Observation フレームワークは、@Observable マクロを用いた簡潔な記述が可能で、特にSwiftUIのView更新において高いパフォーマンスを発揮します。

一方で、既存の Combine フレームワーク(ObservableObject)からの移行を検討する際、課題となる点がありました。それは ViewModel や Service など、UI以外の場所での値の監視です。Combine では @Published プロパティのProjected Valueを用いて値の変化をストリームとして扱えますが、それと同等の標準的な手段がこれまでの Observation フレームワークには不足していました。

Swift 6.2では、この点が解消されています。@Observable クラスのプロパティの変化を AsyncSequence として監視する機能(Observations)が追加され、Combine に依存することなく、標準APIのみで値の監視が可能になりました。

本記事では、この新しい監視手法について整理します。

ObservableObject による値の監視

Observation フレームワークが登場する以前、SwiftUI では ObservableObject と Combine を用いた状態管理が一般的でした。

@Published プロパティの projected value($)を利用することで、値の変化をストリームとして扱える点は大きな利点でした。

import Combine

class CounterViewModel: ObservableObject {
    @Published var count: Int = 0
    private var cancellables = Set<AnyCancellable>()
}

let viewModel = CounterViewModel()

// $をつけることで Publisher として扱える
viewModel.$count
    .sink { value in
        print("count changed:", value)
    }
    .store(in: &viewModel.cancellables)

この仕組みにより、View の更新だけでなく、ViewModel や Service など UI 以外のレイヤーでも、値の変化を一貫した方法で監視できていました。この点は、ObservableObject が持つ強みの一つです。

Observation フレームワークと withObservationTracking

Swift 5.9 で Observation フレームワークが導入されると、View 更新のパフォーマンスと記述の簡潔さは大きく改善されました。一方で、View 以外で値の変化を検知する方法として利用されているのが withObservationTracking です。

import Observation

@Observable
class Counter {
    var value: Int = 0
}

let counter = Counter()

func observe() {
    withObservationTracking {
        // 1. ここで値を読む(アクセスする)ことで監視対象にする
        print("Current value: \(counter.value)") 
    } onChange: {
        // 2. 変更前(willSetタイミング)に呼ばれる
        print("Value will change...")
        
        Task {
            // 3. 再帰的に監視を続ける
            observe()
        }
    }
}

withObservationTracking は、クロージャ内で読み取られたプロパティへの依存関係を自動的に追跡し、それらが変更された際に onChange を呼び出します。これは SwiftUI の View 更新を支える中核的な仕組みです。

withObservationTracking の課題

しかし、この方法をロジック層で使うには、いくつかの問題がありました。

値そのものを直接受け取れない

onChange で通知されるのは「変更される」という事実のみで、変更後の値は再度読み取る必要があります。

再登録が必要

変更を継続的に監視するためには、onChange の中で再び withObservationTracking を呼び出す再帰的な実装が必要です。

非同期処理との相性

withObservationTracking 自体は同期的であり、Callbackベースの記述になるため、async/await のフローと組み合わせる際に直感的な記述が難しくなります。

Swift 6.2: AsyncSequence による監視の導入

Swift 6.2 では、こうした課題を解消する形で、@Observable クラスのプロパティの変化を AsyncSequence として監視できる Observations 型が追加されました。

import Observation

@Observable
class Counter {
    var value: Int = 0
}

let counter = Counter()

// 監視対象を定義
let counterChanges = Observations {
    counter.value
}

Task {
    for await value in counterChanges {
        print("value changed:", value)
    }
}

withObservationTracking が持っていた課題は解消され、簡潔な記述で安全に値の変化を監視できるようになりました。

Combine フレームワークに依存せず、自然な形でSwiftの並行処理モデルに直接統合されています。

まとめ

Swift 6.2 の Observations 導入により、ObservableObject が持っていた「Combine による値の監視」という優位性は解消されました。

ただし、この機能を利用するためには iOS 26以降の環境が必要となるため、サポートOSの要件によっては、すぐにプロダクションコードで全面的に採用することは難しいかもしれません。

とはいえ、「View 以外での監視」という最大の課題に対する標準的な解法が示された意義は大きく、安心して Observation への移行を進められる環境が整ったと思います。

Goエンジニアになって半年経ったので振り返る

Goエンジニアになって半年経ったので振り返る

この記事は every Tech Blog Advent Calendar 2025 の 23 日目の記事です。

はじめに

こんにちは!デリッシュキッチンで主にバックエンドの開発を担当している秋山です。

私は今年の6月にエブリーへバックエンドエンジニアとして中途入社し、そこから実務でGo言語を使い始めました。 それまでは約3年間主にRuby on Railsを触っていました。

この記事では、Goに転向して半年経った今感じていることや学びを振り返りたいと思います。

Goを使い始めて感じたこと

他の言語から来ると最初は戸惑う部分もありますが、使っていくとGoの良さが見えてきます。 ここでは、他言語から移ってきた人の視点で感じたことを書きます。

Goバージョン間の後方互換性が嬉しい

2012年にGoの1系が出てから毎年2回メジャーアップデートされますが、Goでは後方互換性の維持を考慮されています。 そのため、比較的容易にGoのバージョンアップを行うことができます。

業務の中でGoのバージョンアップを行わなければならないことがありました。 Goに触れる前は「メジャーアップデートに破壊的変更はつきもの」だと勝手に認識していたので、Goのバージョンアップの容易さに驚かされました。

後方互換性が保たれているおかげで「アップデートしたら動かなくなるかも」という不安が少なく、安心して最新バージョンを追えるのが良いポイントだと思います。

エラーハンドリングに違和感があった

Goで書かれたアプリケーションコードを初めて見た時の話です。 try/catch(rubyの場合はbegin/rescueですが)のエラーハンドリングに慣れていたこともあり、下記のようにnilチェックを行うエラーハンドリングに当時違和感がありました。

x, err := call()
if err != nil {
    return err
}

ちなみに、rubyでは通常このようにエラーハンドリングが行われます。

begin
  x = call()
rescue => e
  # call()で例外が発生した時にここの処理が実行される

今ではGoの書き方に慣れてきまして、エラーを値として扱うことで明示的に処理フローを追いやすくて良いなと思います。

GoのFAQが便利

他にもRuby/RailsからGoに移った時に

  • クラスってないの?
  • 継承ってないの?

などのような疑問が出ましたが、下記のFAQに回答がありました。

go.dev

このFAQを読んだだけでもGoの思想に対する理解を1歩進められそうです。

FAQ以外にもgithub上には議論が白熱しているissueやdiscussionもあるので、Goの機能追加の背景なども知れてより理解が深められそうです。

エラーハンドリングについても議論が白熱したみたいです。

github.com go.dev go.dev

AI活用で転向のハードルは下がっている?

AIにコードを書いてもらう機会が増えたり言語理解にAIを使用することができるようになり、新しい言語を学ぶハードルは確実に下がっていると思います。

ただ、Goを始める前「AIにコードを書いてもらうから転向もすんなりいけるかな」のように思っていた節がありましたが、実際にはそんなことはありませんでした。

日々の業務ではCursorを使わせてもらっており、Goの知識が少なかった私にとってはCursorは非常に強力なツールです。

しかし、AIが書いたアプリケーションコードを人間が全く確認せずにそのままリリースすることは現時点でリスクが高いので、AIが出力したコードをまずは自分でレビューします。 この時結局Goの知識がないとAIコードのレビューに時間がかかってしまいます。

また、チーム内でのレビューもGoの理解なしには難しいところがあるので、結局はGoの理解が大事だなと思いました。

Goエンジニアの成長を促進するエブリーの環境

Goエンジニアへの転向において、会社の環境も大きな助けになりました。

外部イベントへの積極的な参加

エブリーでは外部イベントの積極的な参加や登壇を推奨しており、実際に登壇を行っているメンバーもいます。 私自身も今年の9月に行われたGo Conference 2025に参加しました!

ちなみに、エブリーは今年もGo ConferenceにプラチナGoルドスポンサーとして協賛しました。

Go Conferenceの様子は下記ブログをご覧ください。

tech.every.tv

会社としてこのようなイベントに積極的に協賛しているのは私自身モチベーションにつながります。

また、つよつよエンジニアの方と話す機会もあり、僕もつよつよに成長したいと感じました。

定期的なGo勉強会

エブリーでは現在2週に1回の頻度でGoの勉強会が開催されています。

この勉強会では、持ち回りで担当者がテーマを持ってきて使い方を学ぶだけでなく、なぜそうするのか・どうしたら良さそうかなど参加者それぞれが疑問に思ったことをどんどん深掘りしていくスタイルになっています。

この勉強会に参加することで、日頃の業務で使っているだけでは得られないGoの知識をの取得や理解を深めることができています。 また既存のコードに対しても「本当はこの書き方の方が正しいよね」という気づきも多く、実務のコード品質向上にも繋がっています。

今後も日々邁進

AIが活躍する現在も言語理解や日頃の情報キャッチアップは大事だと思っています。 そのため、GoももちろんですがGoに限らずこれからも技術向上に邁進していきます!

参考

Go Workshop Conference 2025 IN KOBE に参加してきました!

この記事は every Tech Blog Advent Calendar 2025 の 22 日目の記事です。

こんにちは @きょー です!

先日 Go Workshop Conference 2025 IN KOBE に参加してきました。とても楽しかったので記事として皆さんにも共有できればなと思います!

会場の様子

はじめに

Go Workshop Conference とは?

gwc.gocon.jp

公式の HP にも書いてありますが、聞くだけでなく実際に手を動かすワークショップを中心とした Go 言語のイベントです。ソフトウェアからハードウェアなど幅広いワークショップがあり、Go 言語に関心のある方は楽しめる内容になっていました。

ワークショップは午前と午後に分けられ以下のようなものがありました。(資料は自分が見つけられたものを記載してます。既にアップロードされているもの等ありましたら@きょーまで連絡お願いします!)

午前に開催されたワークショップ

午後に開催されたワークショップ

どれも面白そうなワークショップですよね!自分は TinyGo を触ってみたいという思いから午前は「TinyGo Keeb Tour at GWC」午後は「Gopher くん基板を作って TinyGo で遊ぼう」に参加してきました。

何か選ぶということは何かを選ばないということ、魅力的なワークショップが集まっている中で二つしか選べないというのはとても苦しいものですね...

参加したワークショップ

午前の部、TinyGo Keeb Tour at GWC

まず席に着くと視界に映るハンダゴテ。普段の開発では触る機会が全くないためこの時点でハードをいじることへのワクワクと「Go Workshop Conference にきたんだ...!!」という実感が湧いてきて小躍りしそうになったのを覚えています。

以下の写真に写っているものを最初に配られました。

(余談ですが、この Gopher の基板デザインがとにかく可愛くて、TinyGo Conference の基板を再利用しているのもエコでいいなと思いました。)

ハンダゴテしやすいように台座(3D プリンターで作られたらしい)も用意していただいたのでそれを組み立てたりすると ↓ のような感じに。

裏側にも Gopher 発見!

実際にハンダ付けしている様子。

これは LED。こんな小さいけどお前、いけるのか、、、?

だんだん形になってきた。

ディスプレイ、スピーカーをつけて(さらば真ん中の Gopher)

キーボードもつけたら完成!!

実際に動かしてはないですが、ここまで形になるとなんかもう動きそうですね(というか動いてくれ...!!)

今回プログラムを載せる場所は普通のサーバーとは異なり ↑ の写真の左上のマイコンです。

言語は C? C++? いえ、ここは Go Workshop Conference。もちろん Go です。ただ普段使っている Go のバイナリを置こうとするとマイコンのスペック的に容量が足りなかったりするため、より小さいバイナリを作れる TinyGo というコンパイラを使っていきます。

tinygo.org

少し悲しくなりますがここからはハンダゴテは使わないのでさよなら、、、

パソコンと ↓ の README をもとに今まで作ってきた基盤を動かしていきます。

サンプルプログラムには LED を光らせたり、音を鳴らしたりするものだけでなく、ディスプレイとキーボードを使ってゲームをできるようにするものもありました。

無事自分の基盤でも LED を光らせることができました!感動!!(あの小さかった LED がこんなに発光するのすごい)

オーガナイザーの@さごさん、サポートしてくださったスタッフの方々、ハンダゴテをたくさん貸し出ししてくださった @ysaito さんありがとうございました!

昼の部、はじめての Go 体験!そしてあなたのキーキャップがおしゃれになる!

お昼ご飯を食べ終え会場に戻ってみると何やら面白そうなものを発見。キーキャップをデコってオシャレにできるらしい

自分も挑戦してみることに

最初にキーキャップのベースとなる色を決めていきます。いろんな色がありワクワクしてきますね。「こんな綺麗にできるのか?」という不安もありましたが一番下の右から二番目の色を選びました。直感です。

塗ったらライトを当てて固めていきます(硬化というらしい)

固まったらデコるために好きな素材を選んでいきます(写真撮るの忘れてしまったのですが、めっっっちゃ色々な素材がありました!)

自分は月、星、キャンディー、そして今の時期話題のクマを選びました。各素材が大きいのでキーキャップからはみ出てしまい載せるのが結構難しかったです。ただそこは運営の方々のサポートもあったのでなんとか思った形に完成させることができました!

テーマは「ゆめかわ」。我ながら満足のいく作品ができたと思っています。え、可愛くないですか???

午前中に作った基盤と合わせるとこんな感じ。ん〜〜〜可愛すぎて押せない!!

オーガナイザーの @micchieさん、@mikichinさんをはじめスタッフの方々ありがとうございました!

午後の部、Gopher くん基板を作って TinyGo で遊ぼう

午後も基盤をいじっていきます!

もう基盤が Gopher になっている時点でテンション上がりますね。このほかにも色々な基盤がありました。(写真撮り忘れた...orz)

オーガナイザーの satoken さんのブログに新作の武将 Gopher をはじめたくさんの基盤が載っているのでぜひ見にいってみてください!

zenn.dev

午前に比べるとハンダ付けも慣れたものでどんどん進めていくことができました。

まずはボタンをつけて

ディスプレイやスピーカー、マイコンなども取り付けて完成!

TinyGo で LED が光るプログラムをマイコンに置いて動作確認!( 資料: https://github.com/sat0ken/gopher-board-workshop/blob/main/README.md

光らず。原因を探っていきます。

ソフトウェアだけでなく、ハードウェアのデバッグもしていく必要があるため怪しいところを一つ一つ潰していきました。

  • ハンダ付けがしっかりできているか確認
  • プログラムは問題なくビルドできているか、マイコンに置けているか確認
  • ブレッドボードは問題ないか、使っているジャンパー線や LED は問題ないか確認

色々調べていくうちにジャンパー線が悪いことがわかり、交換してみると、、、

光った!!!

ただ LED が光るだけではありますが、ソフトウェア・ハードウェア全て繋がり思った挙動をしてくれるとめちゃくちゃ嬉しいですね。

何も分からなかったデバッグを一緒に手伝っていただいた方々本当にありがとうございました...!

ディスプレイに「私は Gophers!」と表示させてみたり

Gopher の画像を表示させてみたりしてたくさん遊ばせていただきました!楽しい!

最終的にここの画像は自分の推し日本酒である写楽を表示させたりして遊んでました。

写真からだとわかりずらいかもですが目の LED を高速でチカチカさせることもでき、その時の Gopher がかなりカオスで面白かったです。

オーガナイザーの @satokenさん、スタッフの方々ありがとうございました!

展示

会場には展示ブースもありました。

Go 製のゲームエンジンと、TinyGo を使ったハンコンを組み合わせた展示

こちらは@のぼのぼさんの展示です。

Go 製のゲームエンジンで開発されたレースゲームを、ハンドルコントローラーで操作できるようにする内部の仕組みを作られたそうです。コントローラーから送る信号も、ゲームから返ってくる信号も双方向でやり取りできるようにしているため、ゲーム内のアクションが手元にダイレクトに伝わってきて臨場感がすごかったです。

実際に運転してみた動画もあるのでよければ見てみてください!

https://x.com/Keyl0ve_/status/1999731494458392895?s=20

TinyGo と 3D プリンターなどの展示

こちらは@さごさんの展示です。

TinyGo と 3D プリンターを組み合わせた展示がいろいろ並んでいました。特にキーボード周りが面白く、手前に見える「Go」と表示されているものも自作とのこと。5x5 のキーボードを 4 つ組み合わせた基盤に合わせてプログラムを書く必要があり、こだわりが詰まっていました。

0 次会

懇親会まで時間があったので知り合った方々と 0 次会!こういう交流があるのもカンファレンスならではでいいですよね

懇親会

肝心の懇親会の写真を撮り忘れてしまいました。楽しいとついつい写真撮るの忘れてしまいますよね(他責)

Go Workshop Conference の参加者や運営の方々で集まりわいわい楽しく過ごせました!希望者で2次会にいったりもして本当に楽しい1日を過ごすことができました。

終わりに

改めてものづくりって楽しいなと思いました。普段のソフトウェア開発ももちろん楽しいですが、ハードウェアが組み合わさり目に見えてものが出来上がっていく様子は本当に楽しかったです。(小学校の図工の時間を思い出しました。)

また、今回はワークショップのみで構成されていたので、座学中心のカンファレンスとは違って「自分の手で体験を作る」感覚がとても強かったです。同じ枠に参加していても完成するものは人それぞれで、自分だけのワークショップカンファレンスを形にしているようで新鮮でした。

TinyGo についても学びが多かったです。Go のソースはそのままにコンパイラを TinyGo に切り替えるだけでバイナリのサイズが小さくなることや、ツールチェーンもほぼ Go と同じ感覚で触れることを学べた点が良かったです。

運営をはじめ、関わっていただいたスタッフの方々、一緒に楽しんでくださった参加者の皆様本当に楽しいカンファレンスをありがとうございました!