stackbook

← 辞書(分野別)

§2

言語の決め方と言語別の既定

最終確認:2026年9月

2-1. TypeScript(Node.js)

ランタイム
Node.js(LTS)
  • Bunスクリプト・CLI・新規の小規模APIで速度を重視するとき
  • DenoDeno Deploy前提のとき

BunはAnthropicの傘下に入った(ライセンスはMITのまま)

パッケージマネージャ
  • BunランタイムもBunにする場合
モノレポ
  • Nx大規模でコード生成や依存グラフの可視化が必要なとき
Lint+フォーマット
Biome(1ツールで完結・高速)
型チェック
tsc --noEmit(strict: true)
テスト(ユニット)
  • Jest既存プロジェクトのみ
テスト(E2E)
APIモック
バリデーション
  • Valibotバンドルサイズを極限まで削りたいフロント
HTTPフレームワーク
Hono(軽量・どこでも動く・型安全なRPC)
  • NestJS10人以上のチームでDI・モジュール構造を強制したいとき
  • FastifyNode専用で既存プラグイン資産を使いたいとき
OpenAPI
@hono/zod-openapi(Zodスキーマからルートと仕様を同時に定義)
ORM/クエリ
Drizzle(SQLに近い・軽い・エッジ対応)
  • Prismaスキーマ駆動でGUI(Studio)やマイグレーションの手厚さを重視するとき
  • KyselyORMを使わず型付きクエリビルダーだけ欲しいとき
マイグレーション
ジョブキュー
pg-boss(Postgresベース、§4-3)
  • BullMQ(Redis/Valkey)秒間数百件を超える、またはValkeyが既にあるとき(§23-1)
  • Inngest/Trigger.devサーバーレス環境でワークフロー(リトライ・待機・ステップ実行)が必要なとき
ロギング
設定・環境変数の検証
Zodでスキーマ定義して起動時に検証(t3-envなど)
日付
  • Temporal API対応環境が揃っていればネイティブを使う
  • Day.js軽さ最優先
HTTPクライアント
fetch(標準)
  • kyリトライやフックを簡潔に書きたいとき
ビルド(ライブラリ)
  • tsup既存プロジェクトのみ(tsupは保守されていないため、機会があれば移行する)
実行(開発時)
Node.jsの型除去による直接実行(node --watch)
  • tsxenum・デコレータなど型除去で消せない構文や、パスエイリアスを使うとき
脆弱性チェック

2-2. Go

依存管理
Lint
golangci-lint(設定ファイルで有効ルールを明示)
フォーマット
gofumpt(gofmtより厳格)
  • gofmtチームに合わせる場合
HTTPルーティング
標準 net/http(メソッド・パスパラメータ対応済み)+ ミドルウェアは自前か小さなライブラリ
  • chiミドルウェアのエコシステムを使いたいとき
  • Echoフレームワーク一式を求めるチーム
DBドライバ
クエリ
sqlc(SQLから型安全なコードを生成)
  • entグラフ構造のスキーマが中心のとき

GORMは暗黙の挙動が多く、性能問題の調査が難しいため選ばない(§20)

マイグレーション
  • Atlas宣言的スキーマ管理(あるべき状態から差分生成)をしたいとき
  • golang-migrate既存プロジェクト
OpenAPI
oapi-codegen(スキーマファースト)
  • ogen生成コードの性能・厳密さを重視するとき
RPC
Connect(connect-go)
  • gRPC既存のgRPC基盤がある場合
ジョブキュー
River(Postgresベース、トランザクション内でジョブ投入可能)
  • AsynqRedis前提のとき
ロギング
log/slog(標準)
設定
環境変数+envconfig(caarlos0/env など)
  • koanf複数ソース(ファイル・環境変数・リモート)を統合したいとき
CLI
テスト
標準 testing + go-cmp
  • testifyアサーションを簡潔にしたいチーム
統合テスト
testcontainers-go(実DBでテスト)
モック
インターフェース+手書きフェイク
ホットリロード
脆弱性チェック
リリース

2-3. Ruby / Rails

Railsの標準構成(「Rails omakase」)にできるだけ乗る。外部依存を増やさないことが最大のメリットになる。

バージョン管理
依存管理
Lint+フォーマット
RuboCop(rubocop-rails-omakase)
  • Standard設定を一切考えたくないとき
テスト
Minitest(Rails標準)+ fixtures
  • RSpec+FactoryBotチームがRSpecに慣れている、または既存資産があるとき
