はてなのサービスを支えるGo / hatena.go #1 maku693
by
HAMADA Shota
×
Copy
Open
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
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