Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
技術的ミスと深堀り
Search
Recruit
PRO
March 03, 2025
Technology
3
210
技術的ミスと深堀り
2025/2/19に開催したRecruit Tech Conference 2025の雫石の資料です
Recruit
PRO
March 03, 2025
Tweet
Share
More Decks by Recruit
See All by Recruit
事業の財務責任に向き合うリクルートデータプラットフォームのFinOps
recruitengineers
PRO
2
300
AI-DLCを現場にインストールしてみた:プロトタイプ開発で分かったこと・やめたこと
recruitengineers
PRO
2
340
プロダクトマネジメントの分業が生む「デリバリーの渋滞」を解消するTPMの越境
recruitengineers
PRO
3
950
あなたの知らない Linuxカーネル脆弱性の世界
recruitengineers
PRO
4
360
dbtとBigQuery MLで実現する リクルートの営業支援基盤のモデル開発と保守運用
recruitengineers
PRO
5
270
『ホットペッパービューティー』のiOSアプリをUIKitからSwiftUIへ段階的に移行するためにやったこと
recruitengineers
PRO
4
1.8k
経営の意思決定を加速する 「事業KPIダッシュボード」構築の全貌
recruitengineers
PRO
4
450
Browser
recruitengineers
PRO
12
4.1k
JavaScript 研修
recruitengineers
PRO
9
2.3k
Other Decks in Technology
See All in Technology
Keynoteから見るAWSの頭の中
nrinetcom
PRO
1
160
Oracle Database@Google Cloud:サービス概要のご紹介
oracle4engineer
PRO
1
820
田舎で20年スクラム(後編):一個人が企業で長期戦アジャイルに挑む意味
chinmo
1
1k
AWSと生成AIで学ぶ!実行計画の読み解き方とSQLチューニングの実践
yakumo
2
170
善意の活動は、なぜ続かなくなるのか ーふりかえりが"構造を変える判断"になった半年間ー
matsukurou
0
230
ハッカソンから社内プロダクトへ AIエージェント ko☆shi 開発で学んだ4つの重要要素
leveragestech
0
550
松尾研LLM講座2025 応用編Day3「軽量化」 講義資料
aratako
15
4.9k
迷わない!AI×MCP連携のリファレンスアーキテクチャ完全ガイド
cdataj
0
180
小さく、早く、可能性を多産する。生成AIプロジェクト / prAIrie-dog
visional_engineering_and_design
0
320
Introduction to Sansan, inc / Sansan Global Development Center, Inc.
sansan33
PRO
0
2.9k
Node vs Deno vs Bun 〜推しランタイムを見つけよう〜
kamekyame
1
190
Sansan Engineering Unit 紹介資料
sansan33
PRO
1
3.6k
Featured
See All Featured
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
0
3.4k
Build your cross-platform service in a week with App Engine
jlugia
234
18k
Believing is Seeing
oripsolob
0
19
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
9.2k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
9.8k
KATA
mclloyd
PRO
33
15k
A designer walks into a library…
pauljervisheath
210
24k
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
2.8k
Skip the Path - Find Your Career Trail
mkilby
0
37
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
34k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
122
21k
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
2
3.5k
Transcript
技術的ミスと深堀り RECRUIT TECH CONFERENCE 2025 フロントエンドエンジニアが挑むプロダクト価値向上 雫石 卓耶 株式会社リクルート プロダクトディベロップメント室
雫石 卓耶 経歴 / Career 2021年に、リクルートへ新卒入社。社会人4年目。 HR系領域のWebフロントエンド / バックエンドエンジニア 現在は、『リクルートダイレクトスカウト』の開発メンバー
プログラミング。最近は、それ以外の趣味がないのが悩み 趣味 / Hobbies プロダクトディベロップメント室 アプリケーションソリューションユニット 横断エンジニアリング部 アプリケーションソリューショングループ
リクルートダイレクトスカウト • 転職スカウトサービス • 登録しプロフィールを入力すると、 企業 / エージェントからスカウトが届く • スカウトを受諾すると、企業
/ エージェント との、右のようなチャット画面が開く
開発メンバーの一員として • 普段から、技術的なミスをしてしまわないように注意している ◦ ミスが、求職者や企業 / エージェントの、利益や人生に影響して しまうかもしれず、それが怖いから
開発メンバーの一員として • 普段から、技術的なミスをしてしまわないように注意している ◦ ミスが、求職者や企業 / エージェントの、利益や人生に影響して しまうかもしれず、それが怖いから • しかし、システムからミスを完全に無くすのは難しいのも事実
Agenda 明らかになったミスに対して、私は深堀りを行うことがあります。どのような深 堀りを行ったのかについて、3つの事例をご紹介します。 • 事例1:データベースとnull文字 • 事例2:WebSocketとHTTP • 事例3:WebSocketのクローズ忘れ •
まとめ
事例1
事例1:データベースとnull文字 • 事例 ◦ チャット画面に入力されたメッセージをデータ ベースに挿入する際、null文字が含まれていて 失敗した • 補足 ◦
エラーの発生件数は1件だけ ◦ ユーザーへの直接の不利益は無し(メッセージ は通常通り見られる) • 対応 ◦ 入力内容からnull文字を排除する処理を追加
事例1の深堀り • 今回の件を単純化すると、反省点は「DBのvarchar(1)にどのような文字を挿 入できるか」がわかっていなかったこと • そもそも、「文字」はどのように表される? • DBの文字コード(charset)はUTF-8を使用
Unicodeと文字数 a U+61 コードポイント 各文字に一意なコードポイントが 割り振られている
Unicodeと文字数 a U+61 61 UTF-8 コードポイント バイト列 コードポイントをエンコードしてバイト列を得る。 バイト列は、ファイルへの読み書きや、通信などで使用される
Unicodeと文字数 a U+61 61 UTF-8 コードポイント バイト列 仮説1:バイト数を文字数としている?
複数のバイトにエンコードされる文字もある a U+61 61 UTF-8 コードポイント バイト列 あ U+3042 E3
81 82 UTF-8 1バイトに収まらない 複数バイトにエンコード
複数のバイトにエンコードされる文字もある a U+61 61 UTF-8 コードポイント バイト列 あ U+3042 E3
81 82 UTF-8 バイト数を数えると 「あ」は3文字になる
複数のバイトにエンコードされる文字もある a U+61 61 UTF-8 コードポイント バイト列 あ U+3042 E3
81 82 UTF-8 仮説2:コードポイント数を 文字数としている?
複数のコードポイントで表現される文字もある 文字画像の出典: https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:U845b-k.svg https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:U845b.svg 「かつしかく」 の1文字目 「かつらぎし」 の1文字目 U+845B U+E0101
U+845B U+E0100
複数のコードポイントで表現される文字もある 文字画像の出典: https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:U845b-k.svg https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:U845b.svg 「かつしかく」 の1文字目 「かつらぎし」 の1文字目 U+845B U+E0101
U+845B U+E0100 基底文字としては区別されない
コードポイントは、文字の同一性ごとに割り当てられる • Unicodeは、文字の形の詳細に立ち入らない ◦ 文字の形はフォントが決める • いろいろな「a」があるが、抽象的には同一の文字 • 同一の文字なので、おなじコードポイントが割り当てられている 表の出典:
Unicode® Technical Report #17: Unicode Character Encoding Model, https://www.unicode.org/reports/tr17/
複数のコードポイントで表現される文字もある 文字画像の出典: https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:U845b-k.svg https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:U845b.svg 「かつしかく」 の1文字目 「かつらぎし」 の1文字目 U+845B U+E0101
U+845B U+E0100 異体字: 見た目は異なるが意味は同じ文字 →同一な文字とみなされて同じコードポ イントが割り当てられた →賛否両論あったらしい
複数のコードポイントで表現される文字もある 文字画像の出典: https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:U845b-k.svg https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:U845b.svg 「かつしかく」 の1文字目 「かつらぎし」 の1文字目 U+845B U+E0101
U+845B U+E0100 異体字セレクタによって指定できる
複数のコードポイントで表現される文字もある a U+61 61 UTF-8 コードポイント バイト列 あ U+3042 E3
81 82 UTF-8 U+845B U+E0100 E8 91 9B F3 A0 84 80 UTF-8 コードポイント数を数えると は2文字になる
複数のコードポイントで表現される文字もある a U+61 61 UTF-8 コードポイント バイト列 あ U+3042 E3
81 82 UTF-8 U+845B U+E0100 E8 91 9B F3 A0 84 80 UTF-8 書記素クラスタを使うと、 「ユーザが認識する『文字』の境界」 を決定できる。 仮説3:書記素クラスタ数を 文字数としている?
どの仮説が正しい? • 仮説1:バイト数? • 仮説2:コードポイント数? • 仮説3:書記素クラスタ数?
実験してみた • 使用しているDBMSはPostgreSQL • varchar(1)の列を定義し、いろいろな文字を挿入してみた ◦ a(U+0061):挿入可 ◦ あ(U+3042):挿入可 ◦
(U+845B U+E0100):挿入不可 • →文字数は、コードポイント数でカウントされるようだ(仮説2が正しそう) • →varchar(1)には「コードポイント1つ分」が挿入できそうだ
すべてのコードポイントが挿入可能なのか? null文字(0x0000)以外のすべてのコードポイントを挿入するプログラムを作成 してみた Unicodeコードポイント(約110万個) 0 0x10ffff
すべてのコードポイントが挿入可能なのか? null文字(0x0000)以外のすべてのコードポイントを挿入するプログラムを作成 してみた →一部の範囲のコードポイントが挿入できなかった Unicodeコードポイント(約110万個) 0 0x10ffff
すべてのコードポイントが挿入可能なのか? Unicodeコードポイント(約110万個) 0 0x10ffff UTF-16のサロゲートペアに使用される領域。 単独では文字を表さない
すべてのコードポイントが挿入可能なのか? Unicodeスカラ値(USV) 0 0x10ffff
すべてのコードポイントが挿入可能なのか? Unicodeスカラ値(USV) 0 0x10ffff varchar(1)にどのような文字を挿入できるか? →USV - {0}の任意の値1つ(PostgreSQLでは)
追加の調査 • フロントエンドやバックエンドでは、バリデーション処理で文字数を数えて いる。このカウント方法はコードポイント数によるか? そうでない場合、 DBのカウント方式と差異があるが、おかしな挙動にならないか? • サロゲートペアが単独で入力されることはないか? された場合、DBではエ ラーになるが、システム全体としてはどうなる? →深堀りを行うことで、新しい観点が得られ、横展開調査ができた →結果としては問題なかった
事例2
事例2:WebSocketとHTTP • 背景 ◦ チャット機能では、メッセージサーバーとの通 信をWebSocketで実現している • 事例 ◦ リリース前試験において、リクルート社内の一
部のセキュリティが厳しい環境で、チャット機 能が使えない • 補足 ◦ その環境では、ファイアウォールにより、あら かじめ許可された種類の通信しかできない
チャット機能の通信を許可してもらうことに ファイアウォール担当「WebSocket通信を利用したいのですね。であれば、 HTTPの許可は不要ですかね? TCPポートだけ許可すれば良いですか?」
チャット機能の通信を許可してもらうことに ファイアウォール担当「WebSocket通信を利用したいのですね。であれば、 HTTPの許可は不要ですかね? TCPポートだけ許可すれば良いですか?」 私「はい……おそらくHTTPの許可は必要ないと思います……? TCPポートは 443番を使用しているようなので、許可していただけますか……?」
チャット機能の通信を許可してもらうことに ファイアウォール担当「WebSocket通信を利用したいのですね。であれば、 HTTPの許可は不要ですかね? TCPポートだけ許可すれば良いですか?」 私「はい……おそらくHTTPの許可は必要ないと思います……? TCPポートは 443番を使用しているようなので、許可していただけますか……?」 →TCPだけ許可してもチャット機能は使えず
チャット機能の通信を許可してもらうことに ファイアウォール担当「WebSocket通信を利用したいのですね。であれば、 HTTPの許可は不要ですかね? TCPポートだけ許可すれば良いですか?」 私「はい……おそらくHTTPの許可は必要ないと思います……? TCPポートは 443番を使用しているようなので、許可していただけますか……?」 →TCPだけ許可してもチャット機能は使えず 私「あっ、やっぱりHTTPも関係するみたいなので許可をお願いします……」 →ようやくチャット機能が利用可能に
私は、WebSocketのことを 何もわかっていない……
私の趣味 • プロトコルスタックの自作 ◦ イーサネット〜TCPまでの、C言語での簡易的な自作実装はすでにあっ た • イーサネット〜WebSocketまでを(簡易的にでも)全部実装すれば、理解を 深められるかもと思った •
送ったデータをそのまま返す、WebSocket Echoサーバーを実装してみる
実装したWebSocket Echoサーバーの動作
TCP接続をパッシブオープン • クライアントからのWebSocketリクエストを待ち受け
クライアントからの最初のリクエスト • GET / HTTP/1.1 • Host: xxx • Upgrade:
websocket ◦ WebSocket通信にアップグレードしたいと言っている • Connection: Upgrade • Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== ◦ 次に応答を返すために必要 • Sec-WebSocket-Version: 13
サーバーからのレスポンス • HTTP/1.1 101 Switching Protocols • Upgrade: websocket •
Connection: Upgrade • Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= ◦ 先ほどのSec-WebSocket-Keyに、仕様で決まっているマジックナンバーを追 加し、sha1をとって更にbase64エンコードしたもの ◦ 正しい手順でWebSocket要求が受け入れられたことをクライアントに示す →WebSocket接続完了 →先ほどのファイアウォール問題で、TCPだけでなくHTTPも許可する必要があった理由
ここから先はバイナリで通信する • 以下のような形式のバイナリデータがTCPソケットで送られてくる • 仕様通りにフラグやマスキングの処理を行うと、ペイロードが得られる • 同じようにして、ペイロードをそのまま返却すると…… 出典:FETTE, Ian; MELNIKOV,
Alexey. Rfc 6455: The websocket protocol. 2011.
動作した! →うれしい
事例3
事例3:WebSocketのクローズ忘れ • 事例 ◦ チャット画面を閉じた後も、WebSocketの接続が残り続けてしまう場合 がある ▪ システムに余分な負荷がかかってしまう • 原因
◦ WebSocketのクローズ処理の実装漏れ • 対策 ◦ クローズ処理を追加する
チャット画面を開閉してChrome DevToolsの表示を確認 クローズ処理の追加前後で、通信状況を比較してテスト クローズ処理追加前 クローズ処理追加後 →この表示だけを証拠に「接続が閉じた」と判断するのは心もとなかった
WebSocketについて学んだ今なら • 「WebSocketの通信=TCPソケット」とわかっている ◦ →OSのTCPスタックに問い合わせれば状況がわかる ◦ ESTAB状態のソケット数の増減を調べることで、確実にWebSocketがク ローズされていることを確認して、修正をリリースできた • 学んでいなかった以前の私なら「そもそもWebSocketの『接続』とは何だろ
う……?」となっていた気がする
まとめ • どの事例も、修正自体は軽微なもの
まとめ • どの事例も、修正自体は軽微なもの • しかし、そこから深堀りすると、物事の仕組みがわかって楽しい ◦ →私の楽しみ
まとめ • どの事例も、修正自体は軽微なもの • しかし、そこから深堀りすると、物事の仕組みがわかって楽しい ◦ →私の楽しみ • それが、類似の問題を防いだり、確実に解決したりすることにつながる ◦
→サービスの利用者、求職者や企業 / エージェントのため
まとめ • どの事例も、修正自体は軽微なもの • しかし、そこから深堀りすると、物事の仕組みがわかって楽しい ◦ →私の楽しみ • それが、類似の問題を防いだり、確実に解決したりすることにつながる ◦
→サービスの利用者、求職者や企業 / エージェントのため • 「私の楽しみ」と「サービス利用者のため」を両立させていきたい