Go for Rubyists
Ruby開発者のためのGo言語ガイド — 全ての概念をRubyと比較します
📖 基本文法
変数と型 — Rubyの動的型付けが恋しくなる瞬間
ダックタイピングが消えた世界で生き残る
Rubyではx = 1で終わり。Goではvar x int = 1。最初は面倒だが、コンパイラがバグを捕まえてくれる経験をすると考えが変わる。
制御文 — if/forは似てるがwhileがない
Rubyのeach/map/selectが恋しくなるforループの世界
Goにはwhileがない。forひとつで全部処理する。Rubyの.each、.map、.selectのようなコレクションメソッドもない。全てfor rangeで直接回す。
関数とメソッド — クラスのない世界のメソッド
Rubyのdefはクラスの中に住む。Goのfuncはstructにつく。
Goにはクラスがない。関数が基本で、structにメソッドを付ける方式でオブジェクト指向を模倣する。Rubyのclass ... defパターンとは根本的に違う。
🔩 型システム
Struct vs Class — 継承なしで生きる方法
Rubyのclass < Baseの代わりにGoのstruct埋め込み
Goにはclassがない。structがデータを保持し、メソッドはstructに付く。継承の代わりにembedding(埋め込み)でコード再利用。Rubyのinclude/extendに似て非なるもの。
Interface — Rubyのダックタイピングが型システムに出会った時
明示的なimplementsなし、メソッドが合えば自動的にインターフェースを満たす
Goのインターフェースは、Rubyのダックタイピングとjavaのinterfaceの中間にある。「このメソッドを持っていればこの型だ」— コンパイル時に検証されるダックタイピングと思えばいい。
if err != nil — Rubyのbegin/rescueが恋しくなる理由
Goは例外を使わない。エラーを値として返す。コードの半分がエラー処理になる。
Rubyはbegin/rescue/endで例外を捕まえる。Goには例外がない。関数が(結果、エラー)を返し、呼び出し側で毎回if err != nilでチェック。これがGoコードの50%を占める。
⚡ 並行処理
Goroutine — RubyのThreadとは次元が違う軽量並行処理
goキーワードひとつで数万の並行タスクを実行。GILはない。
RubyのThreadはGIL(Global Interpreter Lock)のため真の並列実行ができない。Goのgoroutineはスレッドより軽く、数万個を同時実行可能。
Channel — goroutine間のパイプライン
Rubyにはない概念。goroutine間でデータを安全にやり取りする通路。
Channelはgoroutine間で値をやり取りする型安全なパイプ。Rubyには正確に対応する概念がない。Queueが最も近いが、channelは言語レベルでサポートされる。
📁 プロジェクト構成
パッケージとモジュール — Gemfileがgo.modになった時
Rubyのrequire/gemシステム vs Goのpackage/moduleシステム
RubyのGemfile + BundlerがGoではgo.mod + go getになる。パッケージ管理の概念は似ているが、GoはGitHub URLがパッケージ名で、中央レジストリ(RubyGems)がない。
テスト — RSpecなしで生きる方法
Goのテストは標準ライブラリに組み込まれている。gem install不要。
RubyでRSpec + FactoryBot + shoulda-matchersの設定に30分かかる。Goでは_test.goファイルを1つ作ればすぐテスト可能。go testコマンドひとつ。
🔬 OSS分析
Keploy — eBPFでトラフィックを傍受しAPIテストを自動生成する仕組み
Go + eBPF + 透過プロキシでコード変更なしにテストを生成するCNCFプロジェクト
KeployはeBPFでカーネルレベルのネットワークsyscallを傍受し、透過プロキシでトラフィックを録画した後、そのままテストケース+Mockに変換する。コードは一行も変えずに。
eBPF宛先リダイレクト — connect() syscallをカーネルで書き換える原理
Keploy、Cilium、Istioが使う透過プロキシの核心メカニズム
アプリがpostgres:5432にconnect()を呼ぶと、eBPFがカーネル内で宛先を127.0.0.1:proxyPortに書き換える。アプリは全く知らない。このトリックがどう実現されるか、Goコードレベルで解剖する。