バックエンド開発を考えるエンジニアがGolangを選ぶ理由とプラットフォーム構築での注意点

Published on: | Last updated:

2023年のStack Overflow Developer SurveyでGoは「最愛言語」上位に入り、採用側の期待も一気に上がった(出典:Stack Overflow Developer Survey 2023)。

結論:Go 1.18以降のジェネリクスとgoroutineで土台は作れるが、プラットフォーム開発は「抽象化とDXの税金」を払い続ける前提で決める話になる。

  • 速い出荷:単一バイナリ配布と標準ツールで運用が軽い
  • 増える手作業:エラーハンドリングとボイラープレートが蓄積しやすい
  • 抽象の限界:型表現と合成の自由度は強めに制限される
  • 逃げ道:code generation、設定(YAML)、周辺ツールに複雑さが移動する
  • 向く領域:インフラ寄りの基盤、オペレーション安全性重視

タイトル:Goでプラットフォーム作る?できるけど、覚悟が要るやつ

たぶんね、最初は気持ちいいんだよ。Go。

言語が小さい。やることが見える。書いて、ビルドして、置く。終わり。

その「終わり」がね。プラットフォームだと終わらないの。

シンプルは無料じゃない。後から請求書が来る。

Goがバックエンドで強い理由はちゃんと現実的

Goは単一バイナリ配布(静的リンクで依存をまとめる方式)ができ、go build・go test・go fmt(標準ツールチェーン)が揃っているから、運用が軽い。

goroutine(軽量スレッド)とchannel(安全にデータを渡す仕組み)で並行処理が書きやすく、マイクロサービスの横展開に向く。

ここはね、私も否定しない。ほんと楽。

「環境差で動かない」が減る。バイナリ一個って強い。

CIでgo test回して、go fmtで整えて、デプロイ。はい。みたいな。

でも:バックエンドが得意なのと、プラットフォームが得意なのは別の筋肉。

バックエンドは「自分たちが使う」ことが多い。

プラットフォームは「他人が使う」。しかも長期。

図1:Goで「サービス」から「プラットフォーム」に行く時の景色
図1:Goで「サービス」から「プラットフォーム」に行く時の景色

プラットフォームで一番しんどいのはDXの細部

プラットフォーム開発はDX(Developer Experience、開発者体験)を設計し続ける仕事で、APIの誤用を防ぐ型設計と拡張性がコストの中心になる。

Goは言語機能を増やしすぎない方針なので、抽象化・合成・表現力を欲張る設計だと自前の仕組みが増えやすい。

これ、ほんとね。

動くかどうかより、使われ方が壊れる。

使う人が増えるほど、優しい設計が要る。意地悪な罠を潰す作業が増える。

進階の指標:サービスならp95レイテンシやエラー率を見る。プラットフォームは「オンボーディング時間」「破壊的変更の頻度」「拡張ポイントの数」「互換性ポリシー」が効いてくる。

数字で言うと、社内の新規参加者が「最初のPRまで何日かかった?」みたいなやつ。地味。刺さる。

ジェネリクスは来たけど魔法じゃない

Go 1.18のgenerics(型パラメータで再利用コードを書く仕組み)は導入されたが、RustやTypeScriptほど表現力が強い設計ではなく、イディオムも発展途上だ。

ジェネリクス以前のinterface{}と型アサーション依存は、冗長さと安全性の揺れを生み、プラットフォームの再利用部品を作りにくくした。

「やっと来たね」って空気、覚えてる。たぶんみんな。

でも、来た瞬間に全部きれいになるわけじゃない。

ジェネリクスって、道具箱に新しいドライバーが増えた感じ。

家が勝手に建つわけじゃない。うん。

よくあるズレ:プラットフォーム側は「型で誤用を防ぐ」方向に寄せたい。Goは「分かる範囲で止める」感じが強い。

結果。ドキュメントとテストに頼る割合が上がる。

エラーハンドリングが増殖して手が止まる瞬間

Goの明示的エラー処理は可読性が高いが、プラットフォームの複雑な失敗経路ではif err != nilの反復がDXを削りやすい。

例外・パターンマッチ・高度な伝播機構が標準でないため、リトライや依存解決を綺麗に書くには設計と規約が必要になる。

if err != nil {
    return err
}

この3行、嫌いじゃないの。正直。

でもね。プラットフォームだと、ここが何十回も出てくる。

同じ景色が続くと、人は注意力が落ちる。

落ちると事故る。

小さい事故が積もって、ある日「この基盤、触るの怖い」になる。

対策の方向:エラーをラップするルール、sentinel error、errors.Is/Asの使い分け、ログ相関IDの付与。全部、言語じゃなくて運用で支える。

この「運用で支える」が、税金っぽいんだよね。

図2:Goのエラーが増えた時に起きる分岐の流れ
図2:Goのエラーが増えた時に起きる分岐の流れ

言語機能が少ないぶん 足場を自作しがち

Goは代数的データ型(ADT)や強いイミュータブル支援が標準でなく、複雑なドメインモデリングを型で表すのが得意ではない。

その結果、依存性注入やDSL的APIは、コード生成や規約で補う設計になりやすい。

ここでね、ふっと思い出すのがKubernetes。

Goで巨大なものを作った代表。KubernetesもDockerもGo。事実。

でもKubernetesのコード、読んだことある人は分かる。長い。深い。インターフェースが多い。生成コードも多い。

