🦄

🐉 7つのボールを集めてモノレポ神召喚した話

に公開

🌟 はじめに

7つの言語を統合したモノレポを作れば、技術力の神龍が召喚されるのでは?

そんな思いから始まった、無謀とも思える挑戦の記録です。Zig、C++、Rust、Go、Kotlin、Python、TypeScriptという7つのプログラミング言語を、Turborepoで統合管理するモノレポを構築しました。

結果的に、Bazelとの格闘、Windows環境での苦労、そして最終的な勝利まで、技術選択の重要性を痛感する旅となりました。

7言語統合 Turborepo

🎯 なぜ7言語なのか?

技術的カバレッジの完全性

現代のソフトウェア開発で求められる全領域をカバーしたかったのです:

領域 言語 選択理由
Next-gen System 🔮 Zig 最新技術への感度アピール
Classic System 🔧 C++ 企業での根強い需要
Modern System 🦀 Rust 安全性・パフォーマンス
Network/Cloud 🐹 Go クラウドネイティブ標準
JVM Modern 🟣 Kotlin エンタープライズ対応
Data/AI 🐍 Python ML/AI開発の中心
Web Frontend ⚛️ TypeScript モダンWeb開発

時代的な完全性

  • 過去: C++ (1985-)
  • 現在: Rust, Go, Kotlin, Python, TypeScript
  • 未来: Zig (2024-)

🌪️ 第一の試練:Bazel地獄編

当初は「Google使ってるし、Bazelでしょ!」と安易に考えていました。

Bazelとの格闘記録

Rust統合での絶望

# cargo razeのインストールでつまずく
cargo install cargo-raze --locked --version 0.14.0
# → インストールできない

# rules_rustでのlockfileエラー
CARGO_BAZEL_REPIN=true bazel sync
# → lockfile version 4が理解できない
# → Cargoバージョンの非互換性

Windows環境での地獄

# シンボリックリンクエラー
WARNING: Failed to create symlink
# → 開発者モード有効化が必要

# UTF-8エンコーディング問題
couldn't read src\main.rs: stream did not contain valid UTF-8
# → VSCodeで再作成が必要

設定ファイルの複雑さ

# WORKSPACE.bazel(抜粋)
load("@rules_rust//crate_universe:repositories.bzl", "crate_universe_dependencies")
crate_universe_dependencies()

load("@rules_rust//crate_universe:defs.bzl", "crates_repository")
crates_repository(
    name = "crate_index",
    cargo_lockfile = "//:Cargo.lock",
    lockfile = "//:Cargo.Bazel.lock",
    manifests = ["//:Cargo.toml"],
)
# ... 延々と続く設定

敗北宣言

数時間格闘した結果、以下の結論に至りました:

Bazelは企業レベルの巨大プロジェクト用。個人・中小規模には複雑すぎる

💡 第二幕:Turborepo による救済

「実用性を重視しよう」と方針転換し、Turborepoを採用しました。

Turborepoを選んだ理由

1. 学習コストの低さ