システムテスト
Capybara+Selenium(Rails標準)
フロント
Hotwire(Turbo+Stimulus)+ importmap
アセット
Propshaft(Rails標準)
コンポーネント
  • PhlexRubyだけでビューを書きたいとき
ジョブ
Solid Queue(DBベース)
  • Sidekiq非常に高スループットが必要なとき
キャッシュ
  • Redis既存のRedis基盤がある場合
WebSocket
  • AnyCable同時接続数が非常に多いとき
認証
Railsの認証ジェネレータ
  • DeviseOAuth連携・多要素認証など機能を一式揃えたいとき
  • Rodauth高度なセキュリティ要件
認可
  • Action Policyルールが複雑でキャッシュやテスト支援が欲しいとき
管理画面
ページネーション
ファイル
デプロイ
セキュリティ静的解析
依存の脆弱性
N+1検出
  • Bullet開発中にブラウザ上の通知でN+1を知りたいとき
モバイル

2-4. Python(AI/ML、データ処理が必要な場合に限定)

バージョン・依存管理
uv(Python本体の導入からロックファイルまで1本)
  • Poetry既存プロジェクト
Lint+フォーマット
型チェック
  • mypy既存プロジェクトが使っているとき
テスト
Webフレームワーク
  • Django管理画面付きのCRUDアプリをPythonで作る必要があるとき
バリデーション
ORM
SQLAlchemy(2.x形式)
  • SQLModelFastAPIと密に統合したい小規模案件
マイグレーション
HTTPクライアント
ジョブ
ロギング
データ処理
  • pandasライブラリ連携上必要なとき
ノートブック
  • marimoGitで差分管理しやすいノートブックが欲しいとき

2-5. Rust

ビルド・依存
Lint/フォーマット
非同期ランタイム
Webフレームワーク
DB
シリアライズ
ロギング/トレース
CLI
エラー
thiserror(ライブラリ)/ anyhow(アプリ)
テスト実行
ベンチマーク
  • divan記述を簡潔にしたいとき
脆弱性チェック
バイナリ配布
  • GoReleaser(Rust対応あり)Goと配布の仕組みを揃えたいとき
クロスコンパイル
  • crossDockerで環境ごと切り替えたいとき
WebAssembly
Node.jsから呼ぶネイティブ拡張
Pythonから呼ぶネイティブ拡張
デスクトップアプリ
Tauri(UIはWeb技術、裏側はRust)
  • ElectronNode.jsのAPIやChromiumの挙動に強く依存するとき
組み込み(非同期)
  • RTIC割り込み駆動で厳密なリアルタイム性が必要なとき
gRPC

2-6. Kotlin(JVM)

既存のJava資産との連携、複雑な業務ルール、大規模バッチ、Kafkaなどのストリーム処理で選ぶ。

JDK
Eclipse Temurin(LTS)をmiseで管理
ビルド
Gradle(Kotlin DSL)
  • Maven既存プロジェクト
Lint/フォーマット
Webフレームワーク
  • Ktor軽量に作りたい、Springの規模が過剰なとき
DBアクセス
jOOQ(SQLに近い型安全なクエリ)
マイグレーション
  • LiquibaseDBの種類を横断して管理したいとき
非同期
Kotlinコルーチン
シリアライズ
Jackson(Spring標準)
テスト
JUnit + Kotest(アサーション)+ MockK
統合テスト
バッチ
ストリーム処理
ロギング
SLF4J+Logback(JSON出力)
コンテナ化
Jib(Dockerfileなしでイメージ作成)
起動速度の改善
通常は不要
  • GraalVMネイティブイメージサーバーレスで起動時間が問題になるとき

2-7. Elixir(BEAM)

大量の常時接続、プレゼンス(誰がオンラインか)、障害からの自動復旧が中心の常駐サービスで選ぶ。

バージョン管理
mise(Erlang/Elixir)
ビルド・依存
Mix + Hex
フォーマット
Lint
型チェック
Dialyxir(Elixir本体の型システムも段階的に強化中)
Webフレームワーク
  • Plug単体APIだけの極小サービス
画面
Phoenix LiveView(サーバー主導でリアルタイムUI)
リアルタイム
DB
Ecto(マイグレーション含む)
ジョブ
Oban(Postgresベース)
データパイプライン
Broadway(SQS・Kafka等からの消費)
HTTPクライアント
テスト
セキュリティ静的解析
デプロイ
mix release をDockerイメージ化 → ECS/Fly.io/Kamal

2-8. C#(.NET)

