Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
GoでRouter自作実装寄りな話
Search
bmf_san
June 23, 2021
Programming
270
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
GoでRouter自作実装寄りな話
bmf_san
June 23, 2021
More Decks by bmf_san
See All by bmf_san
桃太郎で始めるRego入門‐今日から使えるRegoの基本編
bmf_san
0
110
完璧を求めない意思決定-アクセス制御基盤における制約との向き合い方
bmf_san
5
20k
AAPについて調べてみた
bmf_san
0
160
レーダーをつくる
bmf_san
0
97
契約テストとPactについて
bmf_san
0
140
5分でわかるSLO
bmf_san
2
190
権限について考える
bmf_san
2
190
自作HTTPルーターから新しいServeMuxへ
bmf_san
3
1.9k
古くなってしまったPHPフレームワークとPHPのバージョンアップ戦略
bmf_san
1
530
Other Decks in Programming
See All in Programming
APNsからLive Activityを開始する話
yumnumm
0
160
動作中のプログラムの中身をリアルタイムに覗く / Realtime Debugger for CSharp with Roslyn
prota
1
1.8k
なぜCTOを降りてFDEを選んだのか?〜なぜプロダクト企業がFDEで顧客の現場に踏み込むのか〜
gonta
1
170
Are APIs Still Relevant in the AI Era?
soyuka
0
440
AWSに止められる覚悟してますか?
morizo_1984
2
520
パズルゲームの作り方 / how to make puzzle games
kaityo256
PRO
2
280
JAWS-UG 東京支部が始める、JAWS-UG支部コラボ / JAWS-UG lunchtime LT Collaboration
y0hgi
0
210
KiroのSpecで「五目並べ」を作ってみる
satoshi256kbyte
1
360
RAG の “R” を Swift で覗いてみる 〜「意味から探す」検索の仕組み〜
nao_randd
0
120
mrbgem 三角測量 開発
ogom
0
220
Unity6 URPによる海底をテーマにしたVJシステムの解説 | Unity Shader 完全に理解した 勉強会
gam0022
0
340
Ghostty + Neovimで作る 透明でカッコ良い開発環境
j341nono
0
160
Featured
See All Featured
BBQ
matthewcrist
90
10k
Build your cross-platform service in a week with App Engine
jlugia
234
19k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
540
Measuring & Analyzing Core Web Vitals
bluesmoon
9
1k
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
58k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
590
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.4k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.3k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
68
58k
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.6k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
203
77k
Transcript
GoでRouter⾃作 実装寄りな話 @bmf_san 2021.06.23 社内LT
なんの話 • net/httpを拡張したrouterのライブラリ • net/httpの”⾜りないところ”を補う • /user/:idのような動的なルーティングができな い
ϒϩάͱ͔-5ͱ͔Ͱ͍·Θͨ͠ωλ
Github https://github.com/bmf-san/goblin
Goblin仕様 • net/http準拠 • 動的なルーティング • 名前付きのパラメータ(パスパラーメーター)をサポート/ users/:id • 正規表現も使える
/users/:id[^\d+$] • ミドルウェアをサポート • net/httpのhttp.Handlerインターフェースに従った関数をミドル ウェアとしてルーティングの処理に組み込める
Goblin例 IUUQTHJUIVCDPNCNGTBOHPCMJOCMPCNBTUFS@FYBNQMFTNBJOHPΛࢀর
有名どころ • ライブラリ • https://github.com/fasthttp/router • https://github.com/julienschmidt/httprouter • http://github.com/go-chi/chi •
FW • https://github.com/gin-gonic/gin • https://github.com/labstack/echo • https://github.com/gorilla/mux
Routerの役⽬ NJEEMFXBSFIBOEMFSͷखલͰॲཧ͞ΕΔΠϝʔδ
Routerの役⽬ • リクエストされたURLやHTTP Methodに応じて、 処理の実⾏を制御するアプリケーション • URLとアプリケーションの処理を結びつける
データ構造を考える ・Router≒⽂字列マッチング ・URLの階層構造と相性が良いデータ構造 →⽊構造
⽊構造
トライ⽊(プレフィックス⽊) ・⽂字列の集合を扱う⽊構造の⼀種 ・ざっくりいうと、⽂字列を探索しやすいように⽊に 格納したやつ ・ex. サジェスト、IPアドレス探索、形態素解析とか ⽂字列を扱う系のやつのベースだったりするぽい
もっと良い⽊ • 時間的計算量(処理時間)、空間的計算量(メモ リ)の効率を追求するなら他に選択肢がある • ex. Radix(Prefix) tree https://www.cs.usfca.edu/ ~galles/visualization/RadixTree.html
• 実装できなかった。ムズい。 • strings.Replacerは内部でRadix tree 実装してい る
トライ⽊を知る • https://www.cs.usfca.edu/~galles/visualization/ Trie.html • アルゴリズムのビジュアライズ • https://github.com/bmf-san/road-to-algorithm- master/tree/master/data_structures/tree/trie •
参照実装
オレオレトライ⽊
オレオレトライ⽊(旧) • 最初のリリースで実装していた⽊ • HTTPメソッドをノードに⼊れてしまうのはアンチパターンだった • ルーティングの処理にHTTPメソッドの⼀致を前提としてしまう • HandlerがHTTPメソッドに依存するような実装になってしまう •
middlewareの対応で不都合に • cf. https://bmf-tech.com/posts/⾃作ルーティングをアップデートした
主な構造体 NBQͱMJOLFEMJTUͷ߹ମͰΛදݱͨ͠Α͏ͳΠϝʔδʁ
Goでrouterを実装する上で知っておきたいこと • net/httpの概観 • どんな構造体があるか、どこを拡張したら良いか、どんなイン ターフェースに従うべきか • cf. https://golang.org/pkg/net/http/ •
HTTPサーバーの処理 • http.ListenAndServeから内部を⾒る • cf. https://bmf-tech.com/posts/GolangのHTTPサーバーのコード リーディング
HTTPサーバーのコードにdeep dive • 良く⾒るGoのHTTPサーバーのコード(⾊々省略さ れている)
HTTPサーバーのコードにdeep dive • 省略しないで書いたパターン
HTTPサーバーのコードにdeep dive • ServeHTTPは関数型のaliasであるHandlerFuncに置き換えることができる • cf. • func (f HandlerfFunc)
ServeHTTP(w ResponseWriter, r *Request) • https://golang.org/src/net/http/server.go?s=64180:64240#L2058
HTTPサーバーのコードにdeep dive • Mux(http.NewServeMux( ))は作らなくても良い。DefaultServeMuxを使うことができ る。 • DefaultServeMuxはServeMux型の構造体を持っており、HandlerFuncというmuxにルー ティングを登録する関数を実装している。 •
cf. • DefaultServeMux • https://golang.org/src/net/http/server.go?s=77627:77714#L2269 • func (mux *ServeMux) HandlerFunc(pattern string, handler func(ResponseWriter, *Request))
HTTPサーバーのコードにdeep dive • Server構造体(http.Server{})もわざわざ作らなくても良い。net/httpには ListenAndServe( )が⽤意されている。 • cf. • func
(*Server) ListenAndServe • https://golang.org/pkg/net/http/#ListenAndServe • func ListenAndServe(addr string, handler Handler) error
Routerを実装するには • →http.Handlerインターフェース を意識して、muxを作れば良い
ルーティングを登録する部分の実装 • cf. https://github.com/bmf-san/goblin/blob/master/router.go • メソッドチェーンでrouteを登録する処理 • ServeHTTPの実装(≒http.Handlerインターフェースの実装)した構造体を作る • ServeHTTP内では、ルーティング、ミドルウェア・ハンドラの実⾏を順番にやる
• 作った構造体はListenAndServeに渡される想定 • cf. https://github.com/bmf-san/goblin/blob/master/_examples/main.go
middleware対応のための実装 • cf. https://github.com/bmf-san/goblin/blob/master/ middleware.go • Sliceに保持したミドルウェアを順番に処理していく • 処理をラップしていくように実⾏する •
cf. https://github.com/bmf-san/goblin/blob/ master/_examples/main.go • いわゆるDecorator patternってやつだと思う
muxにあたる部分の実装 • cf. https://github.com/bmf-san/goblin/blob/master/trie.go • オレオレトライ⽊を頑張ってかく • 単純なトライ⽊を書いて、それを発展させていく • データ構造を考えきった時点で6~7割くらい完成ではある
• テストとデバッガを有効につかう • テストがないと前に進めないくらいテストを有⽤ • ⾊々なパターンのルート定義を考慮する必要があり、テストケースが結構悩ましい • デバッガは⽊の⽣成が上⼿くできているか確認したり、脳内デバッグで間に合わないときに有⽤ • 正規表現の利⽤ • 正規表現を使ったルーティングのケースに対応するためにregexpを使っている • strings.Replacerで代⽤できるならそっちが良い • Goでは正規表現はコストがかかる処理なのでキャッシュして再利⽤性を⾼めると良い • 後で対応しようと思っていたらPRもらえた • https://github.com/bmf-san/goblin/pull/17
ベンチマーク • ϕϯνϚʔΫςετ • cf. https://github.com/julienschmidt/go-http-routing-benchmark • go test -bench=“Goblin|Gin|GorillaMux|HttpRouter|Chi|Beego|Echo”
• ϕϯνϚʔΫ݁Ռ • cf. https://github.com/bmf-san/goblin/issues/ 34#issuecomment-864978325 • Routerબఆͷ؍ύϑΥʔϚϯε͚ͩͰͳ͘ɺػೳ໘net/ httpͷΠϯλʔϑΣʔεΛҙ͍ࣝͯ͠Δ͔Ͳ͏͔ͷόϥϯε͕େࣄ ͦ͏ • cf. https://github.com/julienschmidt/go-http-routing- benchmark#conclusions
ベンチマーク • cf. https://github.com/julienschmidt/go-http-routing- benchmark • GoblinՃ͠·ͨ͠ରઓΑΖ͓͘͠Ͷ͕͍͠·͢PR • https://github.com/julienschmidt/go-http-routing- benchmark/pull/97
• READMEߋ৽͍ͯ͠ͳ͍͔ΒϦετݟͨͧ͠PR • https://github.com/julienschmidt/go-http-routing- benchmark/pull/96