// turbo.json - これだけ!
{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", "target/**", "build/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

2. 各言語のネイティブツールを活用

# Rust
cargo build --release

# Go
go run .

# Python
poetry run python src/main.py

# Kotlin
gradle run

# C++
cmake --build build

# Zig
zig build run

3. 統一されたコマンド体系

# 全言語同時実行
npm run dev

# 特定言語のみ
npx turbo dev --filter=rust-api
npx turbo dev --filter=python-api

🎪 各ドラゴンボール(言語)の召喚過程

🔮 一星球:Zig

最も困難だった最新言語の統合。

const std = @import("std");
const print = std.debug.print;

pub fn main() !void {
    print("Zig Next-Gen System Tools in Turborepo!\n", .{});
    
    // 現在時刻の計算
    const timestamp = std.time.timestamp();
    const days_since_2000 = @divTrunc(timestamp, 86400) - 10957;
    print("Days since 2000-01-01: {}\n", .{days_since_2000});
}

課題: AppDataDirUnavailableエラー
解決: 環境変数でキャッシュディレクトリを明示指定

{
  "scripts": {
    "dev": "set ZIG_GLOBAL_CACHE_DIR=%LOCALAPPDATA%\\zig && zig build run --cache-dir .zig-cache"
  }
}

🔧 二星球:C++

安定の高性能システム言語。CMake統合で意外と簡単。

class SystemAnalyzer {
public:
    void performAnalysis() {
        std::cout << "C++ System Analyzer in Turborepo!" << std::endl;
        
        // メモリ管理デモ
        auto numbers = std::make_unique<std::vector<int>>();
        for(int i = 1; i <= 1000000; ++i) {
            numbers->push_back(i);
        }
        
        auto sum = std::accumulate(numbers->begin(), numbers->end(), 0LL);
        std::cout << "Sum: " << sum << std::endl;
    }
};

ポイント: 絵文字文字化け問題で英語出力に統一

🦀 三星球:Rust

期待通りの安全性とパフォーマンス。

fn main() {
    println!("🦀 Hello from Rust in Turborepo!");
    
    let numbers = vec![1, 2, 3, 4, 5];
    let sum: i32 = numbers.iter().sum();
    println!("Sum: {}", sum);
}

🐹 四星球:Go

シンプルで高速。環境変数のGOCACHE問題以外はスムーズ。

func main() {
    fmt.Println("🐹 Hello from Go in Turborepo!")
    
    numbers := []int{1, 2, 3, 4, 5}
    sum := 0
    for _, n := range numbers {
        sum += n
    }
    fmt.Printf("Sum: %d\n", sum)
}

🟣 五星球:Kotlin

JVM版ヘルスチェッカー。Gradleで安定動作。

fun main() {
    println("🟣 Kotlin CLI Health Checker in Turborepo!")
    
    val numbers = listOf(1, 2, 3, 4, 5)
    val sum = numbers.sum()
    println("Sum: $sum")
    
    // システム情報
    println("OS: ${System.getProperty("os.name")}")
    println("JVM: ${System.getProperty("java.version")}")
}

🐍 六星球:Python

FastAPIでHTTPサーバー化。Poetry管理で依存関係もクリア。

from fastapi import FastAPI
from datetime import datetime

app = FastAPI(title="Python API", version="0.1.0")

@app.get("/")
async def hello():
    return {
        "message": "🐍 Hello from Python in Turborepo!",
        "framework": "FastAPI",
        "timestamp": datetime.now().isoformat()
    }

⚛️ 七星球:TypeScript

Next.js 15で最新Web技術。Turborepoの本領発揮。

export default function Home() {
  return (
    <main>
      <h1>⚛️ Next.js in Turborepo!</h1>
      <p>TypeScript + React 18 + Server Components</p>
    </main>
  )
}

🐉 神龍召喚の瞬間

すべての球が集まった時、ついにモノレポ神が召喚されました:

$ npm run dev

• Packages in scope: cpp-system, docs, go-api, kotlin-api, python-api, rust-api, web, zig-tools
• Running dev in 8 packages

rust-api:dev: 🦀 Hello from Rust!
go-api:dev: 🐹 Hello from Go!
cpp-system:dev: C++ System Analyzer completed!
kotlin-api:dev: 🟣 Kotlin CLI Health Checker!
python-api:dev: 🐍 FastAPI running on port 8000
zig-tools:dev: Zig Next-Gen System Tools completed!
web:dev: ⚛️ Next.js on http://localhost:3000
docs:dev: 📚 Docs on http://localhost:3001

📊 Bazel vs Turborepo 最終決戦の結果

項目 Bazel Turborepo
セットアップ時間 ❌ 数時間〜数日 45分で完成
Windows対応 ❌ エラー地獄 完全対応
学習コスト ❌ 非常に高い 適切
実用性 ❌ 企業専用 即戦力
言語サポート ❌ 複雑設定 ネイティブ対応
Rust統合 ❌ 複雑・エラー多数 3分
Go統合 ❌ 複雑 5分
Python統合 ❌ 非常に困難 10分

🚀 現在の状況と今後の展望

現在できること

  • ✅ 7言語の統一コマンドでの実行
  • ✅ 各言語の特性を活かした実装
  • ✅ 並列ビルド・キャッシュ
  • ✅ Windows/Linux/macOS対応

今後の予定

Phase 1: CI/CD統合(次の目標)

# .github/workflows/ci.yml
name: Multi-Language CI
on: [push, pull_request]

jobs:
  test:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - name: Install dependencies
        run: npm install
      - name: Run tests
        run: npm run test
      - name: Build all
        run: npm run build

Phase 2: Docker統合

# マルチステージビルドで各言語を統合
FROM rust:alpine as rust-builder
FROM golang:alpine as go-builder
FROM node:alpine as web-builder
# ... 各言語のビルド

FROM alpine:latest
COPY --from=rust-builder /app/target/release/rust-api /usr/local/bin/
COPY --from=go-builder /app/go-api /usr/local/bin/
# ... 統合実行

Phase 3: 本格的なマイクロサービス化

  • API Gateway(Next.js)
  • 各言語サービス間通信
  • 共通スキーマ定義(OpenAPI)
  • 分散トレーシング
  • 監視・ログ統合

Phase 4: パフォーマンス最適化

  • 各言語のベンチマーク比較
  • 最適化手法の実装
  • 負荷テスト
  • キャッシュ戦略の改善

💡 学んだこと

技術選択の重要性

「最新技術 ≠ 最適解」

Bazelは確かに強力ですが、目的に対して過剰でした。Turborepoは:

  • 学習コスト適切
  • 実用性重視
  • 各言語の良さを活かす
  • チーム開発に優しい

実用性 First の価値

企業での評価は「動かない高度な技術」より「動く実用的な技術」です。

Windows対応の重要性

開発者の多くがWindows環境。Windows軽視は機会損失につながります。

🎯 ポートフォリオとしての価値

技術幅の証明

  • システムプログラミング: Zig, C++, Rust
  • アプリケーション開発: Go, Kotlin
  • データ・AI: Python
  • Web開発: TypeScript

問題解決思考の証明

  • Bazel → Turborepo の判断プロセス
  • 各言語の環境問題の解決
  • 実用性重視の技術選択

実行力の証明

  • 動作する成果物
  • 統一されたワークフロー
  • 継続的な改善計画

🤝 おわりに

7つのプログラミング言語を統合したモノレポの構築は、技術選択の重要性を改めて教えてくれました。

「最新技術を追うだけでなく、目的に最適な技術を選択する」

これこそが、エンジニアに求められる本質的なスキルなのかもしれません。

現在のモノレポは基本動作のみですが、今後CI/CD、Docker、マイクロサービス化と段階的に進化させていく予定です。

リポジトリ

🔗 GitHub Repository

関連記事


あなたなら、どの技術選択をしますか?

Discussion