Unityのクライアントとサーバーでコードを共有したいとき、Microsoft/Azure中心の環境、Windows前提の業務システムで選ぶ。

SDK
.NET(LTS)をmiseで管理
ビルド・依存
フォーマット/Lint
dotnet format + .NETアナライザー(.editorconfigで設定)
Webフレームワーク
ASP.NET Core(Minimal API)
  • コントローラー方式大規模で構造を揃えたいとき
DBアクセス
  • DapperSQLを直接書いて性能を詰めたいとき
マイグレーション
リアルタイム
Unityとの通信
MagicOnion(gRPCベースでC#の型をクライアントと共有)
ジョブ・スケジュール
テスト
ロギング
Serilog(構造化ログ)
OpenAPI
ASP.NET Core標準のOpenAPI生成 + Scalar
コンテナ化
dotnet publish のコンテナ出力
  • DockerfileOSパッケージの追加などビルドを細かく制御したいとき

2-9. 作成物ごとの言語の決め方

言語は「何を作るか」で決まる。下表で当てはまる行を探して既定を使い、右の列の条件に当てはまるときだけ乗り換える。バックエンドはさらに細かく §2-10 で判断する。

CRUD中心のWebアプリ・管理画面
Rails(画面の多い業務システムを最も速く作れる)
  • TypeScript外部API連携が中心、またはReactで画面を作り込みたいとき
  • Kotlin業務ルールが非常に複雑で、既存のJava資産と連携するとき
一般的なWeb API・SaaSのバックエンド
TypeScript(フロントと1言語に揃う)
  • Go3人以上で公開APIを長期運用するとき(§2-10 手順3)

負荷の性質で決まる場合は §2-10 を優先する

CLIツール
  • Rust起動時間・バイナリサイズ・処理速度を詰めたい
  • TypeScript(Bun)社内向けでnpmの資産を使いたい
インフラ系ツール(Kubernetes Operator、Terraformプロバイダ等)
Go(公式SDKがGo中心)
開発者向けツール(Linter、フォーマッタ、ビルドツール、パーサ)
  • Go処理が軽く、開発速度を優先したいとき
ブラウザ内の重い処理(画像・動画処理、暗号、大量データの解析)
エッジ関数
TypeScript(Cloudflare Workers)
他言語から呼び出すライブラリ
Rust(napi-rs、PyO3など)
デスクトップアプリ
  • ElectronNode.jsのAPIに強く依存するとき
  • C#(.NET)Windows専用の業務アプリ
モバイルアプリ
  • Kotlin/Swift(ネイティブ)端末機能を深く使うとき
  • Flutterデザインの一貫性を最優先するとき
ゲームのクライアント
エンジンに従う(Unity:C#、Unreal:C++)
組み込み・IoT・ファームウェア
  • CベンダーSDKがCしかないとき
データベース・検索エンジン等の基盤ソフト
  • GoGCの影響が許容できる分散系の制御部分
データ分析・集計
SQL(DuckDB、BigQuery、Postgres)
  • Python(Polars)SQLで表現しにくい変換があるとき
機械学習の学習・推論
  • Rust(candle等)小さなモデルを単一バイナリで配りたいとき
LLM API呼び出し中心のAIアプリ
  • Python埋め込み処理や評価などML系ライブラリを本格的に使うとき
スクリプト・社内の小さな自動化
TypeScript(Node.jsで直接実行、またはBun)
  • Go単一バイナリで配りたいとき
  • シェルスクリプト数行で済むとき

2-10. バックエンドの言語の決め方

バックエンドは「どんな負荷がかかるか」と「何に依存するか」で最適な言語が変わる。以下の順に確認し、最初に当てはまったところで決める。

手順1:外部の制約で決まるか

実行環境の制約、コードを共有する相手の制約、組織の制約、ライブラリの制約の順に確認する(実行できない言語は、ライブラリがあっても選べないため)。

実行環境がエッジ(Cloudflare Workers等)

選ぶ言語TypeScript

Unityのクライアントとモデルや通信定義を共有したい

選ぶ言語C#

既存のJava資産(社内基盤、外部の業務パッケージ)と密に連携する

選ぶ言語Kotlin

Microsoft/Azure中心で、運用チームが.NETに慣れている

選ぶ言語C#

必須のライブラリ・SDKが特定の言語にしかない(機械学習、特定ベンダーのSDK等)

選ぶ言語その言語(機械学習ならPython)

Kubernetes・クラウドのコントロールプレーンを扱う

選ぶ言語Go

手順2:負荷の性質で決める

DBの読み書きと業務ロジックが中心

第一候補TypeScript(画面の多い業務システムなら Rails)

次点Go(3人以上で公開APIを長期運用するとき)

典型例管理画面、予約、受発注、SaaSの大半

理由ボトルネックはDB。言語の性能差はほぼ効かないので、開発速度とチームで選ぶ

外部APIの待ち時間が中心

第一候補TypeScript

次点Go

典型例BFF、複数APIの集約、Webhook中継

理由非同期I/Oの書きやすさと、フロントとの型共有

大量の常時接続(数万接続以上が目安、§23-3)

第一候補Elixir

次点Go

典型例チャット、プレゼンス、通知配信、共同編集

理由軽量プロセスで数十万規模の接続を扱え、落ちた処理を自動で再起動する仕組みが言語に組み込まれている。それ未満のチャットや通知はマネージド(§19-9)で足りる

中程度の常時接続+高スループット

第一候補Go

次点Rust

典型例APIゲートウェイ、プロキシ、ゲームのロビー

理由goroutineで並行処理が簡潔に書け、運用も単純

レイテンシの上振れが許容できない(p99で10ms未満が厳格に必要、§23-3)

第一候補Rust

次点Go

典型例広告入札、取引、リアルタイム対戦の判定

理由GCによる停止がない

CPU負荷の高い計算

第一候補Rust

次点Go

典型例画像・動画変換、圧縮、暗号、シミュレーション

理由ネイティブ性能とメモリ効率

数値計算・機械学習

第一候補Python

次点Rust(推論のみ)

典型例推論API、レコメンド、特徴量計算

理由ライブラリがPythonに集中している

複雑な業務ルールと厳密な状態管理

第一候補Kotlin

次点Go、TypeScript

典型例会計、金融、保険、大規模な在庫・物流

理由sealed classなどで状態を型で表現しやすく、トランザクションやバッチの基盤が成熟している

大規模バッチ

第一候補Kotlin(Spring Batch)

次点Go、Python

典型例夜間の一括計算、請求締め、データ移行

理由再実行・中断再開・分割実行の仕組みが揃っている

ストリーム処理

第一候補Kotlin(Kafka Streams)

次点Go

典型例Kafkaのイベント集計、リアルタイム分析

理由Kafka周辺のエコシステムがJVM中心

長時間ワークフロー

第一候補言語よりエンジンで決める:Temporal(Go/TypeScript)

次点Step Functions

典型例決済→発送→通知、人の承認待ち

理由リトライ・待機・状態保持をエンジンに任せる

サーバーレスのイベント処理

第一候補TypeScript

次点Go、Python

典型例SQS消費、S3トリガー、定期実行

理由起動が速く、AWS SDKが充実。起動速度を詰めるならGo

GraphQLサーバー

第一候補TypeScript

次点Go(gqlgen)

典型例多様なクライアント向けの集約API

理由GraphQLのツール群がTypeScript中心

サービス間のRPC

第一候補Go(Connect)

次点Kotlin、Rust

典型例社内マイクロサービス

理由Protocol Buffers周りのツールが充実し、単一バイナリで配りやすい

手順3:チームと変更頻度で最終調整

  • 仕様が頻繁に変わる・試作段階なら、手順2の結果より開発速度を優先し、Rails/TypeScriptで始める。Go・Kotlin・Rust・Elixirは本番化の段階で切り替え・切り出しを検討する。
  • 担当者が1〜2人なら、手順2で選んだGo・KotlinはTypeScriptに、Elixirはマネージドのリアルタイム基盤(§19-9)に置き換える。保守できる人がいない言語を増やさないためである。Rust(厳格なレイテンシ要件)と、手順1の制約で選んだ言語はそのまま使う。
  • 3人以上で長期運用が前提で、性能要件が明確なら手順2の結果に従う。

1つのプロダクトで言語を混ぜるときのルール

  • 言語の境界はプロセス(サービス)単位にする。同じプロセス内で混ぜるのは、ネイティブ拡張(napi-rs、PyO3)とWebAssemblyのときだけ。
  • サービス間の契約はOpenAPIかProtocol Buffersで定義し、クライアントコードは生成する。
  • 新しい言語を1つ増やすと、CI、Lint、依存の更新、監視の計装、担当できる人の確保が必要になる。既定の言語では要件を満たせないか、明らかに大きな差がつく場合にだけ増やす。
  • 迷ったら既定の言語で作り、計測してボトルネックになった部分だけを適した言語で切り出す。