😀

Go言語で気づいたシンプル設計の真髄 ─ Rails・Java経験者がハマったポイントまとめ

に公開

はじめに

最近Go言語を学ぶ機会があり、簡単なWeb API開発を通じて様々な発見があった。この記事では、RailsやJavaとの比較を交えながら、学んだGoの文法や設計思想について整理して共有する。技術的に誤りがないよう注意しつつ、Goの特徴を確認する。(この記事の一部はAIによって記述されている。)

学び1: アーキテクチャを考える

GoでWebアプリを作る際、以下の3層で分ける構成にした。MVCアーキテクチャと親和性があり、馴染みがあったためである。

  • ハンドラ層: HTTPリクエストとレスポンスを直接扱う部分
  • サービス層: ビジネスロジックを記述する部分
  • リポジトリ層: データベースへのアクセスを担当する部分

Railsとの比較

  • Ruby on Railsの場合: RailsはActive Recordパターンを採用しており、モデルクラスがデータ永続化(DBアクセス)とビジネスロジックの両方を持つ設計である。そのため、機能追加によって1つのモデルが膨れ上がる「Godクラス」化(Fat Model)を招きやすい傾向がある。

  • Goの場合: GoにはRailsのようなフルスタックフレームワークが存在せず、自らアーキテクチャを決定する必要がある。自由度が高い反面、責務分離を徹底しないとコードが複雑化する恐れがある。

image.png

学び2: Goの文法でつまずいたポイント

JavaやRailsの経験を踏まえた視点で、Goの文法において特に戸惑った点を整理する。

1. if文のスコープ付き変数代入

if v, ok := m["key"]; ok {
    fmt.Println(v)
}

Goのif文では、条件式の前に変数宣言を含めることができる。このvはif~elseブロックの中でのみ有効であり、外には漏れない。一時的な変数を使った条件分岐が書きやすい反面、スコープが限定される点に注意が必要である。JavaやRubyではこのような記法はなく、事前に変数を宣言してからnullチェックするのが一般的である。

2. deferの扱い

defer db.Close()

deferは関数終了時に指定した関数を実行する仕組みである。リソース解放に非常に便利で、上記の例では関数を抜ける際に必ずdb.Close()が呼ばれる。これはJavaのtry/finallyでのリソース解放に近いが、Goではリソース確保直後にdeferを置けるため、より直感的である。

3. 値のコピーと共有の挙動

JavaやRuby(Rails)では、変数はオブジェクトそのものではなく、オブジェクトへの参照を保持しており、メソッドに渡す際には参照を渡すことによってオブジェクトを共有する。これに対し、Goでは基本的にすべての引数に値のコピーを渡すが、スライスやマップなど一部の型は内部的に参照を含むため、結果として共有的に振る舞う。

4. 構造体タグ(Struct Tags)

type Todo struct {
    ID    int    `json:"id"`
    Title string `json:"title"`
}

Goの構造体にはタグを付与でき、JSONのキーやDBカラム名との対応を明示できる。RailsのActiveRecordは規約に基づき自動的にマッピングされる。

学び3: Goらしい書き方・考え方

1. エラーハンドリングは逐一確認

Goには例外構文がなく、関数はエラーを戻り値として返し、呼び出し側がif err != nilで逐一確認する。Javaの例外処理やRailsのrescueに比べると冗長に見えるが、明示的に処理を書くことで予測可能性と堅牢性が高まる。

2. ライブラリは最小限で組み合わせる

Goは必要最小限のライブラリを組み合わせて利用する文化である。

gorilla/mux → ルーティング

go-sql-driver/mysql → DB接続

Railsはフルスタックフレームワークであり、Springも機能が統合されている。それに対し、Goは小さな部品を組み合わせることでシンプルさを維持する。

学び4: 開発の設計・運用まわりでの知見

1. Docker ComposeでDB環境を構築し、Goから接続

RailsやJavaでも一般的だが、Goは単一バイナリで動作するため、Dockerとの相性が特に良い。環境構築が軽量でストレスが少ない。

2. Swagger(OpenAPI)でAPI仕様を整理

RESTful APIの管理にはSwaggerを使用して仕様書を記述すると楽になる。

3. curlでAPIを叩きながら開発

Goでは軽量にHTTPサーバを起動できるため、curlで挙動を確認しながら実装を進めるのが自然である。RailsはRSpec、JavaはJUnitでテストコードを充実させるのが一般的だが、Goはまず手動検証、その後必要に応じてテストを書くスタイルが馴染む。

まとめ

Goを学んで感じたのは「シンプルだが奥が深い」ということである。JavaやRailsに慣れていると、エラー処理の多さやフレームワークの少なさが素朴に見える。しかし、それは明示的なエラーハンドリングと責務分離の徹底によって堅牢なシステムを作るための思想である。

Rails的な「魔法」は少ないが挙動の予測がしやすく、Java的な大規模システムの知見とも親和性がある。Goはシンプルさと高性能を両立した実用的な言語であり、今後も実践を通じて言語選択や設計の引き出しを増やしていきたい。

参考文献

GitHubで編集を提案

Discussion