Upgrade to Pro — share decks privately, control downloads, hide ads and more …

「Go Style Guide」から学んだ可読性の高いコードの書き方

「Go Style Guide」から学んだ可読性の高いコードの書き方

Go Conference 2023 ( 2023/06/02 Fri. )
https://gocon.jp/2023/
登壇資料

株式会社アンドパッド
プロダクトテックリード
小島 夏海

みなさん、Googleが公開したGo Style Guideは読みましたか?

ソフトウェア開発は継続的な活動であり、一般的に複数人で行うことが多いです。
継続的に複数人で開発を行う場合、自分が書いたコードを他人が読んだり修正したりすることが非常に多いです。
そのため可読性の高いコードを書くことは開発効率やメンテナンス性の向上に役立ちます。

Goはシンプルな言語ですが、どのように書くべきか悩むことが全くないわけではなく、そのような時従来はEffective Go/Uber Go Style Guide/OSSコード等を参考にどのように書くか決めていたと思います。
これらに加え、昨年末にGoogleからGo Style Guideが公開されました。GO Style Guide では従来よりも幅広い範囲について解説がされています。(例えば、テストの書き方については非常に詳しく記載されています)
このトークでは「実際に開発しているプロダクトではどのように書いていたか」や「読んだ内容を元に現在はどう書いているか」を交えつつ「Go Style Guide」の内容から学んだことをご紹介します。

ANDPAD inc

June 02, 2023
Tweet

More Decks by ANDPAD inc

Other Decks in Technology