(出典:Kubernetes Project 公開リポジトリ、設計ドキュメント群)

逃げ方:複雑さがGoの中じゃなく、YAMLや設定、独自CLI、独自スキーマに移動する。

あの「YAMLで地獄」ってやつ。ある。

ほんと、ある。

コードがシンプルでも、システムがシンプルとは限らない。

インターフェースは強いけど 大規模だと脆い

Goのinterfaceは暗黙実装で差し替えが容易だが、バージョニングやオプション挙動が増えると設計の曖昧さが露出しやすい。

プラットフォームでは互換性ポリシーと拡張ポイントの管理が重要で、interfaceの埋め込みが複雑化すると理解コストが跳ねる。

小さいチームのうちはね、interface最高ってなる。

差し替えできる。テストも楽。うん。

人が増える。機能も増える。プラグインも増える。

その時に「どのinterfaceが正?」が揺れ出す。

揺れる設計は、揺れる文化を呼ぶ。怖い。

それでもGoでプラットフォームを選ぶ場面はある

Goは運用単純性と性能効率が高く、コンテナ管理やジョブ実行などインフラ寄りプラットフォームでは適合しやすい。

チームがGoに習熟している場合、学習コストを抑えつつ、標準ツールで統一できる利点が大きい。

ここ、ちょっと元気出る話。

Goが合う場面、ちゃんとある。

Goでプラットフォームを作る時のpros/cons
pros cons
単一バイナリで配布が軽い。現場が助かる。 抽象化が弱め。拡張APIが増えるほど苦しくなる。
goroutineで並行処理が書きやすい。スループットが出る。 エラー処理の反復が積もる。読む人の集中力が削れる。
標準ツールが揃う。go test/go fmtで文化が作れる。 コード生成や規約が増える。ルールが人を縛る。
運用が素直。観測・デプロイのパイプが作りやすい。 複雑さがYAMLや独自CLIに移動しがち。別の地獄。

日本の現場っぽい話:社内基盤って、異動で人が入れ替わる。年度で体制が変わる。引き継ぎ資料が命。

Goの「書いたら動く」は救いになる。

その代わり「設計ルール」が文章で残ってないと崩れる。

このバランス。

通路の定錨:採用の会話はconnpassの勉強会とか、社内のSRE/Platformチャンネルとかで一気に進むことが多い。そこに「運用が軽い」って話は刺さりやすい。

刺さる。ほんと。

スクショ用 自己チェックリスト 迷ったらここを見る

Goでプラットフォームを作る判断は「Kubernetesみたいに成功例がある」だけで決めず、DXの負債と運用メリットを同じ紙に並べて評価する。

判断材料にはジェネリクス活用範囲、エラー設計、互換性ポリシー、設定地獄の回避策を含めるとズレにくい。

ここ、ほんとにスクショしていい。

あとで見る用。

  • 使う人は誰:社内の少人数?全社?外部開発者?
  • DXの目標:オンボーディングを何日で終わらせたい?最初の成功体験はどこ?
  • 互換性:SemVer(互換性の約束方針)を採用する?破壊的変更の手順は書いた?(出典:Semantic Versioning 2.0.0
  • 型の表現:ドメインが複雑?enum相当が欲しい?ADTが欲しい?
  • エラー設計:errors.Is/Asの規約は?ログの相関IDは?
  • 設定の量:YAMLが増える設計になってない?検証はJSON SchemaかOpenAPIで縛れる?(出典:OpenAPI Specification)
  • 生成コード:code generationを採用するなら、生成物のレビュー方針は?
  • 観測:OpenTelemetry(分散トレーシングの標準)を最初から入れる?(出典:OpenTelemetry)
  • 採用:Go経験者を採れる?育てる?異動があっても回る?

チェックが多いほど、Goがダメって話じゃない。

税金の見積もりができるかどうか。

そこ。

FAQ 直答

規則:質問は4つ。答えは短く、断言で言い切る。

Q:Goでプラットフォームは作れる?

Goでプラットフォームは作れるが、抽象化・互換性・DXを言語機能で支えにくいので、規約とツールで補う前提が必要だ。

Q:ジェネリクスがあるなら問題ない?

Go 1.18のジェネリクスは再利用性を上げるが、型表現の自由度は限定的で、設計の苦しさが消えるわけではない。

Q:エラー処理の冗長さは慣れで解決する?

エラー処理の反復は慣れでは消えず、規約・ラップ方針・観測設計で事故を減らす運用コストが残る。

Q:Goが一番向くプラットフォームは?

Goはインフラ寄りの基盤、CLI、オーケストレーション、コンテナ運用のような運用単純性が価値になる領域で強い。

作れるかじゃない。作った後に誰が守れるか。

図3:Goで「税金」を払う場所の見取り図
図3:Goで「税金」を払う場所の見取り図

免責っぽい一言:言語選定は組織の状況で結果が変わる。ここに書いたのは一般論と現場のあるあるで、特定の正解を保証する話ではない。

私が覚えてるのはね。

「Goで統一しよう」って言った瞬間、みんな少し安心した顔をする。

でも半年後、設定ファイルが増えて、生成コードが増えて、ドキュメントが追いつかなくなる。

それでも、運用は安定してる。

その安定のために、誰かが夜にルールを書いてる。

金句:シンプルを選ぶなら、請求書にサインする覚悟も一緒に持つ。

Related to this topic:

Comments