Go言語 2025 - バックエンドで選ばれる理由

15分 で読める | 2026.01.12

公式ドキュメント

2025年のバックエンド選定で、Goは有力な候補です。

理由は「どの処理でも最速だから」ではありません。言語仕様が比較的小さく、並行処理を記述しやすく、HTTPサーバーを標準ライブラリで作れ、単一の実行ファイルとして配布しやすいからです。

一方、既存チームの経験や業務領域を無視して選べる万能言語でもありません。

この記事ではGo 1.22と1.23の代表的な変化を確認しながら、2025年のバックエンドでGoを選ぶ条件を整理します。

2025年にGoが候補になる理由

Goの強みは、個別機能より組み合わせにあります。

  • 読み方を揃えやすい単純な構文
  • goroutineによる並行処理
  • HTTP、JSON、暗号、テストなどの標準ライブラリ
  • クロスコンパイルしやすい単一バイナリ
  • formatter、test、vet、profileを含む公式tooling

APIサーバーやネットワークサービスでは、これらを同時に使います。

採用判断では、人気や印象ではなく「チームが運用するサービスに、この組み合わせが合うか」を見ます。

単純さは共同開発のための機能

Goは、書き方の選択肢を意図的に絞っています。

たとえば公式formatterの gofmt によって、インデントや空白の議論を減らせます。

gofmt -w .
go test ./...
go vet ./...

コードレビューでは書式より、エラー処理、境界条件、データ競合、API設計に時間を使えます。

明示的なエラー処理も特徴です。

user, err := repository.Find(ctx, id)
if err != nil {
    return User{}, fmt.Errorf("find user: %w", err)
}

失敗経路が行として見えるため、ログやHTTP statusへの変換位置を追いやすくなります。

ただし、同じ形の if err != nil が増え、冗長に感じる場面もあります。短さより制御の見通しを優先する設計です。

単純さにも学習が必要

構文が小さいことと、本番コードが簡単であることは同じではありません。

次の設計は別途学ぶ必要があります。

  • context.Context によるcancelとdeadline
  • goroutineの終了条件
  • channelのclose責任
  • interfaceを置く境界
  • errorのwrapと分類
  • database transaction
  • graceful shutdown

Goを選ぶだけで設計上の問題が消えるわけではありません。

goroutineは軽量な並行実行単位

goroutineは go を付けて関数を並行実行する仕組みです。

go sendAuditLog(event)

OS threadを直接1本ずつ管理するより軽量で、Go runtimeが多数のgoroutineをthreadへ割り当てます。

複数の外部APIを待つ処理や、connectionごとに仕事を扱うserverと相性があります。

profileCh := make(chan Profile, 1)
ordersCh := make(chan []Order, 1)

go func() {
    profileCh <- fetchProfile(ctx)
}()

go func() {
    ordersCh <- fetchOrders(ctx)
}()

profile := <-profileCh
orders := <-ordersCh

この例は値だけを返す形に絞っています。実際にはcontextによるcancelと、各処理のerrorを呼び出し元へ返す経路も設計します。channelを一つにまとめて受信順に変数へ代入すると、どちらの結果か取り違えるため、型または識別子で対応付けます。

重要なのは「並行にした」だけでは安全にならない点です。

共有memoryへ複数goroutineが同時に書けばdata raceが起きます。終了しないgoroutineはresourceを保持し続けます。

go test -race ./...

race detectorは有力な検査ですが、実行した経路だけを観察します。設計とtestの代わりにはなりません。

標準ライブラリだけでHTTP APIを始められる

Goの net/http にはserverとclientの両方があります。

Go 1.22では ServeMux のpatternが拡張され、HTTP methodとwildcardを表せるようになりました。

package main

import (
    "encoding/json"
    "net/http"
)

func main() {
    mux := http.NewServeMux()

    mux.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
        id := r.PathValue("id")
        w.Header().Set("Content-Type", "application/json")
        json.NewEncoder(w).Encode(map[string]string{"id": id})
    })

    http.ListenAndServe(":8080", mux)
}

小さなAPIなら、routingのためだけにframeworkを追加せず始められます。

標準ライブラリにはJSON、SQL、TLS、structured logging、test、contextも含まれます。依存を減らせることは、更新対象や供給網riskを減らす助けになります。

ただし、認証、validation、migration、observabilityまで全部標準で完成するわけではありません。必要な外部packageは、保守状況と更新方針を確認して採用します。

単一バイナリは配布を単純にする

Goは通常、依存を含む実行ファイルへcompileできます。

CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o app ./cmd/api

実行環境へ言語runtimeやpackage managerを別途用意せず、binaryを起動できます。

containerでも構成を小さくしやすく、起動手順を揃えやすい点が利点です。

FROM gcr.io/distroless/static-debian12
COPY app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]

ただし、次には注意が必要です。

  • CA証明書やtimezone dataが必要か
  • cgoを使う依存がないか
  • target OSとarchitectureが正しいか
  • debug用shellがない環境をどう観測するか

単一binaryは運用を単純にしますが、監視や設定管理を不要にはしません。

toolingが開発cycleを揃える

Goは基本的な開発toolを公式配布に含めます。

go mod tidy
gofmt -w .
go vet ./...
go test ./...
go test -race ./...
go build ./...

CPUやmemoryを調べる pprof、実行中のgoroutineやblockingを調べるtraceも標準のecosystemにあります。

