はてなのサービスを支えるGo / hatena.go #1 maku693
by
HAMADA Shota
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
はてなのサービスを支える Go はてなにおけるGo利用のこれまでとこれから 濵田祥太 / id:maku693 hatena.go #1
Slide 2
Slide 2 text
自己紹介 ● 濵田祥太 id:maku693 ● 好きな言語:Go, JavaScript ● 認定スクラムマスター
Slide 3
Slide 3 text
今日お話しすること ● はてなとGoの関わり ● はてなのGo製Webアプリケーションの構成と それに対する考察 ● 現状の課題と今後の展望
Slide 4
Slide 4 text
はてなとGoの関わり
Slide 5
Slide 5 text
● Go 1.1 ● 社内で初めてA Tour of Goを題材にした勉強 会が行われた記録がある 2013年
Slide 6
Slide 6 text
● Go 1.3 ● Mackerelリリース ● Mackerel-AgentにGoが採用 ○ プロダクションにおける初採用 2014年
Slide 7
Slide 7 text
2015~2016年 ● Go 1.5 ~ 1.7 ● MackerelのサブシステムでGoが採用されは じめる ● Mackerel以外にも徐々に利用が広まる ○ 社内むけコマンドラインツール ○ はてラボ人間性センター
Slide 8
Slide 8 text
● Go 1.8~1.11 ● Mackerelの時系列DBがGoで書かれたものに リプレース ● Mackerel以外のサービスのサブシステムで プロダクション投入されはじめる ○ はてなブックマーク ○ はてなブログ 2017~2018年
Slide 9
Slide 9 text
● Go 1.12~1.15 ● カクヨム ○ 一部サブシステムをGoでマイクロサービスとして 実装 ● はてなブログ タグ ○ 内部APIの実装言語として採用 2019~2020年
Slide 10
Slide 10 text
● Go 1.16 ~ 1.21 ● マンガノ ○ SPA/BFF向けGraphQL APIをGoで実装 ● はてなのサービス基盤でGoが採用される ● チーム横断組織「Goサブ会」発足 2021~2023年
Slide 11
Slide 11 text
● 現在はてなでは新しいシステムを開発する際 はPerl以外の言語を使うことを推奨 ● Goで書かれたアプリケーションも多数開発・ 運用中 そして現在
Slide 12
Slide 12 text
はてなにおけるGo利用の歴史 ● Mackerelでは10年ほど前から利用 ● プロダクションでWebアプリケーションに 採用され始めたのは5年ほど前から
Slide 13
Slide 13 text
はてなのGo製 Webアプリケーションを 俯瞰してみる
Slide 14
Slide 14 text
はてなのGo製Webアプリケーション ● 今回は主にWebアプリケーションの話を します ○ 観点を絞るため ○ 全て稼働中のサービス ○ コード規模は数千行〜数万行
Slide 15
Slide 15 text
はてなのGo製Webアプリケーション ● ここでいうWebアプリケーション ○ 比較的長命なプロセス(サーバ) ○ HTTPなどでクライアントからリクエストを 受け取り、レスポンスを返す ○ データストアにデータを保存したり、データを取得 したりする
Slide 16
Slide 16 text
パッケージ構造
Slide 17
Slide 17 text
● usecase, service, repository, domain…と いった層があるパターン ○ ビジネスロジックがそれ以外に依存しないように ○ 依存関係の方向が意識されている レイヤード
Slide 18
Slide 18 text
● 層がないパターン ○ いわゆるインフラ層やリポジトリ層がそのまま露出・ 直接利用されているようなイメージ フラット
Slide 19
Slide 19 text
ライブラリ
Slide 20
Slide 20 text
● Go Modules ○ 過去depなどを使っていたシステムは移行した 依存管理
Slide 21
Slide 21 text
● wire or なし ● レイヤード構成にすると自然とDI的な仕組み が欲しくなる ○ interfaceを使って抽象に依存すると、具体的な実装 を注入する必要が出てくる DI
Slide 22
Slide 22 text
● testify, gotest.tools, ginkgo, なし(標準 testパッケージのみ) ● 何かしらアサーション系のライブラリを入れ ていることがほとんど ○ t.Fail()を何度も書く手間を省く ○ BDDっぽい書き方は流行っていない テスト
Slide 23
Slide 23 text
● gomock or モックなし ● レイヤード構造を採用しているサービスの多 くでgomockを利用 ● 手書きしている例はあまりない モック
Slide 24
Slide 24 text
ロガー ● zap, logrus、標準log, slog ● 構造化ログが基本 ○ 運用中の調査に便利 ○ クラウドサービスプロバイダの対応が充実
Slide 25
Slide 25 text
HTTPサーバ ● 標準net/http, echo, go-chi, gin ● http.ServeMuxのみだと機能不足 ○ ほとんどのシステムでルーターやミドルウェアが必要
Slide 26
Slide 26 text
● GraphQL ○ gqlgen, graphql-go ○ ほぼ全てgqlgen ● gRPC ○ システム間通信に採用 ● OpenAPI ○ go-swagger, oapi-codegen ● スキーマファースト ○ クライアントを自動生成できる ○ 分業しやすい API
Slide 27
Slide 27 text
DBアクセス ● sqlx ○ RDBを使うシステムではほぼ間違いなく入っている ○ ORMやクエリビルダが不要な場合のデフォルトの選択肢 ● クエリビルダ ○ goqu, squirrel ● ORM ○ gorm, sqlboiler, ent ● ORMよりクエリビルダの採用例が多い ○ PerlでTengよりSQL::Makerがよく使われていたのに似ている
Slide 28
Slide 28 text
考察
Slide 29
Slide 29 text
● エントリポイント (main) が複数あるサービスはほぼ レイヤード ○ 複数エントリポイントから共通のユースケースを利用するのに 必要 ○ フラットな場合ユースケースの置き場所が自明でない ● フラット構造の場合はDIがなくてもなんとかなるが… ○ これもエントリポイントが増えてくると初期化処理が重複して しまう パッケージ構造
Slide 30
Slide 30 text
ライブラリ選定 ● リフレクションよりコード生成が人気 ○ wire, gomock, gqlgen, oapi-codegen, ent, etc… ○ 独自のジェネレータを自作している場合も ● 重厚なフレームワークより軽量なライブラリ の組み合わせ
Slide 31
Slide 31 text
Goを採用してよかったこと ● 陳腐化しづらい ○ 基本的に言語のバージョン間の後方互換がある ○ ライブラリは公開されている限りそのまま使い続け られる ○ バージョンアップが楽 ■ サービスを長生きさせる前提の技術選定
Slide 32
Slide 32 text
現状の課題
Slide 33
Slide 33 text
● 人気のライブラリはあるがリポジトリ間で 微妙な差異がある ● パッケージ構造についても同様 ● 同じチーム内でも全く同じということがない ○ リポジトリレベルで試行錯誤されている 定番構成が定まっていない
Slide 34
Slide 34 text
定番構成が定まっていない ● ライブラリの探索が不十分 ○ Graceful shutdown毎回手書きしてない? ○ エラーにスタックトレースがないけどどうしたら? ○ ORMどれ使ったらいいの? ○ 設定ってどうやって読むのがベスト?
Slide 35
Slide 35 text
定番構成が定まっていない ● パッケージの切り方のガイドラインがない ○ どの層をなんと名づけてどこに置いたらよい? ■ domain? usecase? repository? infra? etc…
Slide 36
Slide 36 text
定番構成が定まっていない ● 既存の実装を参考にするか、自分で考える しかない ○ 断片化による認知負荷増・知識のポータビリティ低下 ■ せっかく複数チームでGoを使っているのに知見を配れない ○ リードタイムに影響する ■ できるだけ技術選定以外のことに時間を使いたいはず ■ 同じ問題を何度も解く意味はない
Slide 37
Slide 37 text
定番構成を決める動き ● Goサブ会で標準化を進めている ○ 発散から収束へ ○ 今後GoでWebアプリケーションを作る際の デファクトスタンダードを用意
Slide 38
Slide 38 text
標準化 ● 定番ライブラリの選定・実装 ● Webアプリケーション向けのテンプレートリ ポジトリ作成 ● https://speakerdeck.com/stefafafan/introductio n-to-the-go-task-force
Slide 39
Slide 39 text
まとめ
Slide 40
Slide 40 text
まとめ ● はてなではGoをよく使っています ○ あなたが今日押したボタンの裏でもGoが動いているか も… ● 今までの利用実績をまとめ、社内スタンダー ドを決めつつあります
Slide 41
Slide 41 text
紹介したライブラリ ● DI ○ https://github.com/google/wire ● テスト ○ https://github.com/stretchr/testify ○ https://github.com/gotestyourself/gotest.tools ○ https://github.com/onsi/ginkgo ● モック ○ https://github.com/uber-go/mock ● ロガー ○ https://github.com/uber-go/zap ○ https://github.com/sirupsen/logrus ● HTTPサーバ ○ https://github.com/labstack/echo ○ https://github.com/go-chi/chi ○ https://github.com/gin-gonic/gin
Slide 42
Slide 42 text
紹介したライブラリ ● API ○ https://github.com/99designs/gqlgen ○ https://github.com/graphql-go/graphql ○ https://github.com/grpc/grpc-go ○ https://github.com/go-swagger/go-swagger ○ https://github.com/deepmap/oapi-codegen ● DB ○ https://github.com/jmoiron/sqlx ○ https://github.com/doug-martin/goqu ○ https://github.com/Masterminds/squirrel ○ https://github.com/go-gorm/gorm ○ https://github.com/volatiletech/sqlboiler ○ https://github.com/ent/ent