10 ポイント 投稿者 GN⁺ 2024-12-16 | 5件のコメント | WhatsAppで共有
  • 著者がGo言語を何年も使ったあとJavaへ移行する中で感じた、Go言語の限界と問題点を説明する記事
  • Goがシンプルで退屈な(boring)言語だという特徴が、長所ではなく短所になりうるという視点を提示
  • Goの哲学: GoogleのGo設計チームは単純さと制限を重視したが、その結果、ユーザーが自分で解決しなければならない反復作業を生みやすい

1. Goは「面白くない」ことが短所になりうる

  • Russ Coxの主張:
    • Goは「退屈な(boring)」ことが長所だと強調
    • ループは for しかなく、フィルター、マップ、リデュースのような機能は標準では提供されない
    • ほかの多くの言語にあるさまざまな高級機能がないことも、シンプルさの一部とみなされている
  • Redditユーザーの意見:
    • 「退屈さ」と「強力さ」の境界は曖昧
    • Goの基本機能の不足は、いずれ言語に追加される可能性が高いと主張
  • サードパーティパッケージへの依存:
    • 足りない機能を補うためによく使われる samber/lo パッケージ:
      • フィルター、マップ、検索などの必須機能を含む
      • GitHubで18.1kスターを獲得し、12.6k以上のプロジェクトで利用
    • 一部機能は slices パッケージで追加されたものの、依然として機能面では不足がある
  • 著者の不満:
    • 反復的なループ記述を強いられる
    • フィルターやマップのような処理を簡潔に書きにくい
    • 別のレシーバーメソッドとして切り出すことはできるが、コードの整然さを損ねる
  • Goのシンプルさは多くの場合で長所だが、基本的な利便機能の不足は生産性とコード可読性を下げる短所になりうる

2. Clean Codeの原則を妨げる

  • エラー処理の問題:
    • 関数は戻り値に error を含むことがほとんど:
      • if err != nil パターンを繰り返し使う必要がある
      • コード整理の過程で、かえってコードが複雑になる問題が発生
    • HTTPハンドラーのコードが簡単なプロジェクトでも20行以上に膨らむ
      • 本来の目標は4行程度に保つこと
    • panic() とリカバリミドルウェアを検討するほど、エラー処理方式にフラストレーションを感じた
  • 短い名前の推奨:
    • 変数名、メソッド名、関数名に短い名前を使うことが推奨される:
      • ca のような名前が何を意味するのか不明確
      • 例: c は Command、Controller、Argument、Amendment のどれなのか?
      • 長い名前を使えばより明確になる可能性があるが、Goの哲学は短い名前を好む
    • そのため、チームのコードレビューでテストメソッド名などをめぐる終わりのない議論を招く
  • Goの哲学はコードの簡潔さと単純さを強調するが、結果としてクリーンコードの原則に反する複雑さと非効率を招くことがある

3. 意図的に小さな言語という哲学とDIY文化

  • 基本機能の不足:
    • 単純なHTTPハンドラーを実装するのは簡単だが、基本的なミドルウェア(例: 指数バックオフ、クロスサイト設定など)が必要になると複数のパッケージを探す必要がある
    • それらのパッケージが (1) 保守されているか、(2) 期待どおりに動くかを確信しにくい
  • 反復作業の増加:
    • シンプルさを保とうとするGoの設計思想が、かえって開発者に「車輪の再発明」を求める形になりやすい
    • 例: 簡単なフィルター機能ですら自分で実装しなければならない場面がある
  • 未成熟なパッケージエコシステム:
    • 多くのGitHubプロジェクトが放置されていたり、数バージョンしかリリースされていなかったりする
    • 比較的新しい言語である点を考えると .NET/Java と比べるのは不公平かもしれないが、現実問題としてGoのパッケージの安定性と成熟度は不足している
  • ORMの限界:
    • Goの主要なORMパッケージであるGormは、HibernateやEntity Frameworkと比べて機能的に見劣りする
    • 奇妙な挙動やドキュメント不足の問題がある
    • Goコミュニティの反応: 「GoにORMは不要、自分でやれ!」
  • Goのシンプルさはプロジェクトやチームによっては長所になりうるが、標準で提供されない機能の不足は生産性と開発体験に悪影響を及ぼす可能性がある

4. Goには唯一のやり方があるわけではない

  • 一貫性と統一性という誤解:
    • テーブルテスト(Table Test)
      • stretchr/testify のようなテストスイートを使用(557kプロジェクトで利用中)
      • テーブルテスト内でカスタムサブテストを書く
    • その結果、「統一されたやり方」というGoの哲学と現実の間に隔たりがある
  • チーム内対立を招く:
    • チーム間でテストスタイルや実装方式についての議論がむしろ増える
    • Goの哲学と設計チーム自体にも一貫性の不足がある:
      • 例: Getterメソッドの命名に関する不一致
  • 機能拒否とパッケージ依存:
    • Goチームはアサーション(assertion)機能の追加を拒み、プログラマ側の未熟さを問題視するような態度だと批判される
    • 結果として必要な機能を使うために、また別のパッケージをインストールする必要がある(go get)
  • Goはシンプルさと統一性を志向するが、実際には多様な実装方式とそれに伴う議論が存在し、言語設計哲学の曖昧さが問題を悪化させている