言語、build、test、format、module管理の入口が揃っているため、repositoryごとの手順差を減らせます。

一方、静的解析やsecurity scanは追加toolも必要です。公式toolだけで品質保証が完了すると考えないことが大切です。

Go 1.22の代表的な変更

Go 1.22は2024年2月に公開されました。

バックエンド開発で分かりやすい変更は3つです。

loop変数がiterationごとに作られる

以前はloop変数をclosureから参照すると、意図せず同じ変数を共有するbugが起きやすい状態でした。

Go 1.22では、該当するmoduleで各iterationに新しい変数が作られます。

for _, user := range users {
    go func() {
        notify(user)
    }()
}

ただし、挙動はmoduleの go versionと関係します。upgrade時は go.mod とtestを確認します。

integerへrangeできる

for i := range 3 {
    fmt.Println(i)
}

012 の順に処理できます。

ServeMuxのpatternが強化された

mux.HandleFunc("DELETE /users/{id}", deleteUser)

methodとpath parameterを標準routerで扱えます。

既存patternとの競合や波括弧の扱いが変わる可能性があるため、古いrouterから切り替えるときはroute testを実行します。

Go 1.23の代表的な変更

Go 1.23は2024年8月に公開されました。

range-over-function iterator

function形式のiteratorを range で扱えるようになりました。

func IDs(users []User) iter.Seq[int64] {
    return func(yield func(int64) bool) {
        for _, user := range users {
            if !yield(user.ID) {
                return
            }
        }
    }
}

利用側は通常のrangeに近い形です。

for id := range IDs(users) {
    fmt.Println(id)
}

独自collection APIを作る選択肢が増えましたが、単純なsliceで十分ならiteratorを導入する必要はありません。

timerとtickerの変更

Go 1.23では、該当するmoduleで回収されていないTimerやTickerをgarbage collectorが回収できるよう改善されました。

またtimer channelは同期channelになり、ResetStop 後の古い値に関する挙動が改善されています。

既存コードがchannelのcapacityや古い非同期挙動へ依存していないか、version更新時にtestします。

iter、slices、maps

標準ライブラリに iter packageが加わり、slicesmaps にiterator関連functionが追加されました。

新機能は便利ですが、upgrade理由を「新しいから」にしません。security fix、toolchain support、依存moduleの要件も含めて更新計画を立てます。

Goを選ぶときのtrade-off

成熟したframeworkの機能量

別言語の大規模frameworkには、ORM、管理画面、認証、form処理などが統合されている場合があります。

Goは必要な部品を選び、applicationの境界を自分で設計する場面が多くなります。

短期間で業務画面を大量に作る案件では、既存frameworkの方が速いことがあります。

型表現とdomain modeling

Goの型は実用的ですが、高度な代数的data typeやpattern matchingを中心に設計したいteamには物足りない可能性があります。

ecosystemと採用

既存system、teamの経験、採用市場、社内libraryを無視した言語変更はcostを増やします。

Go自体の習得だけでなく、monitoring、deployment、incident対応まで含めた運用能力を見ます。

向いている場面

  • HTTP APIやgRPC service
  • network proxyやgateway
  • 多数のI/O待ちを扱うservice
  • command line tool
  • 小さなcontainer imageと単純な配布を重視する環境
  • 複数teamで書き方を揃えたいcodebase

既存frameworkへ強く依存する業務system、data science、GUI、極端なreal-time制約では慎重に比較します。実装可能かではなく、他の選択肢より総costが低いかで判断します。

選定checklist

workload

  • I/O待ちの多い処理か
  • 必要なthroughputとlatencyを計測できるか
  • CPU、memory、connection数の上限は何か

team

  • error、context、goroutineをreviewできるか
  • data raceとgoroutine leakをtestできるか
  • on-call担当がprofileを読めるか

ecosystem

  • database driverとmigration toolが要件を満たすか
  • 認証、observability、code generationの候補が保守されているか
  • 既存serviceとのprotocolを共有できるか

operation

  • target OSとarchitectureを管理できるか
  • graceful shutdownとhealth checkを実装できるか
  • Go versionとmodule更新を継続できるか

移行では、書き直す効果、小さく試す境界、rollback方法を確認します。不明点が多ければ全面移行より小さな検証から始めます。

導入は小さく検証する

候補serviceを1つ選び、同じtraffic条件で比較します。

見る値は単純なrequest/secondだけではありません。

  • 実装とreviewにかかった時間
  • binaryとcontainerのsize
  • 起動時間
  • p95・p99 latency
  • memoryとCPU
  • error率
  • deployとrollbackの容易さ
  • 障害時の調査時間

公開benchmarkではなく、自分たちのdatabase、認証、loggingを含む条件で測ります。

まとめ

2025年のGoは、backendの有力候補です。

価値の中心は、単純な言語、goroutine、充実した標準library、単一binary、統一されたtoolingの組み合わせにあります。

Go 1.22ではloop変数、integer range、ServeMuxが改善され、Go 1.23ではrange-over-functionやtimer関連が更新されました。

ただし、新機能や人気だけでは採用理由になりません。

teamの経験、既存資産、必要なlibrary、運用方法、実workloadの計測を揃え、小さなserviceから判断するのが現実的です。

関連記事

参考リソース

← 一覧に戻る
PR
PR
PR
PR