Transcript

  1. Go Style Guideとは • 2022/11/23 にGoogleから公開されたドキュメント [1] ◦ Go Style

    Guide と付属のドキュメントは読みやすく・慣用的 なGoを書くための現在のベストアプローチを体系化したもの ◦ Goのプロジェクトによって支援されているわけではない ▪ 公式ドキュメントではない [1] https://google.github.io/styleguide/go/index
  2. Go Style Guideとは • 2022/11/23 にGoogleから公開されたドキュメント [1] ◦ Go Style

    Guide と付属のドキュメントは読みやすく・慣用的 なGoを書くための現在のベストアプローチを体系化したもの ◦ Goのプロジェクトによって支援されているわけではない ▪ 公式ドキュメントではない [1] https://google.github.io/styleguide/go/index
  3. Go Style Guide以外の情報元 • Effective Go[1] ◦ 公式のドキュメント ▪ 2009年のGoのリリースに合わせて書かれており、それ以

    降大きく更新はされていない ◦ 網羅的に書かれているが、最新の情報はない ▪ 例えば context や generics についての記載はない [1] https://go.dev/doc/effective_go
  4. Go Style Guide以外の情報元 • CodeReviewComments[1] と TestComments[2] ◦ 公式のドキュメント ▪

    どちらもGo言語のリポジトリのWiki内のコンテンツ ◦ CodeReviewComments はレビュー中に寄せられた一般的なコ メントがまとめられている ◦ TestComments はテストについてまとめられている [1] https://github.com/golang/go/wiki/CodeReviewComments [2] https://github.com/golang/go/wiki/TestComments
  5. Go Style Guide以外の情報元 • Uber Go Style Guide[1] ◦ Uber社が公開してくれているドキュメント

    ▪ Uber社内のガイドラインを文書化したもの ◦ 具体的なコード例が多め [1] https://github.com/uber-go/guide/blob/master/style.md
  6. 構成 • 構成としては3つに分かれている ◦ Style Guide : 基礎になるもの ◦ Style

    Decisions : Style Guideの内容について特定のポイント について書かれている ◦ Best Practices : 時間をかけて定着していったパターン
  7. それぞれの対象 名前 対象 Normative (一貫性を確立を目的としている ) Canonical (永続的なルール) Style Guide

    すべて Yes Yes Style Decisions メンター Yes No Best Practices 興味のある人 No No
  8. Style Guide • Style principles と Core Guideline の2項目 •

    Style principles は包括的な原則を優先度順で 5つ定義している ◦ Clarity : 目的と根拠が読み人にとって明確になっているか ◦ Simplicity : 単純な方法で目的を達するようになっているか ◦ Concision : 簡潔な状態になっているか ◦ Maintainability : 保守しやすいか ◦ Consistency : 既存のコードベースとの一貫性
  9. Style Decisions • 統一されたスタイルの決定と標準的な説明・例を提供 • 大項目としては下記 ◦ Naming ◦ Commentary

    ◦ Imports ◦ Errors ◦ Language ◦ Common libraries ◦ Useful test failures ◦ Test structure ◦ Non-decisions
  10. Best Practices • Dicisionsの内容の具体的な例や補足がある • 大項目としては下記 ◦ Naming ◦ Package

    size ◦ Imports ◦ Error handling ◦ Documentation ◦ Variable declarations ◦ Function argument lists ◦ Complex command-line interfaces ◦ Tests ◦ String concatenation ◦ Global state
  11. Style Guide • Style principles は優先度順で5つ定義されている ◦ Clarity : 目的と根拠が読み人にとって明確になっているか

    ◦ Simplicity : 単純な方法で目的を達するようになっているか ◦ Concision : 簡潔な状態になっているか ◦ Maintainability : 保守しやすいか ◦ Consistency : 既存のコードベースとの一貫性 Clarity Maintainability Concision Simplicity Consistency 優先度: 高 優先度: 低
  12. Clarity 0値のフィールドを省略する ことで指定されている オプションが目立つ // Bad ldb := leveldb.Open("/my/table", &db.Options{

    BlockSize: 1<<16, ErrorIfDBExists: true, // These fields all have their zero values. BlockRestartInterval: 0, Comparer: nil, })
  13. Simplicity genericsは使わないで済む 場合は使わない // Bad func ReadFour[T io.Reader](r T) ([]byte,

    error) // Good func ReadFour(r io.Reader) ([]byte, error) The original code was shown by GopherCon 2021: Robert Griesemer & Ian Lance Taylor - Generics! https://www.youtube.com/watch?v=Pa_e9EeCdy8
  14. Simplicity %qを使う // Bad fmt.Printf("value \"%s\" looks like English text",

    someText) fmt.Printf("value '%s' looks like English text", someText) // Good fmt.Printf("value %q looks like English text", someText)
  15. Concision 繰り返しを避ける 以下のようなもので繰り返 しが発生しないように注意 する • ファイル名 • インポートパス •

    パッケージ名 • メソッド/関数名 • 型名 // Bad widget.NewWidget db.LoadFromDatabase // Good widget.New db.Load
  16. Concision パッケージ名と同じ変数名 を使う時にパッケージ名に エイリアスを設定する場合 は urlpkg のように pkg を suffix

    とする // Bad import "net/url" func main() { url := "https://gocon.jp/2023/" url.Parse(url) // エラーになる )
  17. Concision パッケージ名と同じ変数名 を使う時にパッケージ名に エイリアスを設定する場合 は urlpkg のように pkg を suffix

    とする // Good import urlpkg "net/url" func main() { url := "https://gocon.jp/2023/" urlpkg.Parse(url) )
  18. Maintainability • 何度も編集されるものなのでメンテナンス性も大事 • ここでのメンテナンス性の定義 ◦ 正しく修正することが容易 ◦ 拡張しやすいように構造化されている ◦

    前提条件が明確になっていてコードの構造ではなく、 問題の構造に対応する抽象化をしている ◦ 不要な結合を避けて、使用する機能だけを含める ◦ 重要なロジックが正しいことを確認するための 包括的なテストスイート持つ ◦ テストが失敗した場合、明確で実用的な内容を出力する
  19. Maintainability 構造体のフィールドごと ではなく、全体を比較する var got, want BlogPost // Bad if

    got.Title != want.Title { ... } if got.Body != want.Body{ ... } // Good if diff := cmp.Diff(got, want); diff != "" { t.Errorf(diff) }
  20. 読んだ後どうするのがよさそうか • Go Style Guideがすべての場面で正しいというわけでは なく、チームのフェーズや規模等によって重要視 するものは異なる ◦ Go Style

    Guide等を元に共通認識を作っていくことが大切 • 最終的にはGoogleやUberのようにガイドラインを 作っていくのもよさそう ◦ 努力だけで守り続けるのは大変なのでリンターやコード生成も 活用していくとよい ▪ 既存のリンターを活用することで検出できることも多い
  21. 読んだ後どうするのがよさそうか • Go Style Guideがすべての場面で正しいというわけでは なく、チームのフェーズや規模等によって重要視 するものは異なる ◦ Go Style

    Guide等を元に共通認識を作っていくことが大切 • 最終的にはGoogleやUberのようにガイドラインを 作っていくのもよさそう ◦ 努力だけで守り続けるのは大変なのでリンターやコード生成も 活用していくとよい ▪ 既存のリンターを活用することで検出できることも多い
  22. まとめ • Googleが公開した「Go Style Guide」についての概要 を紹介しました • その内容を元に可読性の高いコードをどう書いていく かについて紹介しました ◦

    可読性は複数の要素でなりたっている ◦ Go Style Guideが絶対ではないのでチームで同じ方向を 向けるように話していくことが大切
  23. おまけ • リンター作ったので紹介 ◦ sliceがnilかどうかの比較は slice == nil ではなく len(slice)

    == 0 で比較する必要がある ◦ Style Guideでも紹介しているのですがこれを検出する リンターがなさそうだったので作りました https://github.com/replu/slicenilcmp