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