5. Goのデバッグは楽しくない

  • デバッグ中に式を評価できない:
    • デバッグセッションで式を評価したり、オブジェクトのカスタム文字列表現を確認したりできない
    • 実行時にオブジェクトの状態を明確に把握しにくい
  • スタックトレースとログの非直感性:
    • 大規模テスト(例: CIで数千件のテストを実行)に失敗すると、分かりにくいスタックトレースやログが出る
    • 結果としてデバッグが難しくなり、生産性が低下する
  • Cスタイルのデバッグ体験:
    • GoのデバッグツールチェーンはCベースで動作する:
      • Cに似た原始的なデバッグ体験を提供
      • 開発者フレンドリーではない
  • Rustとの比較:
    • RustはGoの限界を改善している:
      • 明確で有用なエラー情報を提供
      • エラーメッセージに正確な修正提案を含む
  • Goのデバッグ体験は、最適化されたバイナリ提供を重視する設計思想に基づいているが、その代償として開発者体験を犠牲にしている。デバッグ効率を重視する環境では代替言語を検討する価値がある

要約: Goの適性と限界

  • Go組み込みツールの長所:
    • パッケージ管理、テスト、性能監視のための基本ツールチェーンを提供
    • 追加設定なしで使え、初期の開発環境構築を簡素化できる
  • 限界:
    • 「退屈なコード」と反復作業:
      • Goのツールチェーンは実用的だが、コード記述時に反復作業(Plumbing Code)を強いる
      • 例: 単調な構文や限定的な機能が作業の面白みを削ぐ
    • "import cycle not allowed":
      • テストで循環依存(import cycle)を許可しない
      • ドメイン駆動設計(DDD)を進める際、構造的制約によって複雑さが増す
    • struct 埋め込み手法への依存:
      • 奇妙で制限の多い struct 埋め込みメカニズムにより使いづらさが生じる
  • 適した活用領域:
    • インフラ開発に適している:
      • Docker、Drone、Hugo などのシステムレベルツールはGoで書かれている
    • 軽量サーバーやCLIアプリケーション開発に有用
  • 適さない活用領域:
    • 複雑なエンタープライズアプリケーション(例: ERPシステム)の開発:
      • 制限的な言語哲学とツールのため、大規模なビジネスロジック管理が非効率
  • Goは特定の作業、特にインフラ関連では優れた効率を発揮する一方で、複雑なビジネスドメインのアプリケーションには適さないツールである。CTOがGoogle技術スタック寄りであっても、技術選定は慎重に行うべきだ

5件のコメント

 
secret3056 2024-12-17

Rustの?さえあれば、今よりはずっとましだったのではないでしょうか…

 
bbulbum 2024-12-17

Go を使っていて感じたのは、これまでどれほど暗黙的なエラーハンドリングをしていたのか、ということでした。
もちろん、エラーハンドリングを一つのポイントで処理するほうが構造的にはすっきり見えるかもしれませんが、エラーを返しうる動作であることを明示的に示しつつ、より安全な形でコードを書くようになるのではないかと思います。

 
tsboard 2024-12-16

if err != nil {} これは正直ちょっと面倒ではあります。指摘されている欠点にも同意です。それでも、この言語が目指している方向性を明確に理解して、どの点をより活用するかを考えれば、指摘された欠点があっても、もっとうまく活用できるのではないかと思います。Cに似ていて、GCがあり、限定的とはいえジェネリクスまでサポートしていて、そのうえクロスコンパイルまでできる! こうして見ると、かなりお得な言語ではないでしょうか?

 
riki3 2024-12-16

JavaからGoに移ったとき、最初は似たような感覚を覚えた気がします。
今ではJavaに費やした時間がもったいないと思うほどGoを楽しんでいます。複雑なビジネスアプリケーションに向いていないという話を聞くと、そのアプリケーションはシステムを単純化するための検討が十分ではなかったのではないか、という気がしてしまいます。

 
GN⁺ 2024-12-16
Hacker Newsの意見
  • Java開発者がGoにJavaスタイルを押し付けると問題が発生する

    • Goの哲学は短期的にはあまり有用でなくても、長期的には大きな違いを生む
    • JVMエコシステムに深く浸かっている人は、Goを楽しみにくい
  • 多くの開発者が抽象化を早くやりすぎる

    • 単純な繰り返しで十分なときに、不必要な抽象化を作ってしまう
  • Goの標準ライブラリは大きいが、何でもできるほど大きいわけではない

    • プロジェクトごとに車輪の再発明をする傾向がある
    • Goはサーバー/CLIアプリケーションに最適である
  • プログラミング言語の選択よりも大きな課題が存在する

    • Goのメカニズムと哲学に適応することが重要である
  • Goを好きな理由を理解しにくい

    • 言語そのものよりも、ツールチェーンとデプロイの容易さが好まれている
  • Goのコアチームが誤った判断を覆すことにフラストレーションを感じる

    • 優れたパッケージシステムとツールが存在する
    • 複雑なERPシステムにはJavaのほうがより良い選択かもしれない
  • GoはUNIXと同じような問題を抱えている

    • 複雑さをユーザーに押し付ける傾向がある
    • JavaのランタイムはGoに比べて速いペースで進化している