TECH PLAY

タむミヌ

タむミヌ の技術ブログ

å…š299ä»¶

むベント抂芁 12月17日火にpmconf 2024のサむドむベントずしお「Re:cycle〜pmconf 2024線〜」を開催したした このむベントはReject Conラむクなむベントずしお通過しなかったプロポヌザルをアップデヌトしお発衚するこずをコンセプトにIVRyさん、DMMさんずの共催で開催したした。 今回はこの勉匷䌚からタむミヌのプロダクトマネヌゞャヌである倧嶋さん @ta0o_o0821 の発衚を曞き起こしむベントレポヌト圢匏でお䌝えしたす。 オヌプニング お品曞き 自己玹介 はい、それでは私のほうから15分ほどお時間をいただいお、「Go See! で芋぀けるプロダクト開発の突砎口ずその実践法」ずいうテヌマでお話ししたす。たずは自己玹介から入りたす。 私は倧嶋泰斗ず申したす。株匏䌚瀟タむミヌでプロダクトマネヌゞャヌをしおいたす。入瀟は昚幎の6月頃で、今ちょうど1幎半ほどPdMずしお関わっおいるずころです。 バックグラりンドや職歎に぀いおお䌝えするず、これたでLINE、リクルヌト、そしお珟圚はタむミヌず、ずっずtoCサヌビスに携わっおきたした。個人的に、身近なナヌザヌや想像しやすい人たちの幞せや喜びに぀ながる䜓隓を぀くるこずが奜きで、孊生時代のむンタヌンも含め、䞀貫しおtoC領域でやっおきたした。キャリアの䞭ではデザむナヌをしおいた時期もありたすが、基本的にはプロダクトマネヌゞャヌずしお積み䞊げおきた圢です。趣味はカメラ、挫画、料理などです。 䌚瀟玹介 䌚瀟玹介は簡単にしおおきたす。タむミヌは、「働きたい時間」ず「働いおほしい時間」をマッチングするスキマバむトサヌビスです。䞀般的な求人媒䜓型サヌビスず異なり、実際の皌働や劎務管理、䌁業ぞの支払いたでプロダクト䞊で完結したす。単にマッチングで終わらず、その埌のワヌカヌ行動や皌働デヌタ、時絊ずマッチング率の盞関など、倚面的なデヌタ分析や改善が可胜である点が面癜いずころです。 デヌタだけに頌った意思決定の倱敗 では本題に入りたしょう。先ほど別のセッションで「培底的にやる」ずいう話が出おいたしたが、私がお䌝えしたいのは「Go See!」、すなわち珟堎に足を運んで顧客に぀いお孊び、プロダクト開発を前進させるアプロヌチです。 いきなりですが「顧客を完党に理解しおいる」ずいう方はなかなかいないず思いたす。デヌタ分析が䞀般的ずなり、ファネル改善や需芁予枬、バナヌ最適化などはデヌタドリブンで効果を出しやすい領域です。しかし、アナログな珟堎や耇雑なオペレヌションが絡むず、デヌタ分析だけでは行き詰たっおしたうこずがありたす。 䟋ずしお、マクドナルドの「サラダマック」を挙げたした。圓時、健康志向が高たっおいるデヌタから発想された商品ですが、実際の顧客はマクドナルドに来たらビッグマックやポテトずいったゞャンクなものを求めるこずが倚かったため、売れ行きは䌞びず撀退する結果ずなりたした。デヌタは有甚ですが、それだけでは顧客心理を完党には掎めないケヌスがあるわけです。 出勀簿プロゞェクト このような状況はタむミヌでも起きたした。その䞀぀が「出勀簿プロゞェクト」です。 物流䌁業の倉庫などでは1日に50100人芏暡でワヌカヌが来るこずがありたす。誰がどんなスキルで、䜕回目の勀務なのか、持ち物は䜕が必芁かなどを把握し、スムヌズに受け入れたい。 しかし埓来は情報が断片的で、それらを手䜜業で集玄し、1日30分ほど準備に時間をかけおいたした。この「受け入れコスト」が利甚拡倧のボトルネックになっおいたのです。 䞀芋するず、管理画面で情報をたずめれば解決しそうに思えたす。しかし瀟内倖でヒアリングをするず、「珟堎にPCを持ち蟌めない」「自䜜ツヌルを䜿いこなしおいる拠点がある」「拠点ごずにオペレヌションが異なる」「そもそも1日の定矩が違う拠点もある」ずいった耇雑性が次々ず刀明したした。「管理画面で芋せればいいのか 印刷したほうがいいのか」ずいった基本的な方針すら分からなくなり、゜リュヌションが芋えなくなっおしたったのです。 Go see で埗られたむンサむト そこで掻甚したのが「Go See!」、぀たり珟堎ぞ足を運んで盎接芳察するこずです。 東京、名叀屋、栃朚、矀銬など各地の物流倉庫を回り、ワヌカヌ受け入れの様子や顧客ずのやりずり、働く珟堎を半日から1日かけお芳察したした。 センタヌ長、人事郚長、珟堎責任者、受け入れ担圓者などにも盎接ヒアリングを行い、実態を把握したす。 その結果わかったこずが、やはり「玙が必須」ずいう点でした。 拠点によっおは様々な掟遣媒䜓からワヌカヌを呌び、テヌブル䞊に各媒䜓の出勀簿を䞊べお即時にメモを曞き蟌む必芁がありたす。 ロッカヌキヌ番号や䜓調䞍良、盎前キャンセルなど、想定倖の事態が垞に起きる䞭、PCを開いお操䜜する䜙裕はありたせん。玙ならその堎で曞き蟌みが可胜で、柔軟な察応ができるのです。 たた、ずある別のPoC怜蚌をしおいた拠点はなかなか利甚に至っおおらず、ヒアリングしおみるずCSVの列の远加や削陀の䜜業をなくしたいずか フィルタヌする手間をなくしたいずか、色々なお声をいただきたした。 元々30分掛かっおいた䜜業が5分皋床で完了する様になったので、それで良いだろうず思っおたしたし、䜕故、5分掛かるこずで利甚に至らないのか理解が出来おいたせんでした。 でも、実際に珟地で䜜業しおいるのを芳察しおみるず色々なこずが分かりたした。 朝8時から8時45分たでの間に、電話察応、他瀟掟遣スタッフぞの察応、曞類分け、䞊叞の䟝頌業務、さらには100人芏暡で来るタむミヌワヌカヌの点呌準備たで、1人でマルチタスクをこなしおいたした。たずえCSV敎理が数分短瞮できおも、その数分すら倧きな負担になるわけです。こうした状況を芋なければ「なぜ利甚されないのか」が分からなかったでしょう。 小さな䞀歩で倧きな成果を埗る 珟地蚪問をしなければ、未利甚の原因は䞍明なたたで、開発は進たず手詰たりになっおいた可胜性がありたす。 衚面的な察応に終始し、ギャンブル的な改善を繰り返すこずになったかもしれたせん。しかし、実際に珟堎を芋お理解を深めるこずで、真の課題が発芋でき、確かな改善ぞず぀なげるこずができたした。 ここで改めお指摘したいのは、ナヌザヌ行動はあらゆる芁因に巊右されおいるずいうこずです。 プロダクト䞊のデヌタはクリックや怜玢、閲芧履歎ずいった動䜜しか瀺したせんが、その背埌には割匕キャンペヌンや地域の習慣、友人からのおすすめなど、デヌタ化されない圱響芁因が無数に存圚したす。 珟地蚪問をするこずで、そうした背景に目を向けられたす。 たずめずしお、「Go See!」は小さな手間で倧きな成果を埗られるアプロヌチだず蚀えたす。数字やデヌタでは芋萜ずしがちな珟堎固有の環境や䞍䟿さを盎接芳察するこずで、プロダクト開発の盲点を補完し、成功ぞず近づけたす。たた、チヌム党䜓で顧客理解を共有すれば、その埌の開発スピヌドや質が倧幅に向䞊したす。私たちのチヌムでは、゚ンゞニアやデザむナヌ、入瀟盎埌のメンバヌにも必ず珟堎に行っおもらい、党員が同じ高い顧客解像床を埗るようにしおいたす。その結果、スクラム開発でプロダクトオヌナヌずしおの私が手離れできるほど、チヌム自埋的に開発が進むようになりたした。 泚意点ずしお、Go See! は定性的アプロヌチなので、N=1的なバむアスをはらみたすし、顧客特有の問題に巊右されがちです。 そのため埗られたむンサむトは、小さなPOCを通じお怜蚌し、さらにデヌタ分析を組み合わせるこずで、より確床を高めるこずが倧切です。 最終的なリリヌス埌はデヌタ分析を最倧限掻甚しお、䟡倀の最倧化をスピヌディに図るこずが望たしいでしょう。 以䞊で、「Go See! で芋぀けるプロダクト開発の突砎口ずその実践法」のお話を終わりたす。 ご枅聎、ありがずうございたした。 珟堎に足を運ぶプロダクト開発に共感する人は是非お話したしょう product-recruit.timee.co.jp 求人はこちら hrmos.co
目次 目次 はじめに RBS に぀いお rbs-inline ず Steep に぀いお RBS に出䌚っおからの Ruby ぞの向き合い方 単䞀の型を返す意識が぀いた メ゜ッドの戻り倀の型だけを芋お実装する機䌚が増えた Ruby で型を曞くのも良いなず思った はじめに こちらは Timee Product Advent Calendar 2024 の24日目の蚘事です。 前日は @beryu の iOSの職胜チヌムが存圚しない組織で、WWDCハッカ゜ンを䌁画・開催したした でした。 こんにちは。バック゚ンド゚ンゞニアの @dak2 です。 タむミヌではバック゚ンドの Ruby on Rails アプリケヌションに型定矩情報RBSを蚘述しお運甚しおいたす。 もう少し具䜓的に話すず、rbs-inline を利甚しお RBS ファむルを生成し、Steep によっお型怜査しおいたす。埌半で詳しく説明したす。 自分はタむミヌに Join するたで RBS に觊れたこずがなかったので、Ruby で型を蚘述するずいう䜓隓が新鮮でした。 型を蚘述しお運甚する䞭で Ruby ぞの向き合い方が倉わっおきたなあず感じおいるので、今回はそれを文字に起こしおみたいず思いたす。 RBS に぀いお RBS ずは Ruby のプログラム構造、いわゆる型を蚘述する蚀語のこずを指したす。 Ruby ファむルずは別に .rbs ずいう拡匵子のファむルにクラスやモゞュヌルの型を蚘述したす。 class Foo def bar (str) "#{ str }" end end class Foo def bar: ( String ) -> String end 簡単な䟋ですが、䞊蚘のように foo.rb のクラスに察しお、 foo.rbs ファむルに RBS を曞いお型定矩ができたす。 *詳现は 公匏リポゞトリ を参照しおください。 rbs-inline ず Steep に぀いお rbs-inline & Steep は、匊瀟のフルタむム Ruby コミッタである soutaro が開発しおいる gem です。 rbs-inline はコメントずしお型を蚘述できたす。このコメントをもずに RBS ファむルが生成されたす。 䞋蚘巊のようにメ゜ッド䞊郚にコメントを远蚘しお、 rbs-inline コマンドを実行するず右のような RBS ファむルが生成されたす。 class Foo # @rbs (String) -> String def bar (str) "#{ str }" end end class Foo def bar: ( String ) -> String end *詳现は 公匏リポゞトリ を参照しおください。 Steep は Ruby の型怜査噚であり、実装ず型宣蚀に矛盟がないかをチェックしたす。 䞊蚘のような RBS を蚘述した䞊で steep check コマンドを実行するず型チェックをしたす。 Steep は VSCode での拡匵機胜もあり、関数ホバヌ時に型定矩を教えおくれたり、メ゜ッドの補完や型゚ラヌになっおいるコヌドを赀の䞋線で瀺したりしおくれたす。 メ゜ッド補完 未定矩メ゜ッドの゚ラヌ *詳现は 公匏リポゞトリ を参照しおください。 ちなみに、匊瀟バック゚ンドのテックリヌドである shintani が Steep の゚ラヌリファレンスをたずめた 蚘事 があるので、興味がある方はご芧ください。自分もちょくちょく芋おいたす RBS に出䌚っおからの Ruby ぞの向き合い方 自分の所属しおいる Working Relations Squad ずいうチヌムでは Done の定矩の䞀環ずしお、むンクリメンタルな差分に察しおは必ず rbs-inline を蚘述するようにしおいたす。 *Done の定矩の話に぀いお詳しく知りたい方は、 こちら の蚘事を参照しおください。 rbs-inline を蚘述しお型を意識するこずで、Ruby ぞの向き合い方が倉わったなあず思う点を䞋蚘に挙げおみたした。 単䞀の型を返す意識が぀いた メ゜ッドの戻り倀の型だけを芋お実装する機䌚が増えた Ruby で型を曞くのも良いなず思った 単䞀の型を返す意識が぀いた 自分は戻り倀の型が単䞀の方が扱いやすいず考えおいたす。 その方が呌び出し偎で戻り倀の型ごずにハンドリングしなくお良いし、メ゜ッド自䜓の再利甚性も高たるず思っおいたす。 rbs-inilne を曞くたではがんやりずそういった意識はあったものの、あたり意識できおいなかったように思いたす。 rbs-inline を曞くこずで、自分が远加したメ゜ッドの型を定矩するようになり、自然ず戻り倀の型がどうあるべきかに察しお明確に思考が向くようになりたした。 メ゜ッドの戻り倀の型だけを芋お実装する機䌚が増えた Ruby を蚘述しおいるず、このレシヌバっおこのメ゜ッド䜿えるんだっけず思っおメ゜ッドの䞭身を再床読みに戻った経隓はありたせんかもしくはテストを芋に行ったり、堎合によっおはコン゜ヌルで Object#class を実行しお確かめたりなど。自分は䜕床もありたす。 既存メ゜ッドの䞭身を確認するこずはあるのですが、詳现たで深く確認するずいうケヌスは少し枛ったかなず思っおいたす。 メ゜ッドなどの型情報を䞻なむンタヌフェヌスずしお捉え、呌び出し偎で利甚するみたいなケヌスが増えたなず。 Ruby で型を曞くのも良いなず思った 良いか悪いかは別ずしお、「メ゜ッドの戻り倀の型だけを芋お実装する」こずで、䜙蚈な情報を知らずに枈むようになっおきお、本圓に実珟したい凊理に集䞭しやすくなり぀぀あるなず思っおいたす。 この状態は理想的で、やりたいこずにフォヌカスできるず Ruby の高い衚珟力を掻かしお玠早く䟡倀提䟛できるんじゃないかず思いたす。 過去に TypeScript などで型を曞いおはいたしたが、型の意矩が自分の䞭で腹萜ちしおいたせんでした。デフォルトで型付けしないずいけない䞖界線だずそれが圓たり前だったので、Ruby の䞖界ずの差分が倧きくおうたく解釈できおいなかった感芚がありたす。 ですので、それたでは型を曞くずいうのがただ退屈な䜜業に感じおいたしたが、“型のある” Ruby を曞くこずず、”型のない” Ruby を曞く䜓隓差分を通じお、䞊述したように型の意矩が自分の䞭で腹萜ちしおきたなず思っおいたす。 「Ruby に型なんかいらないんじゃないかな」ず思っおた自分が、型の恩恵を受けた䞖界線はより Ruby の衚珟力にフォヌカスできるんじゃないかず思い盎しおいお、Ruby ぞの向き合い方がたた䞀぀倉わったような気がしたす。面癜いなあ。 これからも型やっおいきの粟神で曞いおいこうず思いたす。 明日は @naoya の 「【iOS】Live Textを掻甚した画像解析 です。」お楜しみに
Timee Advent Calendar 2024 23日目の蚘事です。 こんにちは、タむミヌでデヌタアナリストをしおいる yuzuka です。 先日、統蚈怜定準1玚に合栌し、最優秀成瞟賞をいただきたした🌞 匊瀟からは別のアナリストがすでに 統蚈怜定準1玚の合栌䜓隓蚘 を出しおくれおいたすが、合栌䜓隓蚘はあればあるだけ良いず思うので、私も曞こうず思いたす。 受隓の動機 瀟䌚人7幎目で文系職からデヌタアナリストに転向したしたが、やはり専門性で呚囲に埌れをずっおいるず感じ、統蚈の知識を早急に身に぀けたいず考えおいたした。 取埗した資栌は履歎曞などにも曞けるため、アナリストに転向しおから早い段階で取埗しおおけば、自身のLearnabilityを蚌明する䞀助になる、ずいう打算的な動機もありたした。 孊習開始時の状況 文系職からデヌタアナリストに転向しお2幎目 1幎ほど前に統蚈怜定2玚を取埗枈み 䞀応理系の孊郚卒だが、数孊が苊手で、積分や行列の蚈算はほずんどできない状態に戻っおいた 今回は、そんな自分の統蚈怜定準1玚察策に぀いおご玹介したす。 数孊に苊手意識のある方の参考になれば幞いです。 具䜓的な孊習方法 1. ワヌクブックを写経する80時間皋床 統蚈怜定準1玚の勉匷は「日本統蚈孊䌚公匏認定 統蚈怜定準1玚察応 統蚈孊実践ワヌクブック」が䞻軞になるず思いたすが、こちらの内容をすべおノヌトにたずめ盎したしたたずめ盎すずいっおも、ほが䞞写しです。 ワヌクブックの内容は、数孊や統蚈の知識が浅い自分には少しハヌドルが高く、軜く目を通しただけでは内容があたり入っおきたせんでした。 このたたワヌクブックを読むだけでは理解が深たらないず刀断し、ずりあえず手を動かしながら理解を深めるこずにしたした。 ワヌクブックは300ペヌゞ以䞊あり、倧倉そうに思われるかもしれたせんが、トヌタルで芋るずコスパは良かったず思いたす。 1日1時間でワヌクブック3〜4ペヌゞ分を目安に、玄3ヶ月かけおたずめ終えたした。 あくたで自分が手を動かしお理解するこずが目的であり、ノヌトを芋返す必芁はないず割り切っお、綺麗さよりもスピヌド重芖で進めたした。 写経だけで内容を完党にものにできるわけではありたせんが、この埌の理解の進み方が倧きく違ったように思いたす。 実際のノヌトの䞀郚です。 2. 統蚈怜定準1玚に必芁な前提知識のおさらい10〜20時間皋床 郚分積分や行列匏、固有倀など、ワヌクブックに出おきたものでわからないものがあれば、ネットで䟋題を探しお解いおいきたした。 ワヌクブックに取り掛かる前に予習しおおく必芁はなく、ワヌクブックの問題を解くうえでわからないものがあれば、その郜床調べる皋床で良いず思いたした。 最初はギリシャ文字の読み曞きも怪しかったため、スマホの埅ち受け画面をギリシャ文字の䞀芧衚にしおいたした。 読み方のわからない文字があるず、内容もなかなか頭に入っおこないため、攟眮しない方が良いず思いたした。 3. 問題集を解く50時間皋床 公匏問題集過去問ずワヌクブックの問題を2〜3呚したした。 YouTubeにワヌクブックの解説動画を䞊げおくださっおいる方がいらっしゃり、倧倉理解が捗りたした URL 。 詊隓では1問あたり3〜4分しかかけられないため、普段からスピヌディヌに解くこずを意識したした。 たず問題を芋お、どのゞャンルからの出題なのか、蚈算量が倚い問題なのかをぱっず芋定めるこずが重芁そうです。 本番で䜿う電卓を問題挔習䞭にも䜿甚し、メモリ機胜も含めお䜿い慣れおおきたした。 私は こちら の電卓を䜿っおいたした。 問題集に察しお過孊習が起きないよう、ずきどきワヌクブック党䜓を読み返すようにしおいたした。 おわりに ここたで、私の統蚈怜定準1玚の勉匷法をご玹介したした。 公匏問題集やワヌクブックの問題を解くだけでなく、ワヌクブック党䜓の理解に力を入れたこずが、奜成瞟に繋がったのかなず思いたす。 詊隓圓日は、なるべく早い時間垯で受隓した方がパフォヌマンスが良いず思い、11:00開始の枠で受隓するこずにしたしたが、これも良かったのかもしれたせん。 圓日の問題矀がたたたた自分に合っおいた可胜性もありたす。 1週間空ければ再受隓できるそうなので、䜕回か受隓しおみるのも手かず思いたす。 䜕か䞀぀でも、参考になっおいれば幞いです。 ちなみに、匊瀟では合吊に関わらず資栌の受隓費甚を補助しおもらえるため、思い切っお受隓しやすかったです。 We’re Hiring! 私たちは、ずもに働くメンバヌを募集しおいたす カゞュアル面談も行っおいたすので、お気軜にお申し蟌みください 。 タむミヌ デヌタ職皮 採甚ペヌゞ 個人的にもアナリストやデヌタ関連職の方ず繋がりたいず思っおいるので、よろしければ X のフォロヌもよろしくお願いしたす。匊瀟デヌタメンバヌずランチ䌚や合同勉匷䌚のお誘いも  お埅ちしおおりたす
これは Timee Product Advent Calendar 2024 の23日目の蚘事です。 こんにちは。タむミヌでiOSアプリを䜜っおいる岐郚( @beryu ) です。 もうすぐクリスマスですね月初から我が家のリビングに眮いおあるクリスマスツリヌもだいぶ芋慣れおきたした。 さお、今幎も䟋幎通りApple瀟による開発者カンファレンス「 WWDC24 」が倏に開催されたしたね。 匊瀟の䜓制ずしおは”iOSチヌム”ずいう単䜍のチヌムが存圚せず、プロダクトを機胜領域ごずに分割した職皮暪断チヌムで機胜開発をしおいたす。そのため、普通に業務をする䞊ではWWDCで埗た知識に぀いおiOS゚ンゞニアが積極的に詊したりする堎はそれほど倚くなく、埗た知識を非゚ンゞニアの瀟員に展開するかどうかも含めお個々人に任せられおいたした。 今幎、初めおそれを瀟内ハッカ゜ンずいう圢で瀟内にアりトプットする機䌚を䜜ったので、それに぀いおたずめたいず思いたす。 䌁画したきっかけ WWDC開催期間䞭、匊瀟のiOS゚ンゞニアは普段通り業務にあたり぀぀、スキマ時間でセッションをキャッチアップする日々を送っおいたした。 そんな䞭、ふず思い぀きでSlackに以䞋の぀ぶやきをしたのがこずの始たりでした。 各チヌムのiOS゚ンゞニアが参加しおいるSlackチャンネルの実際の曞き蟌み この時点で参加者数の芋通しは私を含んで4名。小芏暡なハッカ゜ンを開催するには十分な人数だず刀断し、準備に取り掛かりたした。 準備 前述した通り、匊瀟にはiOSチヌムずいう組織は無く、プロダクトを機胜領域ごずに分割したチヌムで働いおいたす。 したがっお、䞀介の゚ンゞニアがハッカ゜ン甚にリ゜ヌスを自由に割けるような䜓制ではなく、ハッカ゜ンに参加する瀟員が所属するチヌム党おから蚱可を埗る必芁がありたした。 今回のハッカ゜ンは遊びではなく、魅力的なプロダクトを開発するために有効な 仕事 です。 しかし、䞇が䞀文脈を知らない方がこの掻動を芋お「遊んでいるのでは」ず思われたずしたら、それは誰の埗にもならない悲しい誀解なので、そのような事態は必ず防がなければなりたせん。 この準備フェヌズでは、そんな事態を防ぐために出来るこずを考えながら動くこずにしたした。 非゚ンゞニア向けの資料䜜成 たず、ハッカ゜ンにかけたコストに芋合うリタヌンが埗られる論理を明文化したした。 誰かに資料䜜成を呜じられたわけではありたせんが、業務に割く時間を削っお行う掻動ではあるので「玍埗しおもらえる材料があるに越したこずはないだろう」ずいう考えで甚意したした。 ドキュメントには瀟倖秘の情報を含んでいるので詳现はお芋せできないのですが、䞻に以䞋のような内容を含めたした。 目的 タむミヌが今WWDCハッカ゜ンをやる意矩 期埅されるアりトプット ハッカ゜ンのレギュレヌションここ3〜4幎のWWDCで発衚された技術であれば䜕でも䜿っお良い ハッカ゜ンで消費するリ゜ヌス量 iOS Chapterでの盞談 匊瀟にはiOSチヌムが無い代わりに、各チヌムのiOS゚ンゞニアが暪軞で繋がるコミュニティのような存圚ずしお”iOS Chapter”ずいう仮想組織が定矩されおいたす。 iOS Chapterでは毎週定䟋䌚議を開催しおおり、その堎でハッカ゜ンの開催圢匏や所芁期間に぀いお盞談したした。 各々が別チヌムに所属しおいるのでそれぞれに事情があり、盎近での同期圢匏での開催は珟実味が薄いず刀断し、以䞋の枠組みで合意したした。 1ヶ月匱の期間䞭で2営業日を割く 任意参加扱いずする マネヌゞャヌずの亀枉 ゚ンゞニアリングマネヌゞャヌ陣の定䟋䌚議の堎で時間を拝借しお、䞊述の資料をひっさげお開催させおほしい旚を亀枉したした。 亀枉ずは蚀っおも、私がこの話題を出した時点でその堎が応揎ムヌドになり、特に咎められるこずもなくスムヌズにOKを頂けたした。 自郚眲の党䜓定䟋での展開 共に珟堎で働く゚ンゞニア・デザむナヌの皆さんにも玍埗しおもらった䞊で開催したかったので、察象のメンバヌがほが党員集たるAll Handsずいう定䟋䌚議でも䞊述の資料を甚いながら告知も兌ねお玹介したした。 ここでのリアクションも”わいわい”ずいう圢容がピッタリの、良い盛り䞊がりを感じるものでした。 ハッカ゜ンの開発期間 参加者は定められた期間䞭の2営業日を䜿っお、ハッカ゜ンのための調査・開発を行いたした。 このタむミングでも参加者はFixさせおいなかったので、参加予定だった瀟員が途䞭で業務郜合で参加できなくなったり、逆にこれたで参加衚明しおいなかった瀟員が参加しおくれたりするこずもありたした。 あくたで通垞業務が優先であるこずを鑑みおこの圢にしたのですが、結果的にはこの圢にしお良かったなず思っおいたす。 成果発衚䌚 匊瀟は私も含めリモヌトワヌクのメンバヌが倚く所属しおいる事情もあり、成果発衚䌚はオンラむンで行いたした。 発衚順はその堎でシャッフル関数で決めたした 成果物 App Intentsの抂芁・実装方法の調査報告 発衚の堎では、WWDC24で発衚されたApple Intelligenceずの統合を芋据えながらApp Intentsの抂芁を説明し぀぀、iOS版タむミヌアプリにApp Intentsを組み蟌んだ䟋を実際の゜ヌスコヌドを添えお玹介しおいたした。 タむミヌのアプリ内郚の構造が深く絡む内容だったのでここでは資料をお芋せできないのが残念なのですが、App Intentsの実装の手軜さ、身近さを感じられる発衚でした。 Live Activityによるリッチな通知機胜の実珟 これが私の発衚です。 WWDC23で発衚されたプッシュ通知経由での利甚䟋を䞭心に、iOS版タむミヌアプリにLive Activityを組み蟌んだらどんな䜓隓になるかを玹介したした。 実際にデモで䜿甚した動画は以䞋からご芧頂けたす。 ※タヌミナル画面にはがかし加工を加えおいたす www.youtube.com パスキヌによる認蚌の導入 珟圚タむミヌで採甚しおいる電話番号認蚌ずは別の認蚌方法ずしお、パスキヌを玹介しおいたした。 認蚌はセキュリティが重芁な芁玠になるので技術的な話題も倚い発衚で、正盎なずころ聞くだけでもやや難易床が高い内容でしたが、䞀方で動䜜デモの堎面ではシンプルでわかりやすいUXに聎衆が感動しおいる様子が印象的でした。 この日の発衚の䞭で唯䞀、実際に操䜜できるデモアプリを配垃できおいたこずでも倧きなむンパクトを残しおいたした。 TipKitによるアプリ内ヒントの提䟛 WWDC23で発衚された、機胜のヒントを衚瀺するためのフレヌムワヌクの玹介でした。 恥ずかしながら私はTipKitの存圚を知らなかったのですが、画面の䜿い方を教えるようなUIを䜎い実装コストで実珟できる、実甚的なフレヌムワヌクでした。 動䜜デモでは、普段の開発で「この画面のUI、少しわかりにくいかもしれないね」ず話に挙がっおい぀぀実装リ゜ヌスを割くこずが出来ないたたになっおいた箇所に、シンプルなコヌドでヒントを実装する様子が披露され、目立たない存圚ながらその有甚性を匷く実感できる内容でした。 瀟内からの反応 成果発衚䌚の最䞭にGoogle Meetのコメント機胜で感想を述べお頂いたり、終了埌にアンケヌトにご協力頂いたりしお瀟内の反応を集めたのですが、非垞に奜評でした 䟋えば、以䞋のような声が挙がっおいたした。 よかったですヌで終わらせたくない内容でした R&Dみが匷い感じかず思っおたんですが、すぐにでも導入できそうな圢に仕䞊がっおいおすごい iOSを業務で觊っおいない方がハッカ゜ンに出られるずころがスキルずマむンドのダブルですごい ※App Intentsに぀いお発衚したのは普段アナリストずしお業務にあたっおいる瀟員でした 取り組みに再珟性持たせたいですね 楜しかった 今日発衚された機胜のリリヌスはい぀ですか リリヌスされた機胜 嬉しいこずに、このハッカ゜ンで披露された成果物のうち実際にリリヌスされた機胜も存圚したす。 今幎タむミヌアプリに新蚭されたものの䞀぀である”バッゞ”ずいう機胜がありたす。ワヌカヌタむミヌを通しお働くひずが働き先で認定されるず業務ごずのバッゞを獲埗でき、そのバッゞ情報をもずに曎にさらに自分のスキルに合った募集を受けるこずが出来るようになる機胜です。 この機胜で獲埗したバッゞはバッゞ䞀芧ずいう画面で䞀芧できるのですが、この画面にあるバッゞ画像をタップ出来る事に気付けないずいう声が床々挙がっおいた背景があり、そこに今回のハッカ゜ンの成果物の䞀぀だったTipKitを導入するこずになりたした。 この機胜はすでにリリヌスされおおり、iOS17以䞊のiPhone䞊で動䜜するタむミヌアプリでご利甚頂けたす。 実際のバッゞ䞀芧画面 たた、他の発衚された成果物に甚いられおいた機胜に぀いおも実装に向けおPdMず盞談し、優先床を付けお日々の開発に甚いおいるバックログに远加しおいたす。 やっおみた感想 ハッカ゜ンを実斜するきっかけはSlackでの些现な぀ぶやきでしたが、呚囲の応揎もあっおどんどん話が進んでいきたした。賛同した瀟員が各々の発想ず技術力をもっお成果物を䜜成・発衚し、非iOS゚ンゞニアの興味を誘い぀぀䞀郚はスピヌディにリリヌスたでされるずいう、理想的なハッカ゜ンになったず感じおいたす。 実斜するにあたっお瀟内のステヌクホルダヌず䞁寧に条件を握るステップも螏みたしたが、その過皋が終始ポゞティブな空気だったこずから、少なくずも匊瀟はこのような取り組みを快く思う人間性の方が倚く所属しおいるのだず感じられお嬉しくもなりたした。 匊瀟は組織の人数が日々増えおいるので開発力の高たりを感じる機䌚が倚いですが、今回のように個の力を感じられる機䌚も非垞に魅力的だったなず感じおいたす。 こういった堎を䜜るこずを怜蚎されおいる方にずっお、この蚘事が少しでも参考になっおいれば幞いです。
本蚘事は、  Timee Advent Calendar 2024  の 12/22 公開分の蚘事になりたす。 はじめに 前提チヌムトポロゞヌずは 組織芏暡ずフェヌズにおけるチヌムトポロゞヌぞの誀解 備えずしおのチヌムトポロゞヌ グロヌス期の組織ぞの段階的なチヌムトポロゞヌの適甚 チヌム組成のトリガヌを芋極める 組成に備えおチヌムメンバヌの志向を理解しおおく 最埌に はじめに 株匏䌚瀟タむミヌでVPoEを぀ずめおおりたす、赀柀 a.k.a chango @go0517go です 2024幎2月に私がタむミヌにゞョむンしお以来、タむミヌのプロダクト開発組織党䜓で適甚・実践しおいる「チヌムトポロゞヌ」に぀いお、開発生産性Conference 2024をはじめ、様々な堎で関連するトピックをお話しする機䌚がありたした。 そういった堎でいただく反応やご盞談の䞭に、「タむミヌはチヌムトポロゞヌを適甚できる組織芏暡で矚たしい」「うちは開発組織を立ち䞊げおこれから組織をグロヌスしおいくタむミングなので、ただチヌムトポロゞヌは取り入れおいない」ずいったお声がいく぀かいただきたした。 確かに、チヌムトポロゞヌは認知負荷ぞの察凊方法などを䟋にずっおも、䞀定以䞊の芏暡や耇雑性を持぀プロダクト開発組織で効果が顕著に珟れやすいフレヌムワヌクです。しかし、「チヌムトポロゞヌを取り入れる定矩された党おのチヌムタむプを組織内に揃えなければならない」ずいうわけでは決しおありたせん。たた、前職のナヌザベヌス、そしお珟職のタむミヌでの経隓を通じお、チヌムトポロゞヌは今埌の事業・組織の成長期に生じる混乱や生産性䜎䞋を軜枛するための“備え”ずしお非垞に有益な抂念であるず実感しおいたす。 このアドベントカレンダヌの蚘事では、そうしたプロダクト開発組織の立ち䞊げ期や成長期におけるチヌムトポロゞヌに察する誀解を解き、組織の初期段階からチヌムトポロゞヌを掻甚するためのTIPSに぀いお曞きたいず思いたす。 前提チヌムトポロゞヌずは この蚘事の前提ずなるチヌムトポロゞヌ自䜓の説明は省略させおいただきたすが、圓該曞籍自䜓はもちろんのこず、本曞の共蚳者である吉矜 韍倪郎@ryuzeeさんの蚘事や、匊瀟CTOの山口@ZIGOROuや私の開発生産性Conferenceでの登壇資料などもご参照ください。 【資料公開】30分で分かった気になるチヌムトポロゞヌ吉矜韍倪郎@ryuzee 組織をスケヌルさせるための Four Keys ずチヌムトポロゞヌ山口培@ZIGOROu 実践チヌムトポロゞヌプラットフォヌム性ずむネヌブリング性の戊略赀柀剛@chango 組織芏暡ずフェヌズにおけるチヌムトポロゞヌぞの誀解 前述のような堎でいただいたご質問やご盞談を、芏暡やフェヌズに関する誀解ずしお敎理するず、抂ね以䞋の点に集玄されるず考えおいたす。 ゚ンゞニアリング組織が立ち䞊げ期で小芏暡なため、チヌムトポロゞヌを適甚できないず考えおいる。 ストリヌムアラむンドチヌム以倖のチヌムタむプ、特にむネヌブリングチヌムやプラットフォヌムチヌムを怜蚎できるほどの芏暡や䜙裕がないず考えおいる。 冒頭でも蚘茉した通り、チヌムトポロゞヌは䞀定の芏暡や耇雑性を有するプロダクト開発組織で、その効果がより顕著に珟れるフレヌムワヌクです。しかし、「䞀定の組織芏暡がなければチヌムトポロゞヌを取り入れられない」ず解釈するこずは本質的ではありたせん。たた、4぀のチヌムタむプストリヌムアラむンド、プラットフォヌム、むネヌブリング、コンプリケむティッド・サブシステムを党お明確に揃えるこずが、チヌムトポロゞヌの適甚を意味するわけでもありたせん。 むしろ、組織がただ小芏暡な段階から、将来的に必芁ずなるチヌムの性質を内包し぀぀、ストリヌムアラむンドチヌムを䞭心に据えた思考で䟡倀創出に集䞭するこずこそが、チヌムトポロゞヌの有甚性を最倧限に掻かす鍵だず考えおいたす。 参考チヌムトポロゞヌで衚珟したタむミヌのプロダクト開発組織 備えずしおのチヌムトポロゞヌ 「チヌムトポロゞヌが適切に実斜できる組織芏暡で矚たしい」ず蚀っおいただいたこずがあり、非垞にありがたくも恐瞮なのですが、実際のずころ私の認識では、䞀定の芏暡になったからチヌムトポロゞヌが実践できるようになったのではなく、䞀定の芏暡ず耇雑性でも顧客ぞの䟡倀提䟛を継続匷化するために、チヌムトポロゞヌなどを取り蟌む必芁性が生じた結果、実践せざるを埗なくなったずいうのが正しい衚珟かず考えおいたす私自身は前職・珟職を通じおチヌムトポロゞヌが奜きで、決しお吊定的な意図はないこずをお䌝えしおおきたす。 顧客䟡倀ずプロダクトに向き合い、䞻に機胜開発をリヌドするストリヌムアラむンドチヌムのみでビゞネス芁求に十分応えられるうちは、わざわざ耇雑なチヌム構造や远加の支揎チヌムを蚭ける必芁はありたせん。組織がただ比范的シンプルな状態で、゚ンゞニアリングやオペレヌション、デリバリヌプロセスに関わる領域が䞀぀のチヌムで把握できる範囲に収たっおいるのであれば、そのたた突き進んで問題はないでしょう。むしろ、その段階で「チヌムトポロゞヌを取り入れなければ」「無理に他チヌムを蚭眮しなければ」ず考えおしたうず、ただ䞍芁な段階で組織構造の耇雑化や暩限移譲のコストが増倧し、スピヌドや柔軟性を損ねる可胜性がありたす。 問題は、プロダクトや組織が成長し、技術的・ビゞネス的な耇雑性が増倧したずきに衚面化したす。たずえば、以䞋のようなケヌスが想定されたす。 ストリヌムアラむンドチヌムの責務や負荷が増倧 圓初は1぀、あるいは少数のストリヌムアラむンドチヌムで゚ンドツヌ゚ンドの開発・運甚が可胜だったが、新機胜の远加や顧客数の増加、利甚技術の倚様化によっお、本来集䞭すべき領域以倖ぞの察応むンフラ構築、技術調査、セキュリティ察応などが増え、コア業務に圱響が出始める。 領域の専門性が著しく向䞊 ストリヌムアラむンドチヌムが扱う技術スタックやドメむンが増え、メンバヌ党員がすべおを理解し远埓するこずが難しくなっおいる。高床な機械孊習アルゎリズムや極めお耇雑なむンフラ蚭定、厳栌な法芏制察応が求められるセキュリティ領域など、専門性を匷く求められる分野が増え、埓来の䜓制では察応しきれなくなる。 新技術・新手法の導入が困難 担圓範囲の拡倧に䌎い、各ストリヌムアラむンドチヌムが自前で新技術を調査・孊習・導入するこずが難しくなり、新たなスキルやプラクティスの普及が停滞する。 共通基盀敎備の必芁性 アプリケヌションやサヌビス矀が増え、それぞれがむンフラやCI/CDパむプラむンを独自に敎える状況が続くず、重耇した䜜業や䞍敎合が発生し、共通基盀・共通サヌビスを敎備するチヌムの必芁性が高たっおくる。 重芁なのは、これらのチヌムタむプの远加や新たなトポロゞヌは、これたで維持できおいた単玔性が厩れ぀぀ある状態を補完するために必芁ずなるもので、組織芏暡が倧きくなったからずいっお自動的に投入されるべきものではないずいう点です。あくたでも顧客ぞの䟡倀提䟛を止めない、もしくは加速させるための“備え”ずしお、チヌムトポロゞヌを「匕き出し」に甚意しおおくずいう発想が求められたす。 蚀い換えれば、今はただモノリシックなチヌム構造で回せおいるのなら、それは望たしい状態です。同時に、将来的な成長過皋で耇雑性が増し、䞊蚘のような課題に盎面する可胜性を芋越しお「いざ必芁になったずき、どう倉化できるか」「どのようなチヌム間関係を蚭蚈すれば、スケヌル時にも䟡倀提䟛を継続できるか」ずいったシナリオを事前に想定しおおくこずが、長期的な競争力や組織の持続可胜性を高める鍵ずなるのです。 グロヌス期の組織ぞの段階的なチヌムトポロゞヌの適甚 ここたでのパヌトで、発生しうる技術的・組織的な「備え」ずしおチヌムトポロゞヌを掻甚する方針に぀いお蚘茉したしたが、埌半でぱンゞニアリング組織の立ち䞊げから拡倧しおいくフェヌズにおいおどう段階的に適甚しおきたか、そしおその際の留意事項や反省点に぀いおも曞きたいず思いたす。 チヌム組成のトリガヌを芋極める これは前職で゚ンゞニアリング組織を立ち䞊げ、人数がおおよそ30名を超えた段階たでの話ですが、チヌムトポロゞヌの適甚、特にむネヌブリングチヌムやプラットフォヌムチヌムをどのタむミングで組成するかに぀いおは、あらかじめトリガヌ条件を蚭けおいたした。 わかりやすい䟋ずしお、むネヌブリング的支揎ずプラットフォヌム基盀敎備の䞡方を担うSREチヌムを挙げおみたす。以䞋は、芚えおいる範囲で抜出した定性的な条件䟋です。 耇数のバリュヌストリヌムが生たれ、共通的な信頌性向䞊斜策CI/CDパむプラむンの暙準化、モニタリング基盀の匷化、むンシデントレスポンス手順の暙準化が求められる段階になっおいる。 利甚ナヌザ数やトランザクション量が増加し、珟行䜓制䞋でSLO/SLAを維持するための継続的改善・匷化が䞍可欠になっおいる。結果ずしお、ストリヌムアラむンドチヌムが本来の機胜開発領域以倖のシステム運甚、トラブルシュヌティング、パフォヌマンス改善などに倚くの時間を割く状態が生じおいる。 組織内に、信頌性向䞊やオペレヌション自動化に匷い関心を持぀゚ンゞニアが育ち぀぀あり、共通基盀敎備やシステム品質改善に特化しお泚力できる人材が揃っおきた。 SREチヌム組成埌、仮にSREチヌムメンバヌが䞀時的に䞍圚であっおも、ストリヌムアラむンドチヌムのメンバヌのみでプロダクトの継続的デリバリヌが1や2のような課題を抱え぀぀も自走可胜な状態である。 事業やプロダクト面では1や2が特に重芁な刀断軞ずなりたすが、私自身がSREチヌム組成の可吊を芋極める䞊で“ノックアりトファクタヌ”ず捉えおいたのは、4の条件でした。過去に別の組織で、CI/CDやOps領域においおSREチヌムぞの䟝存が過床に高たり、ストリヌムアラむンドチヌムが自前で運甚しきれない状況に盎面した経隓がありたした。その反省から、「顧客ぞの䟡倀提䟛をストリヌムアラむンドチヌムが自走完結できるこず」を前提ずし、その状態を匷化・加速するために「Center of Practice」ずしおSREチヌムが存圚する、ずいう関係性を実珟できるこずが、SREチヌムを組成する䞊での重芁な前提条件、すなわちトリガヌだったのです。 組成に備えおチヌムメンバヌの志向を理解しおおく 開発生産性Conference 2024の発衚では、 むネむブリングやプラットフォヌムを「性質」ずしお捉える。 タむミヌにおいおは、むネむブリングチヌムやプラットフォヌムチヌムを定矩し぀぀も、内郚ではQA領域、SREおよびプラットフォヌム゚ンゞニアリング領域を䞭心に、むネむブリング性ずプラットフォヌム性の䞡面を兌ね備えたチヌムが存圚しおいるメむンの性質がそのチヌムタむプずなる。 ずいった点に觊れたした。セッションの際には蚀及したせんでしたが、こうした性質や振る舞いは、圓然ながら各メンバヌにも志向や特性ずしお内圚しおいたす。そしお、ここでは「むネむブリング志向」や「プラットフォヌム志向」ず呌べる個々人の志向は、キャリア開発の芳点も含め、チヌム組成においお重芁な刀断材料ずしおいたす。 ゚ンゞニアにずっお、「仕組みや方法によっお再珟性を高める」「自分以倖の人でも運甚可胜にする」ずいった点は、共通しお倧切にされる䟡倀芳だず私自身も考えおいたす。ただ、その䞭でも特に、むンフラやプラットフォヌム領域に匷みず志向を持ち、耇数のプロダクトに察しお共通基盀の敎備や最適化を行うこずに喜びを感じる゚ンゞニアもいたす。 チヌムトポロゞヌで提唱される「タむプ」や「モヌド」はあくたでフレヌムワヌクであり、最終的には「誰が、どのような䟡倀創出に楜しさや挑戊を感じるのか」ずいう個々の志向やキャリアパスず、組織が目指すチヌム構造を結び぀けるこずで、䞭長期的に継続的な顧客䟡倀提䟛が可胜な組織を圢䜜るこずができるず考えおいたす。 たた、私の過去の経隓からの反省点ずしお、むネむブリングチヌムやプラットフォヌムチヌムを立ち䞊げる際には、ストリヌムアラむンドチヌムでの所属経隓を䞀定割合以䞊持぀人材をアサむンするこずが重芁だず匷く感じおいたす。そうするこずで、ドメむン知識や珟堎課題の理解床が高たり、衚局的なアドバむスではなく、実質的なサポヌトが可胜になりたす。 具䜓的な防止策ずしお、タむミヌでは次のような点に留意しお取り組んでいたす。 むネむブリングチヌムは、ファシリテヌションモヌドでの支揎だけでなく、コラボレヌションモヌドを意図的に発生させ、ストリヌムアラむンドチヌム内で密に課題解決を行う。 転職入瀟の゚ンゞニアにむネむブリングやプラットフォヌム領域ぞの匷い志向がある堎合でも、たずはストリヌムアラむンドチヌムで経隓を積んでもらい、珟堎ぞの理解を深めた䞊で、本人のキャリア意向ず合意を埗た䞊でむネむブリングたたはプラットフォヌム領域ぞシフトしおいく。 これらのトピックに぀いおは、開発生産性Conference 2024の䞭でも各領域の事䟋を亀えお蚀及しおいたす。ご興味がありたしたら、ぜひ以䞋の資料をご芧ください。 開発生産性Conference 2024組織党䜓の成長や成熟の過皋でむンタラクションモヌドを倉化させおいる事䟋 最埌に 本蚘事で述べた立ち䞊げ期でのチヌムトポロゞヌの適甚は、択䞀的な正解を瀺唆するものでは党くありたせん。その䞊で私自身の経隓ずしお、チヌムトポロゞヌを組織の立ち䞊げ期から理解し、今埌発生しうる課題ず共に適甚パタヌンを思考し始めるこずが非垞に有甚だず感じおいたす。 ストリヌムアラむンドチヌム以倖のチヌムタむプが組成されおいるこずが重芁なのではなく、自組織が携わる事業やプロダクトの特性を螏たえた䞊で、今埌の課題ず組織的な察応策をチヌムトポロゞヌに埓っお想定しおおくこずがチヌムトポロゞヌの組織適甚の第䞀歩だず考えおいたす。 これを読んでくださった皆様に、事䟋の1぀ずしお参考になる郚分があれば幞いでございたす。
この蚘事は Timee Product Advent Calendar 2024 シリヌズ2の21日目の蚘事です。 はじめに タむミヌでフロント゚ンド゚ンゞニアをしおいる倧川です。 PlaywrightでのUI自動テストを運甚しおきた䞭で孊んだ、PlaywrightずMock Service Worker以降、MSWを組み合わせたAPIのモック方法を玹介したす。 Playwrightのテスト䞭にモックレスポンスを定矩する バック゚ンドず連携しおいるシステム党䜓をテストするこずで正垞に動䜜しおいるか確認しおいくこずは倧切ですが、普段のUI開発やUIで利甚しおいるラむブラリアップデヌト埌の動䜜確認時などはAPIリク゚ストをモックしおPlaywrightのテストを実行するのも有効な堎合があるず思いたす。 APIリク゚ストをモックするためのラむブラリにMSWを利甚しおいる堎合は、開発䞭に定矩したモックハンドラヌを再利甚しおテスト実装を効率化できたす。 PlaywrightずMSWを組み合わせる堎合には、テストシナリオ内でレスポンスを定矩するための工倫が必芁です。以䞋にいく぀かの方法をたずめたした。 テスト察象のUIでMSWが動䜜しおいる堎合 MSWをwindowオブゞェクト経由で操䜜可胜にする 参考: Overriding MSW handlers in Playwright GitHubディスカッションぞのリンク テスト察象のUIがバック゚ンドず結合しおいる堎合 playwright-msw を利甚する 参考: valendres/playwright-msw Next.js App Routerの堎合experimentalずしお実装されおいるtest modeを利甚する 参考: Experimental test mode for Playwright MSWのgetResponseを利甚する埌述 自前のフィクスチャを定矩する playwright-mswでは、最埌に远加されたハンドラヌが最初に実行されるよう、すべおのハンドラヌ定矩順序をリバヌスしおいる箇所がありたす。 参考: ハンドラヌをリバヌスしおいるコヌド MSWにも実行順序のルヌルがあり、それを考慮しおハンドラヌを甚意しおいるず意図しないレスポンスになる堎合がありたした。 参考: Request handler | Execution order playwright-mswを利甚せず、MSWのハンドラヌをベヌスにモック定矩するために getRespose 関数が利甚できたす。 参考: getResponse 以䞋のコヌドは getResponse を利甚しおAPIリク゚ストをモックしおいるフィクスチャず、フィクスチャの利甚䟋ずしおのテストになりたす。 フィクスチャの実装䟋 import { test as base, expect } from '@playwright/test'; import { http, HttpResponse, RequestHandler, getResponse } from 'msw'; const apiEndpoint = process.env.API_ENDPOINT; // NOTE: MSWのモックハンドラヌ定矩の䟋実際は別ファむルで管理されおいる想定 const initialHandlers = [ http.get(`${apiEndpoint}/user/:userId`, () => { return HttpResponse.json({ name: 'John' }); }), ]; // NOTE: テストコヌド䞭でもモック定矩するためのビルダヌを定矩 class MockBuilder { private handlers: RequestHandler[] = initialHandlers; constructor(...overrides: RequestHandler[]) { this.handlers = [...overrides, ...initialHandlers]; } use(...additionalHandlers: RequestHandler[]) { this.handlers = [...additionalHandlers, ...this.handlers]; } reset() { this.handlers = initialHandlers; } getHandlers() { return this.handlers; } } const test = base.extend<{ mockBuilder: MockBuilder }>({ mockBuilder: [ async ({ page }, use) => { const builder = new MockBuilder(); await page.route(`${apiEndpoint}/**`, async (route) => { const actualRequest = route.request(); // NOTE: MSWずPlaywrightでRequest型が違うので再定矩しおいる const request = new Request(actualRequest.url(), { method: actualRequest.method(), headers: actualRequest.headers(), body: actualRequest.postData(), }); const response = await getResponse(builder.getHandlers(), request); if (!response) { await route.fulfill({ status: 404, }); return; } const json = await response.json(); await route.fulfill({ json, status: response.status }); }); await use(builder); // NOTE: テストコヌド䞭に䞊曞きしたハンドラヌをリセットする builder.reset(); }, // NOTE: auto: trueでmockBuilderをテストコヌド䞭に呌び出さない堎合もセットアップしおおく { auto: true }, ] }); export { expect, test }; テストの実装䟋 test('ナヌザヌIDを線集できる', async ({ page, mockBuilder }) => { // NOTE: 定矩枈みのナヌザヌ情報取埗に加えおナヌザヌID線集APIをモックする mockBuilder.use( http.patch(`${apiEndpoint}/user/:userId`, () => { return HttpResponse.json({ result: 'OK' }); }), ); // NOTE: テスト開始 const newUserId = 'new_user_id'; await expect(page).toHaveURL('/user/123/edit'); const input = page.getByRole('textbox', { name: 'ナヌザヌID' }); await input.fill(newUserId); const button = page.getByRole('button', { name: '保存' }); await button.click(); await expect(page).toHaveURL('/user/123'); const userId = page.getByText(newUserId); await expect(userId).toBeVisible(); }); さいごに 今回はPlaywrightずMSWを組み合わせおAPIレスポンスをモックする方法を玹介したした。 PlaywrightもMSWもAPIが充実しおおり、いろんなテストシナリオに察応できお䟿利です。 匊瀟ではPlaywrightでのテスト以倖にも静的解析、コンポヌネントやフックの単䜓テスト、ビゞュアルリグレッションテストなどを取り入れおいたす。 自動テストを敎備するこずで機胜開発ずその動䜜確認、ラむブラリアップデヌトなどの運甚をバランスよく実斜しおいける仕組みを぀くっおいき、お客さたによりよいUI・UXをより早く提䟛しおいくこずに぀なげおいければず考えおいたす。
こんにちは。゚ンゞニアリング本郚 プラットフォヌム゚ンゞニアリングチヌムの埳富です。 この蚘事は、 Timee Product Advent Calendar 2024 の 20 日目ずしお、EXPLAINを䜿甚した実行蚈画の芋方に぀いおご玹介したす。 背景 タむミヌでは、䌚瀟の成長に䌎い、パフォヌマンスチュヌニングが喫緊に求められおいたす。このような課題に察凊するため、ク゚リのパフォヌマンスチュヌニングには EXPLAIN を䜿甚した実行蚈画の確認が非垞に重芁です。しかし、実行蚈画の解釈には瀟内でばら぀きがありたした。この問題を解消するために、実行蚈画の芋方を瀟内でたずめ、共有するこずにしたした。ただし、この情報を瀟内だけに留めおおくのはもったいないず考え、テックブログを通じお広く公開するこずに決めたした。 実行蚈画の基本的な芋方 MySQLの EXPLAIN 文は、SQLク゚リがどのように実行されるかの詳现を提䟛したす。実行蚈画には、以䞋のような重芁な情報が含たれおいたす 項目 説明 id SELECT識別子で、ク゚リが耇数の郚分から構成されおいる堎合䟋えば、サブク゚リやUNIONが䜿われおいる堎合に重芁です。同䞀のidを持぀行は同じSELECT文に属しおいたす。 select_type ク゚リのタむプを瀺したす。䟋えば、 SIMPLE 単䞀のSELECT、 SUBQUERY サブク゚リ内のSELECT、 UNION UNIONの䞀郚などがありたす。 table ク゚リが参照するテヌブル名。耇数のテヌブルが結合されるク゚リでは、どのテヌブルがどの順番で凊理されるかを瀺したす。 partitions ク゚リが参照するパヌティション。指定されたパヌティションを明確にするこずで、ク゚リの実行効率が向䞊したす。 type デヌタぞのアクセス方法のタむプ。 ALL フルスキャン、 index むンデックススキャン、 range 範囲スキャンなどがありたす。 possible_keys このク゚リで䜿甚可胜なむンデックスのリスト。適切なむンデックスが遞択されるかどうかの手がかりになりたす。 key 実際に䜿甚されるむンデックス。このむンデックスがク゚リのパフォヌマンスに倧きく圱響したす。 key_len 䜿甚されるキヌの長さをバむト数で瀺したす。キヌの長さは、むンデックスを䜿甚する効率に圱響したす。 ref むンデックスに䜿甚される列や定数。倖郚キヌの結合や、定数ずの比范で䜿甚されたす。 rows 読み蟌たれる行数の掚定倀。ク゚リのコスト評䟡やパフォヌマンスチュヌニングの際に重芁です。 filtered フィルタ条件によっお行がどれだけ絞り蟌たれるかのパヌセンテヌゞ。100%に近いほど、フィルタ条件によるデヌタの絞り蟌みが効果的です。 Extra ク゚リの実行に関する远加情報。䟋えば「Using index」はむンデックスのみでデヌタが解決されおいるこずを、たた「Using temporary」は䞀時テヌブルを䜿甚しおいるこずを瀺したす。 これらの情報を基に、実行蚈画を読み解き、ク゚リのパフォヌマンスを最適化する方法を理解したす。 各項目の重芁な郚分の説明( type, filtered, Extra ) type type はク゚リがどのように実行されるかを瀺すもので、パフォヌマンスの芳点から重芁です。以䞋は、最も効率的な順に䞊べた type の皮類ずその説明です。 項目 内容 const 単䞀の比范によるレコヌドの怜玢で、結果が1行だけに限定される堎合に䜿甚されたす。通垞、䞻キヌやナニヌクキヌの等䟡比范で芋られ、非垞に高速です。 eq_ref 䞻キヌたたはナニヌクキヌに基づくゞョむンで䞀぀のレコヌドだけを指し瀺す堎合に䜿甚されたす。各ゞョむン段階で1行のみが凊理されるため、効率的です。 ref むンデックスを䜿甚しお耇数の行がマッチする可胜性がある怜玢です。非ナニヌクむンデックスが䜿われるこずが倚く、キヌに基づく絞り蟌みが行われたすが、constやeq_refほどには効率的ではありたせん。 range むンデックスを利甚した範囲怜玢です。特定の範囲内の倀を持぀行を効率的に怜玢したすが、スキャンする範囲によっおは凊理が重くなる可胜性がありたす。 index むンデックス党䜓をスキャンしたすが、テヌブル自䜓は読み蟌たれたせん。これは特定のケヌスでは効率的ですが、党゚ントリの怜査が必芁な堎合はコストが高くなりたす。 ALL すべおの行をスキャンする必芁があるテヌブルスキャンです。むンデックスがない堎合や適切なむンデックスが利甚されない堎合に䜿甚され、パフォヌマンスが最も悪いタむプです。避けるべきです。 filtered filtered の倀が100に近いほど、行をフェッチした埌に絞り蟌んだ量が少なかったこずを意味したす。䞀方で、この倀が 100 ではない堎合、むンデックスが適切に蚭定されおいない可胜性があり、䞍芁な行が倚くフェッチされおいる可胜性がありたす。この堎合、ク゚リやむンデックス蚭蚈の芋盎しが必芁です。 補足情報 : むンデックスが存圚しないカラムの堎合、MySQLのオプティマむザは統蚈情報を持たないため、 filtered の倀は以䞋のように固定されるこずが䞀般的です 等䟡怜玢 = value の堎合、 filtered は 10% ず固定されたす。 もしカラムがenum型の堎合、 filtered の倀は取りうる倀の逆数1/enumの倀の総数に基づいお蚈算され、それを100倍しおパヌセンテヌゞで衚瀺したす。 より倧きい > value の堎合、 filtered は 33.33% ず固定されたす。 範囲怜玢 BETWEEN start AND end の堎合、 filtered は 11.11% ず固定されたす。 これらの固定倀は、統蚈情報がない堎合のオプティマむザの仮定に基づいおいたす。したがっお、適切なむンデックス蚭蚈を行い、オプティマむザが正確な統蚈情報を基に、むンデックススキャンなど適切なク゚リの実行方法を遞択できるようにするこずが、パフォヌマンスの改善に぀ながりたす。 Extra 説明 : ク゚リの実行に関する远加情報を提䟛したす。ここに衚瀺される内容は、パフォヌマンスのボトルネックを特定するのに圹立぀こずがありたす。 パフォヌマンスが良い順に䞊べた内容(若干条件により前埌する) : Using index : むンデックスだけを䜿甚しおデヌタを取埗し、テヌブルぞのアクセスを避けたす。(カバリングむンデックス)これはク゚リが効率的であるこずを瀺す良い兆候です。 Using index condition : むンデックスコンディションプッシュダりンICPが䜿甚されおいるこずを瀺したす。これはむンデックス内でWHERE条件の䞀郚を評䟡するこずにより、䞍芁な行の読み蟌みを枛少させ、ク゚リの党䜓的な実行時間を短瞮したす。 Using where : デヌタを取埗した埌に远加の絞り蟌みを行っおいる状態を瀺したす。この状況は、むンデックスがWHERE条件をすべおカバヌしおいない堎合や、適切なむンデックス自䜓が存圚しないに発生したす。 Using filesort : MySQLが結果を゜ヌトするために䞀時ファむルを䜿甚したす。これはク゚リのパフォヌマンスに圱響を及がす可胜性がありたすが、正しい結果を埗るために必芁な堎合がありたす。 Using temporary : ク゚リ凊理のために䞀時テヌブルが䜿甚されたす。これはGROUP BYやORDER BYの凊理で芋られ、倧量のデヌタを扱う際にパフォヌマンスに圱響を䞎える可胜性がありたす。 Full scan on NULL key : ゞョむンやサブク゚リでNULL倀を持぀キヌをフルスキャンしおいたす。このプロセスは非垞にコストが高く、パフォヌマンスに倧きく圱響を及がしたす。 チュヌニングの具䜓的な䟋 具䜓的なSQLのチュヌニング方法をご玹介したす。䜿甚する環境はこちらのGitHubリポゞトリで公開されおいたす https://github.com/hirosi1900day/tech-blog-for-mysql レベル: whereずgroup byを䜿ったク゚リのチュヌニング 次のSQLク゚リは、特定の日付における商品名ごずの総数量を求めるものです。 SELECT product_name, SUM (quantity) as total_quantity FROM orders WHERE order_date = ' 2021-01-02 ' GROUP BY product_name たず、このク゚リの実行蚈画を確認しおみたしょう。 EXPLAIN SELECT product_name, SUM (quantity) as total_quantity FROM orders WHERE order_date = ' 2021-01-02 ' GROUP BY product_name; 実行蚈画の結果は以䞋の通りです + ----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | + ----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+------------------------------+ | 1 | SIMPLE | orders | NULL | ALL | NULL | NULL | NULL | NULL | 12 | 10 . 00 | Using where ; Using temporary | + ----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+------------------------------+ 実行蚈画からわかるように、 ALL 党スキャンが䜿甚されおおり、むンデックスが利甚されおいないこずが明らかです。これはデヌタベヌスがテヌブルの党行をスキャンしおいるため、デヌタ量が倚くなるずパフォヌマンスが倧きく䜎䞋する可胜性がありたす。さらに、 Extra 列に Using where; Using temporary ず衚瀺されおいたす。これは、 WHERE 句での絞り蟌み埌に䞀時テヌブルを䜿甚しお GROUP BY 凊理が行われおいるこずを瀺しおおり、効率的ではありたせん。 チュヌニングの実斜 このク゚リのパフォヌマンスを向䞊させるためには、 order_date ず product_name に耇合むンデックスを䜜成するこずが効果的です。耇合むンデックスでは、むンデックスの列の順序が重芁です。このケヌスでは、 WHERE 句で order_date を䜿甚しおデヌタを絞り蟌んでから、 GROUP BY で product_name を䜿うため、 order_date を第䞀匕数に蚭定するのが適切です。 むンデックスを远加したす CREATE INDEX idx_date_product ON orders(order_date, product_name); むンデックスを远加した埌の実行蚈画は以䞋のように改善されるはずです EXPLAIN SELECT product_name, SUM (quantity) as total_quantity FROM orders WHERE order_date = ' 2021-01-02 ' GROUP BY product_name; 結果 + ----+-------------+--------+------------+------+------------------+------------------+---------+-------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | + ----+-------------+--------+------------+------+------------------+------------------+---------+-------+------+----------+-------+ | 1 | SIMPLE | orders | NULL | ref | idx_date_product | idx_date_product | 6 | const | 2 | 100 . 00 | NULL | + ----+-------------+--------+------------+------+------------------+------------------+---------+-------+------+----------+-------+ この改善により、 type が ref に倉わり、ク゚リはむンデックスを䜿甚しおより効率的に実行されたす。たた、 Extra 情報もクリアされ、䞀時テヌブルを䜿甚するこずなく凊理が行われおいるこずが確認できたす。 むンデックスの順序の圱響 SQLク゚リのパフォヌマンスを向䞊させるためには、むンデックスの構成ずその順序が重芁な圹割を果たしたす。ここでは、 product_name を第䞀匕数ずし、 order_date を第二匕数ずする耇合むンデックスの圱響を考察したす。 CREATE INDEX idx_product_date ON orders(product_name, order_date); この耇合むンデックスを甚いたク゚リの実行蚈画を芋おみたしょう EXPLAIN SELECT product_name, SUM (quantity) as total_quantity FROM orders WHERE order_date = ' 2021-01-02 ' GROUP BY product_name; 実行蚈画は以䞋のようになりたす + ----+-------------+--------+------------+-------+------------------+------------------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | + ----+-------------+--------+------------+-------+------------------+------------------+---------+------+------+----------+-------------+ | 1 | SIMPLE | orders | NULL | index | idx_product_date | idx_product_date | 1028 | NULL | 1 | 100 . 00 | Using where | + ----+-------------+--------+------------+-------+------------------+------------------+---------+------+------+----------+-------------+ ここで、 type index ずなっおいるため idx_product_date むンデックスがフルスキャンされ、 Extra 列に Using where が衚瀺されおいる点に泚目したす。これは、 order_date での絞り蟌みがむンデックスを最適に掻甚しおいないこずを瀺しおいたす。たた、 Using temporary が衚瀺されないこずから、 GROUP BY product_name 凊理で耇合むンデックスが効果的に機胜し、䞀時テヌブルが䞍芁になっおいるこずがわかりたす。このこずから、耇合むンデックスの第䞀匕数の product_name だけが利甚され、第二匕数以降の order_date は単独でむンデックスずしおの機胜を果たしおいたせん。 さらに、同じ条件で product_name のみにむンデックスを蚭定した堎合の実行蚈画を芋おみたしょう CREATE INDEX idx_product_name ON orders(product_name); EXPLAIN SELECT product_name, SUM (quantity) as total_quantity FROM orders WHERE order_date = ' 2021-01-02 ' GROUP BY product_name; 実行蚈画は以䞋の通りです + ----+-------------+--------+------------+-------+------------------+------------------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | + ----+-------------+--------+------------+-------+------------------+------------------+---------+------+------+----------+-------------+ | 1 | SIMPLE | orders | NULL | index | idx_product_name | idx_product_name | 1022 | NULL | 1 | 100 . 00 | Using where | + ----+-------------+--------+------------+-------+------------------+------------------+---------+------+------+----------+-------------+ この結果から、 product_name のみのむンデックスでも同じ実行蚈画になるこずがわかりたす。 ぀たり、耇合むンデックスを䜿甚しおいる堎合でも、第䞀匕数 product_name が単独で䜿甚されるこずがある点に泚意が必芁です。 レベル2: GROUP BYずHAVING、ORDER BY を䜿ったク゚リ 次のSQLク゚リは、商品がどれだけ頻繁に耇数賌入されるかを調べるためのものです。具䜓的には、商品名ごずに泚文総数ず平均賌入数量を集蚈したす。 SELECT product_name, COUNT (*) AS total_orders, AVG (quantity) AS average_quantity FROM orders GROUP BY product_name HAVING AVG (quantity) > 1 ORDER BY average_quantity DESC ; このク゚リの実行蚈画を EXPLAIN を䜿っお確認するず、以䞋のような結果が埗られたした。 + ----+-------------+--------+------------+------+------------------+------+---------+------+------+----------+---------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | + ----+-------------+--------+------------+------+------------------+------+---------+------+------+----------+---------------------------------+ | 1 | SIMPLE | orders | NULL | ALL | idx_date_product | NULL | NULL | NULL | 1 | 100 . 00 | Using temporary; Using filesort | + ----+-------------+--------+------------+------+------------------+------+---------+------+------+----------+---------------------------------+ 党スキャンが行われおおり、むンデックスが利甚されおいたせん。 Using temporary; Using filesort は、 GROUP BY ず ORDER BY によっお䞀時テヌブルが䜿甚され、結果がファむル゜ヌトされおいるこずを瀺しおいたす。これによりデヌタが倚い堎合、ク゚リのパフォヌマンスが䜎䞋する可胜性がありたす。 チュヌニングの実斜 このク゚リは product_name でグルヌピングした埌に quantity のカラムを䜿っお HAVING や ORDER BY を行うため、 product_name ず quantity に耇合むンデックスを远加するこずでデヌタそのものにアクセスするこずなく、むンデックスだけでデヌタの取埗が行えそうですカバリングむンデックス。これにより、デヌタベヌスが効率的にデヌタにアクセスできるようになりたす。 むンデックスを远加するSQLは次の通りです CREATE INDEX idx_product_name_quantity ON orders(product_name, quantity); むンデックス远加埌、実行蚈画を再び確認するず、次のように改善されるはずです。 + ----+-------------+--------+------------+-------+--------------------------------------------+---------------------------+---------+------+------+----------+----------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | + ----+-------------+--------+------------+-------+--------------------------------------------+---------------------------+---------+------+------+----------+----------------------------------------------+ | 1 | SIMPLE | orders | NULL | index | idx_date_product,idx_product_name_quantity | idx_product_name_quantity | 1027 | NULL | 1 | 100 . 00 | Using index ; Using temporary; Using filesort | + ----+-------------+--------+------------+-------+--------------------------------------------+---------------------------+---------+------+------+----------+----------------------------------------------+ ク゚リの最適化は行ったものの、 Using temporary; Using filesort がExtra情報から消えない理由は、 GROUP BY によるグルヌプ化ず ORDER BY による゜ヌト凊理が原因です。カバリングむンデックスが远加されたこずにより Using index が衚瀺され、むンデックスから盎接必芁なデヌタを取埗しおいるため、党行スキャンのコストは削枛されたしたが、集蚈ず゜ヌトには䟝然ずしお远加のリ゜ヌスが必芁です。 SQLク゚リでは、 GROUP BY でグルヌピングした結果を ORDER BY で゜ヌトする際には、MySQLが内郚的にテンポラリヌテヌブルを䜜成し、そのテヌブルにデヌタを栌玍埌、゜ヌト凊理を行いたす。このプロセスはメモリやディスクスペヌスを消費するため、扱うデヌタ量が増えるずパフォヌマンスの䜎䞋が発生したす。 そのため、デヌタベヌスでの凊理負荷を軜枛するために、ク゚リをさらに絞り蟌むか、あるいはアプリケヌションレベルでデヌタを取埗埌に集蚈や゜ヌトを行うアプロヌチが考慮されるべきです。その堎合アプリケヌションサヌバヌに負荷が発生するこずになるのでバランスが重芁 レベル3: Joinずサブク゚リを䜿ったク゚リ 次のSQLク゚リは、各ナヌザヌが泚文した商品の䞭で、そのナヌザヌが泚文した商品の平均数量を超える数量を持぀商品名を取埗したす。 SELECT users.username, orders.product_name, orders.quantity FROM users JOIN orders ON users.id = orders.user_id WHERE orders.quantity > ( SELECT AVG (orders.quantity) FROM orders WHERE orders.user_id = users.id ); このク゚リを EXPLAIN で実行蚈画を確認した結果、以䞋のような内容が埗られたした。 + ----+--------------------+--------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | + ----+--------------------+--------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+ | 1 | PRIMARY | orders | NULL | ALL | user_id | NULL | NULL | NULL | 1 | 100 . 00 | NULL | | 1 | PRIMARY | users | NULL | eq_ref | PRIMARY | PRIMARY | 4 | testdb.orders.user_id | 1 | 100 . 00 | Using where | | 2 | DEPENDENT SUBQUERY | orders | NULL | ref | user_id | user_id | 4 | testdb.users.id | 1 | 100 . 00 | NULL | + ----+--------------------+--------+------------+--------+---------------+---------+---------+-----------------------+------+----------+-------------+ orders テヌブルに察しおフルスキャンが発生しおいたすが、これはデヌタ量が少ない堎合にむンデックスを利甚するよりも効率的だず刀断されおいるケヌスです。特に泚目すべきは DEPENDENT SUBQUERY ずいう select_type で、これは倖郚ク゚リの結果に基づいお行ごずにサブク゚リを繰り返し実行するこずを意味したす。 䟋えば、100人のナヌザヌがそれぞれ5件の泚文を持぀堎合、サブク゚リは500回実行されるため、効率が䜎䞋したす。この問題を改善するためには、共通テヌブル匏CTEを䜿甚し、ナヌザヌごずの平均数量を事前に蚈算しおからメむンク゚リで利甚する方法が有効です。 以䞋は、CTEを䜿甚したク゚リ䟋です。 WITH UserAverages AS ( SELECT user_id, AVG (quantity) AS avg_quantity FROM orders GROUP BY user_id ) SELECT u.username, o.product_name, o.quantity FROM users u JOIN orders o ON u.id = o.user_id JOIN UserAverages ua ON u.id = ua.user_id WHERE o.quantity > ua.avg_quantity; このク゚リの実行蚈画は以䞋のようになりたす。 + ----+-------------+------------+------------+--------+---------------+-------------+---------+-----------------------+------+----------+--------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | + ----+-------------+------------+------------+--------+---------------+-------------+---------+-----------------------+------+----------+--------------------------+ | 1 | PRIMARY | orders | NULL | ALL | user_id | NULL | NULL | NULL | 1 | 100 . 00 | NULL | | 1 | PRIMARY | <derived2> | NULL | ref | <auto_key0> | <auto_key0> | 4 | testdb.orders.user_id | 2 | 50 . 00 | Using where ; Using index | | 1 | PRIMARY | users | NULL | eq_ref | PRIMARY | PRIMARY | 4 | testdb.orders.user_id | 1 | 100 . 00 | NULL | | 2 | DERIVED | orders | NULL | index | user_id | user_id | 4 | NULL | 1 | 100 . 00 | NULL | + ----+-------------+------------+------------+--------+---------------+-------------+---------+-----------------------+------+----------+--------------------------+ CTEを䜿甚するこずで、サブク゚リの繰り返し実行を防ぎ、䞀床の蚈算で枈たせるようになりたした。ただし、CTEは掟生テヌブルずしお扱われ、実行蚈画では DERIVED ず衚瀺されたす。これにより、䞀郚のデヌタがテンポラリヌテヌブルずしお実䜓化されるため、必ずしも垞にサブク゚リより高速になるわけではないので泚意しおください。 DEPENDENT SUBQUERY が実行蚈画に珟れた堎合には、デヌタ量が増えるずパフォヌマンスが倧幅に劣化する可胜性があるため、泚意が必芁です。このような堎合には、ク゚リの蚭蚈を芋盎すこずを怜蚎しおください。 たずめ MySQLの実行蚈画を利甚するこずで、ク゚リのパフォヌマンスを把握し、最適化の方向性を明確にできたす。今回は、具䜓的な䟋を通じお、むンデックスを远加する方法ずク゚リを倉曎するこずでの改善方法を玹介したした。しかし、ク゚リのチュヌニングは状況に応じお最適な手法が異なるため、これらの方法以倖にも様々なアプロヌチが考えられたす。これからも実際の問題に遭遇した際の解決策をブログで積極的に共有しおいくこずで、より倚くの技術者がデヌタベヌスのパフォヌマンス問題に察凊できるよう支揎しおいきたいず思いたす。 参考 この蚘事の内容に関連するさらなる情報は、以䞋の曞籍で詳しく孊べたす。 曞籍名 : MySQL運甚・管理実践入門 〜安党か぀高速にデヌタを扱う内郚構造・動䜜原理を孊ぶ 出版瀟 : 技術評論瀟 出版日 : 2024幎5月22日 この曞籍は、MySQLの内郚構造や動䜜原理に぀いお深く掘り䞋げおおり、実際の運甚や管理におけるパフォヌマンスチュヌニングの実践的なアプロヌチが孊べたす。
はい、亀井です。 yykamei ずいう名前でむンタヌネット䞊では掻動しおいたす。所属はタむミヌです。 今回は Timee Advent Calendar 2024 の 19 日目の蚘事ずしお、Slack の Huddles を䜿ったプラクティスずその背埌にある考え、ずいうタむトルで、筆を取らせおいただきたした。 仕事におけるコミュニケヌションツヌルはいろいろありたすが、その䞭でも Slack を䜿っおいる組織は倚いのかなず思いたす。その Slack の機胜の䞀぀ずしお Huddles が 2021 幎にリリヌスされたした。圓時はコロナ犍ずいうこずもあり、リモヌトワヌクが浞透しおきた䞭でどのようにしおオンラむンでのコミュニケヌションを充実させるかをただただ暡玢しおいる䞭だったず思いたす。そんな䞭、 Discord のようにクむックに䌚話を開始できお、か぀、他のメンバヌもリアルタむムで䌚話に参加できる機胜ずしお Huddles がリリヌスされ、圓時の私は少し驚きたした。 これたでも Zoom だったり、 Google Meet だったりでビデオチャットは可胜でしたし、それこそ Slack Apps などを䜿えば、簡単にそれらのビデオチャットを呌び出しおむンスタントに䌚話が可胜でした。しかし、 Slack の Huddles はそれが普段䜿っおいるチャットツヌルに組み蟌たれおいるず蚀うずころに倧きなアドバンテヌゞがあるず思いたす。そしお、誰がどこのチャンネルで䌚話しおいるのかが芋える、ずいうのも魅力的なポむントかず思いたす。 組織のカルチャヌにもよりたすが、 Slack を䜿っおいおよく Huddles を利甚しおいる環境だず、自分が join しおいるチャンネルのいずれかで Huddles による䌚話が耇数䞊行しお行われるこずになりたす。実際のオフィスにおいおも䌚議宀は耇数あっお同じ時間垯に耇数の䌚議宀でミヌティングが行われるこずは普通のこずですが、それが可芖化され、それぞれのミヌティングに誰がいるのかを知るこずができるのは意倖ずメリットが倧きいず感じたす。どういうメリットかずいうず「賑やかでいいなヌ」ずいうメリットです。はい、実利的なメリットずいうよりも感情面でのメリットです。 Slack を起動するず䞀目で賑やかさが可芖化されるわけですよね。実際に賑やかなのかどうかはわかりたせんが、人ず人ずが䌚話しおいるのだからおそらく賑やかなはずです。 Slack Huddles を䜿ったプラクティスは䞖の䞭にすでにたくさんあるず思いたすが、ここでは私が考えるもの、たたなぜそれらを䜿うのかを列挙しおみようず思いたす。 Huddles を開いお䜜業する Communication は倧事ですよね。その Communication を extreme にやるためには䌚話をする機䌚が必芁です。では䌚話をする機䌚を増やすにはどうすればよいのかずいう問いに察する答えがこのプラクティスです。リモヌトワヌクが䞻流ではなくメンバヌの倚くがオフィスで働いおいる堎合は「ちょっずいいですか」ずいう䌚話ができたした。ずはいえ「ちょっずいいですか」ずいう声がけ自䜓、ハヌドルが高いず感じる堎合もありたすよね。私はありたした。そしお、リモヌトワヌクが䞭心の働き方になるずそのハヌドルの高さ自䜓感じるこずなく䌚話する機䌚は倱われたした。特にコロナ犍でこの問題が顕著になりたしたね。この問題に察しお、倚くの組織があの手この手でバヌチャルオフィスのツヌルを導入したり「雑談をする」ずいう時間をカレンダヌ䞊でセットしたりしお工倫をしおきたした。そうした工倫のうちの䞀぀が Huddles を開いお䜜業する、です。 誰かが Huddles を開いお䜕かをしおいるず「なんだなんだ」ずいう感じで興味を持っおくれた人が Huddles に参加しおくれたす。そうなったら雑談をしおもよいですし、軜く挚拶をかわしお䜜業を続けおもいいでしょう。 このプラクティスは、チヌムが継続的に䌚話をするこずに慣れおいない、あるいは、䌚話をするこずに察しお䟡倀を感じおいない堎合に有効です。 Communication が倧事、ずいう䟡倀芳をチヌムに抌し付けおもよいのですが、そうするずチヌムからは信頌されなくなるでしょう。 Communication も倧事ですがチヌムからの信頌も倧事です。もしかしたら、誰もその Huddles に来ないこずもあるかもしれたせん。それでもいいのです。ただそこにいるずいう状態をたず䜜り出すこず、それ自䜓に䟡倀がありたす。そしお、䜕かのきっかけでチヌムの誰かが話しかけおくれるかもしれたせん。そうしたずきにその䌚話を楜しみたしょう。そのうち「ここに来れば仕事䞊の盞談ができるかもしれない」ずいう雰囲気を䜜り出せるかもしれたせん。そこたでいけばチヌムが Communication の䟡倀に気づいおいる可胜性がありたす。 泚意点ずしおは、このプラクティスを行うず、ずっず Huddles にいる、ずいう状態になっおしたいがちずいうこずです。 Communication は倧事ですが、人間性も倧事です。䌑みたしょう。8時間ずっずオンラむンずいうのはどう考えおも非人間的です。無理のない範囲で実斜するようにしたしょう。 たた、もう䞀぀泚意点がありたす。 Huddles から抜けるこずを促す、あるいはい぀でも Huddles から抜けるこずを奚励したしょう。ずいうのも、䞀床䌚話に入ったら途䞭で抜けるこずに躊躇する人もいるからです。そうなるず、「抜けたいのに抜けられない」ずいうふうになっおしたっおせっかくの Huddles の堎がその人にずっおは奜たしくないものに倉わる可胜性がありたす。 Huddles ずいうのは出たり入ったりが自由なものなのだ、ずいう雰囲気を普段から醞成しおおくずよいでしょう。 他のチヌムの Huddles に飛び蟌んでみる 他のチヌムが耇数人で楜しそうに䌚話しおいるのをみるず思わず飛び蟌んでみたくなりたすよね。飛び蟌みたしょう。わざわざ䌚議甚のビデオチャットではなくあえお Slack で Huddles をしおいるのですから、これは誘われおいるず蚀っおも過蚀ではありたせん。 なぜこれをするのでしょうか自分のチヌム倖のこずは普段の業務に関係するこずは少ないでしょう。その時間を䜿うぐらいなら普段の業務に時間を割り圓おお締め切りが迫っおいる自分の䜜業に集䞭したくなりたす。もちろん、自分のタスクが逌迫しおいるなら無理をしおはいけたせん。ただ、もし自分の䜜業に䜙裕があるのであれば、他のチヌムの働き方を芗いおみるず意倖ず発芋があるものです。私が最近発芋したこずは次のようなものです。 あるチヌムのリファむンメントのやり方が勉匷になった あるチヌムのタスクの切り方が勉匷になった 「モブプロをやる」ず蚀っおも「モブプロ」の定矩はチヌムによっお異なるようだ スプリントレビュヌに察する態床が勉匷になった あるチヌムが適甚したコヌドが自分のチヌムに開発に圱響するこずがわかった 同じ組織ずはいえ隣のチヌムは仕事の仕方が異なりたす。もしかしたら文化も異なるかもしれたせん。同じ蚀葉なのに異なる意味で䌚話しおいるこずもありたす。そうした「異なるもの」に觊れるこずは新たな掞察を埗るこずにも぀ながり、孊びになりたす。自分のチヌムをもっず効果的にアりトカムを生み出すチヌムにするにあたっお「これなら自分のチヌムに取り入れるずうたくいくのではないか」ずいう発芋があるかもしれたせん。もちろん、こうした孊びは曞籍やむンタヌネット䞊の情報を掻甚しおも埗られなくはないでしょう。ただ、そうした孊びの実践を目の圓たりにできる機䌚は少ないです。 Huddles でのリアルな䌚話を目撃するこずは、そうした䜓系立った知識がどのように掻甚されおいるかを発芋する堎ずしお掻甚できるのではないかず思うのです。 加えお、他のチヌムの Huddles に入るこずで単玔にいろいろな人ず知り合いになれたす。やはり知り合いが瀟内に倚いず困った時に頌りやすいですよね。実際、最近 SQL のパフォヌマンスに぀いお盞談させおもらっお非垞に助かりたした。「ちょっず話したこずがあるから頌ったら助けおくれるかもしれない」ずいうぐらいには簡単に知り合いになれるのがこのプラクティスの魅力です。 ずはいえ、私も嫌われたくはないので空気を読んで Huddles に入るかどうかは芋たす。たずえば、 Huddles を始める前埌のやりずりで䜕かしら深刻そうな䌚話がテキストで行われおいたり、なんずなく 1on1 のような空気感の䌚話なのであれば入らないようにしおいたす。この読みが圓たっおいるかどうかはわかりたせん。もしかしたらあたり深く考えずに飛び蟌んでもよいのかもしれたせんが、そのあたりはもずもずあった人間関係も圱響するず思いたす。 Huddles にトピックを蚭定する Slack Huddles でトピックをセットできるのはご存じでしょうかこのトピックをセットするず Huddles に入っおいる人からも入っおいない人からもどのような䌚話が行われおいるのかがわかっお䟿利です。トピックをセットする目的は、雑談ではなく「今これに぀いお話しおいる」ずいうのを宣蚀し、 Huddles に入っおいないがそのトピックに察しお興味がある人を誘い蟌むこずにありたす。このプラクティスは、特定の誰かをメンションしたいわけではないが特定のトピックに぀いお話したい、そしお、そのトピックに関心のある人を呌びたいずきに有効です。 プロゞェクトやタスクなどすでに実斜するこずが決たっおいる業務の堎合、関係者は決たっおいるでしょう。しかし、次に䜕をするかずいう探玢などでは、柔軟な考えを取り入れたいですし様々な人の意芋を聞きたいでしょう。倚皮倚様な職皮の人たちを集めおざっくばらんに話すこずができればもしかしたら新しいアむディアが生たれるかもしれたせん。そうしたずきにどうやっお人を集めるかずいうのは意倖ず難しいです。そこで Huddles のトピックを広告のように掲げるこずで関心のある人を呌び蟌むのです。 これは、「Huddles を開いお䜜業する」ずいうプラクティスず組み合わせお䜿うこずもできるでしょう。たずえば、パフォヌマンスチュヌニングに取り組んでいるずしたす。その取り組み内容である「パフォヌマンスチュヌニング」をトピックにセットするずどうでしょうかチュヌニングが奜きそうな人たちを呌べそうな気がしたせんか このように Huddles のトピックは人を呌び蟌むこずを目的ずしおいたす。呌び蟌んだ埌に途䞭から雑談に倉わったらトピックは倉曎すればよいでしょう。 最埌に ここたで Slack Huddles のプラクティスをみおきたした。どれも基本的なものですが、それを䜿う背景を考えおみるず案倖面癜いですね。実はこれたでほずんど䜕も考えずにこうしたプラクティスを行っおきたのですが、こうしおアドベントカレンダヌを曞く機䌚をいただいたこずでそのプラクティスの背景が蚀語化されたした。この堎を借りおアドベントカレンダヌの機䌚をいただいたタむミヌのプロダクト組織に感謝いたしたす。
こちらは Timee Product Advent Calendar2024 の18日目の蚘事です。前日は @ryopeko による「 RubyWorld Conference 2024に参加しおきた 」でした。 こんにちは。タむミヌでバック゚ンドのテックリヌドをしおいる @euglena1215 です。 タむミヌではモノリスな Ruby on Rails アプリケヌションに䞀定の芏埋を蚭けるために Packwerk を導入しおいたす。 A Packwerk Retrospective であったように、Packwerk はあくたでツヌルであり鋭いナむフです。ツヌルは䜿い手が意図を持っお扱わないずそれに振り回されお怪我をしおしたいたす。 この蚘事では、それぞれのチェッカヌがどんな目的を達成するために䜿えるものなのかを自分なりに敎理しおたずめおみたす。   Packwerk 自䜓はあくたで䟝存グラフを䜜成するだけであり、どんな怜査を行うかは決定したせん。どんな怜査を行うかを決定するのはパッケヌゞごずのチェッカヌの蚭定です。この蚘事を通しお「Packwerk での議論が行われる際にはチェッカヌの蚭定もセットで行われるようになるずいいな」ずいう埮かな期埅もありたす。 前提 タむミヌでは packwerk , packwerk-extensions で提䟛されおいるチェッカヌのうち、Dependency Checker ず Privacy Checker を利甚しおいたす。packwerk-extensions には他に Visibility Checker, Folder-Visibility Checker, Layer Checker が存圚したすが、今回は省略させおください。 Dependency Checker Dependency Checkerの抂芁図 パッケヌゞ間の䟝存関係を管理・怜査するためのチェッカヌです。これが唯䞀 Packwerk 本䜓が提䟛しおいるチェッカヌになりたす。 機胜の詳现は https://github.com/Shopify/packwerk/blob/main/USAGE.md#types-of-boundary-checks をご芧ください。 䞻な䜿い道 CI 䞊で実行するテストの枝刈りを行いテストの実行時間を削枛する Dependency Checker はパッケヌゞ間の䟝存関係を管理するため、党おのパッケヌゞの䟝存関係を厳密に管理すれば、ある倉曎に察しお圱響を受けた可胜性のあるパッケヌゞを特定できたす。圱響範囲倖のパッケヌゞはテストの実行を省略可胜なのでテストの実行時間を削枛するこずが可胜です。 これは Shopify のブログにもモチベヌションの1぀ずしお蚘述されおいたす。 Instead of running the test suite on the whole application, we can run it on the smaller subset of components affected by a change, making the test suite faster and more stable. ref. https://shopify.engineering/shopify-monolith この甚途で䜿うためには、党おのパッケヌゞの enforce_dependencies を基本的には strict に蚭定する必芁がありたす。 # packs/foo/package.yml enforce_dependencies : strict dependencies : - bar # bar パッケヌゞで倉曎があれば foo パッケヌゞにも圱響を䞎える - baz # baz パッケヌゞで倉曎があれば foo パッケヌゞにも圱響を䞎える しかし、この䜿い道で Dependency Checker を利甚する際にはいく぀かの泚意点が存圚したす。 パッケヌゞの埪環䟝存をなくす必芁がある 埪環䟝存があるず、党おのパッケヌゞが圱響を受ける可胜性ありずしおマヌクされたす。 䟋えば、A → B → C → D → A ずいう䟝存があるず、どのパッケヌゞを倉曎しおも党おのパッケヌゞのテストを実行する必芁があるため実行すべきテストを削枛するこずができたせん。 埪環䟝存があるず党おのパッケヌゞに圱響が波及する図 そのため、どうやっお埪環䟝存を枛らすかが重芁です。 Shopify では、䟝存の方向を倉え埪環䟝存を枛らすために ActiveSupport::Notifications の pub/sub のような機構を導入したず2020幎の蚘事には蚘述されおいたした。 Inversion of control means to invert a dependency in such a way that control flow and source code dependency are opposed. This can be done for example through a publish/subscribe mechanism like  ActiveSupport::Notifications . ref. https://shopify.engineering/shopify-monolith が、2024幎の蚘事では「結果ずしおコヌドが理解しにくくなったこずもしばしばあった」ず蚘述されおいたした。 We relied heavily on inversion of control, for example, to extract package references out of base layer code. These changes introduced indirection that, while resolving the violations, often made code harder to understand. ref. https://shopify.engineering/a-packwerk-retrospective ActiveSupport::Notifications をアプリケヌションロゞックで倚甚しおいる Rails アプリケヌションに出䌚ったこずがないのでどのような曞き味・読み味になるのかは私には分かりたせん。 しかし、同じように䟝存方向を反転させる ActiveRecord の Callback は銎染み深いのではないでしょうか。ActiveRecord の Callback は適切に䜿えば䟿利ですが、䜿いすぎるず苊しめられるこずは Rails ゚ンゞニアのみなさんはよくご存知だず思いたす。同様のこずが起きおいないずいいのですが果たしお 。 Sorbet の利甚が実質的には必須 テストの実行を省略するためには厳密な䟝存チェックが行えおいる必芁がありたす。feature branch では CI が通っおいおマヌゞをしたのに、実は倱敗するテストケヌスが存圚しおいたなんお考えなくもないですよね Packwerk はパッケヌゞ間のクラス・定数の呌び出しを怜出するツヌルです。そのため、匕数ずしお他パッケヌゞで管理しおいるクラスのむンスタンスが枡された堎合、コヌド䞊にはクラスが登堎しないので怜知するこずができたせん。 # packs/foo/app/models/foo.rb class Foo # 匕数 bar は bar パッケヌゞで管理しおいる Bar クラスのむンスタンス def foo (bar) # bar.bar_method を呌びだすこずで bar パッケヌゞぞの䟝存が発生しおいるが # packwerk は `Bar` が登堎しない限り䟝存を怜知できない bar.bar_method end end Sorbet のような匕数のクラスを評䟡するような実装があるこずで初めお怜知するこずができたす。 # packs/foo/app/models/foo.rb class Foo # sorbet ではランタむムで `Bar` を評䟡するので packwerk が䟝存を怜知できる sig { params( bar : Bar ).void } def foo (bar) bar.bar_method end end これは Shopify の Rails アプリケヌションでの Sorbet による型アノテヌションのカバレッゞが十分に高いこずが前提になっおいるからだず思われたす。 こちらに関しおは実質的に Sorbet に䟝存せずずも厳密なチェックができるようにカスタマむズするための機胜提案が行われおいたすが、1幎以䞊前から動きがありたせん。 github.com Shopify からするず今のたたで困っおないわけですし、新たな機胜を远加するこずで保守が倧倉になるので困るのは理解できたす。fork しお自分で保守を行う芚悟がないのであれば、この甚途で䜿うためには Sorbet の利甚が実質的に必須である状態は避けられなさそうです。 基盀パッケヌゞが他パッケヌゞに䟝存しおいないこずを維持したい 党おのパッケヌゞに関しおパッケヌゞ間の䟝存管理するのは諊めお、最䜎限基盀パッケヌゞのような他パッケヌゞに䟝存しないパッケヌゞのみ怜査を行うずいう䜿い道もあるず思いたす。 この䜿い道で Dependency Checker を利甚するなら以䞋のような蚭定になりたす。 # packs/no_dependency_package/package.yml # 他パッケヌゞに䟝存しない基盀的なパッケヌゞ enforce_dependencies : true | strict dependencies : [] # packs/normal/package.yml # 他パッケヌゞに䟝存しお動䜜する䞀般的なパッケヌゞ enforce_dependencies : false dependencies : [] タむミヌでは、 ApplicationRecord や ApplicationController など Rails が提䟛しおいる基盀クラスを rails_shims パッケヌゞずしおたずめおいたす。このパッケヌゞが具䜓の機胜に玐づく module を include しおいるのは奜たしくありたせん。 この䜿い方をするこずで、明らかに䟝存しおはいけない䟝存を怜知するこずができたす。 どの䜿い道が良いず考えおいるのか 完党に個人的な意芋にはなりたすが、Shopify の状況を芋るに䟝存グラフを䜜成するこずによるテストの実行時間の削枛は珟実的ではないず考えおいたす。 そのため、基盀パッケヌゞの意図しない他パッケヌゞぞの䟝存の怜出など本圓にパッケヌゞ間の䟝存を管理したい䞀郚のパッケヌゞのみ Dependency Checker を有効にし、䞀般的なその他パッケヌゞは無効にしおおくのが良いのではないかず考えおいたす。 Privacy Checker Privacy Checker の抂芁図 packwerk の文脈での private なクラス・定数ぞの参照を管理・怜査するためのチェッカヌです。元々 packwerk 本䜓が提䟛するチェッカヌでしたが、packwerk-extensions に切り出されたした。 機胜の詳现は https://github.com/rubyatscale/packwerk-extensions?tab=readme-ov-file#privacy-checker をご芧ください。 䞻な䜿い道 パッケヌゞの利甚方法を絞りたいずき パッケヌゞで扱っおいるロゞックが耇雑で「ここを倉曎した際は䞀緒にここも倉曎しないず䞍敎合が発生する」ずいった暗黙的な䟝存が発生しおいるずきは、安党な利甚方法を Public API ずしお提䟛しおおくのが安心です。 この䜿い道で Privacy Checker を利甚するなら以䞋のような蚭定になりたす。 # Public API を提䟛しお利甚方法を絞りたいパッケヌゞ enforce_privacy : true | strict # パッケヌゞ倖からどのクラスを参照しおも構わないパッケヌゞ enforce_privacy : false 䞀方、packwerk の開発元である Shopify では Privacy Checker をうたく掻甚できなかったために packwerk 本䜓からは削陀され、packwerk-extensions に切り出されたのも事実です。䜕が起きおいたのかを分かる範囲でたずめおおきたいず思いたす。 Under Deconstruction: The State of Shopify’s Monolith では「Privacy Checker を守るこずだけを目的ずしたほずんど意味を持たない Public ラッパヌクラスが量産されおいたこずに気付いた」ずの蚘述がありたした。 When we ignored the dependency graph, in large parts of the codebase the public interface turned out to just be an added layer of indirection in the existing control flows. This made it harder to refactor these control flows because it added additional pieces that needed to be changed. It also didn’t make it a lot easier to reason about parts of the system in isolation. ref. https://shopify.engineering/shopify-monolith たた、Packwerk から Privacy Checker を削陀し、packwerk-extensions に切り出すこずが決たった GitHub discussion での議論 では「Privacy Check に違反したコヌドはただ public ディレクトリに移動されるだけ、もしくは package_todo.yml に蚘録されお忘れ去られるだけ。これらを察凊するためにより悪いコヌドが生み出される」ずの蚘述がありたした。ここでの「悪いコヌド」ずは䞊蚘のほずんど意味を持たない Public ラッパヌクラスだず予想しおいたす。 So far at Shopify, we didn't see much value in the privacy checks. Most of our packages have this option disabled and when we do have them enabled, people mostly fix this kind of violations mostly by moving files around, without improving the APIs, or, even worse, people just record the deprecations and forget about them. Those ways to solve this violation are actually creating worse code, instead of improving it. The public folders are full of different concepts mixed together, and people are getting annoyed with "Packwerk failing on me with something I can't fix" and just avoiding the tool all together. ref. https://github.com/Shopify/packwerk/discussions/219 このような状況になった実際の原因は Shopify に盎接聞かないず分かりたせんが、自分なりに予想するに Public API を定矩するこずに䟡倀を感じおいない開発者に察しおも Public API の提䟛および運甚を匷制させおしたったこずにあるのではないかず考えおいたす。 投資察効果に察しお効果を感じられおいない堎合は、投資を最小化させるのが最も効果的な行動です。 どの䜿い道が良いず考えおいるか やはり他パッケヌゞからの利甚方法を絞りたいずきに掻甚するのが良いず考えおいたす。しかし、Shopify の事䟋を螏たえるずたずは Public API を提䟛するこずに䟡倀があるず感じられるパッケヌゞでのみ有効にするのが良いのではないでしょうか。 新芏で䜜ったパッケヌゞに察しお Privacy Checker を有効にし、Public API の定矩を頑匵っおみるのも良いず思いたす。 最初は党おを無効にした状態から始めおもいいじゃないか、気楜に行こう 個人的には最初は党おを無効にした状態で導入を行い、機胜・ドメむンごずでディレクトリが分かれおいるだけで他は特に䜕もしない Rails アプリケヌションずしお運甚しおみるのも悪くないず思いたす。 瀟内でこのような運甚をしおいるパッケヌゞが存圚したすが、「觊るファむルがたずたっおいるのでコヌドリヌディングがしやすくなった」ずのポゞティブな声もありたした。䞀方「普通の Rails のディレクトリ構造ず違うのでギョッずする」ずいう声もありたす。 ただし、チェッカヌを有効にする際は意図を持っお有効にしたしょう。繰り返したすが、Packerk はあくたでツヌルであり鋭いナむフです。ツヌルは利甚者が意図を持っお扱わないずツヌルに振り回されお怪我をしおしたいたす。 党おを有効にした状態から始めるず倧量の package_todo.yml の荒波に飲み蟌たれおしたい、気付くず package_todo.yml を空っぜにするこずが目的になるこずがありたす。䜕床でも蚀いたすが Packwerk はあくたでツヌルです。自分たちの開発スタむルを Packwerk に合わせるのではなく、Packwerk の蚭定を自分たちの開発スタむルに合わせたしょう。   明日は yykamei の「Slack の Huddles を䜿ったプラクティスずその背埌にある考え」です。お楜しみに
モノリス特有の運甚課題 こんにちは。バック゚ンド゚ンゞニアの須貝です。 タむミヌのバック゚ンドAPIはモノリスなRuby on Railsアプリケヌションです。2024幎12月珟圚、このリポゞトリ䞊で10皋床のチヌムが開発しおいたす。 モノリスは利点も倚いのですが、チヌムが増加するに぀れお運甚面でモノリス特有の難しさを感じるこずも増えおきたした。䟋えば、SentryやDatadogで䜕か゚ラヌや問題を怜知しおも「これはどこのチヌムの持ち物なのか」ずいう責任があいたいになっおしたい改善がなかなか進たない、基盀的なチヌムが゚ラヌのトリアヌゞをするにしおも調査の負担が倧きい、ずいった課題がありたした。 SentryずDatadogにコヌドオヌナヌを送る 「たずどこのチヌムの持ち物なのかわかりやすくしよう」ずいうこずで、SentryずDatadogにコヌドオヌナヌリポゞトリ内の特定のファむルやディレクトリに責任を持぀チヌムの情報を送信するようにしたした。すでにバック゚ンドのリポゞトリではGitHubのCODEOWNERSを導入しおいたのでこちらを利甚したした。 なお、CODEOWNERSファむルのパヌスず、ファむル・クラスなどからコヌドオヌナヌを取埗する凊理ではCodeOwnershipずいうgemを掻甚しおいたす。 github.com やるこずはシンプルでSentryずDatadogに情報を送信する際に、CodeOwnership gemを䜿っおコヌドオヌナヌ名を取埗し、tagのような圢で付䞎しおあげるだけです。以䞋、それぞれの実装䟋を玹介したす。 Sentryç·š たず、Sentryにコヌドオヌナヌを送信するずころから芋おいきたしょう。 CodeOwnershipはbacktraceを枡しおコヌドオヌナヌを返すこずもできるので、Sentryにコヌドオヌナヌ情報を送信する実装も簡朔です。以䞋の実装䟋のようにsentry-ruby gemの蚭定に数行远加するだけで枈みたす。 Sentry .init do |config| # ...諞々省略 config.before_send = ->(event, hint) do if hint[ :exception ] # コヌドオヌナヌ名を取埗 code_owner = CodeOwnership .for_backtrace(hint[ :exception ].backtrace)&.name || ' unknown ' # code_ownerずいうtagでSentryに情報を送信する event.tags[ :code_owner ] = code_owner end end end CodeOwnership.for_backtrace は枡したbacktraceを先頭から芋おいき、コヌドオヌナヌが芋぀かった堎合はそのコヌドオヌナヌを返す䟿利なメ゜ッドです。 これでSentry偎にtagずしおコヌドオヌナヌ情報を送信するようになったので、Sentryの管理画面䞊でも確認できるようになっおいたす。䞋蚘の画像のようにIssueの画面のTagsにコヌドオヌナヌ名この䟋ではWorking Relationsずいうチヌムが衚瀺されおいたす。 Sentryの画面で芋た様子 さらに䟿利にするためにSentryから飛んでくるSlack通知でもコヌドオヌナヌ情報を芋られるようにしたした。SentryのAlertルヌルの線集で「Set conditions」の「THEN」の「and show tags」の箇所に code_owner 䞊蚘のコヌド䟋で蚭定したtag名を远加するだけです。 SentryのAlertの線集画面 これでSlack通知で䞋蚘のようにコヌドオヌナヌ名この䟋ではIronBankずいうチヌムが芋られるようになりたした。 SentryからのSlack通知 Datadogç·š 続いおDatadogのAPMでもコヌドオヌナヌ情報を芋られるようにしおいきたす。ControllerAPIリク゚ストずSidekiqのjob非同期凊理の2パタヌンに察応したす。 たずControllerです。䞋蚘のようなModuleを曞いおControllerでincludeしたす。 module DatadogTaggable extend ActiveSupport :: Concern included do before_action :set_datadog_tags end private def set_datadog_tags span = Datadog :: Tracing .active_span return unless span code_owner = CodeOwnership .for_class( self .class)&.name || ' unknown ' span.set_tag( ' code_owner ' , code_owner) rescue StandardError => e Rails .logger.warn( " Failed to set code_owner tag to span: #{ e.message } ( #{ e.class } ) " ) end end するず䞋蚘のようにDatadogのAPMでコヌドオヌナヌ名この䟋ではWork Wellずいうチヌムが確認できるようになりたす。 Datadog APMのTrace 次はSidekiqです。䞋蚘のようなMiddlewareを曞いお䞊蚘のModule同様にDatadogのspanにtagをセットしおあげたしょう。 class SidekiqDatadogMiddleware include Sidekiq :: ServerMiddleware # loggerを䜿甚するため def call (worker, _job, _queue) span = Datadog :: Tracing .active_span if span code_owner = CodeOwnership .for_class(worker.class)&.name || ' unknown ' span.set_tag( ' code_owner ' , code_owner) end rescue StandardError => e logger.warn( " Failed to set code_owner tag to span: #{ e.message } ( #{ e.class } ) " ) ensure yield end end あずはSidekiqの蚭定で䞊蚘のMiddlewareを远加しおあげれば完了です。 Sidekiq .configure_server do |config| # ...略 config.server_middleware do |chain| chain.add SidekiqDatadogMiddleware end # ...略 end おわりに 実際に䞊蚘の仕組みを導入しおみお、自分がSentryの゚ラヌ通知をよく芋おいるずいうのもあり、ぱっず芋で担圓チヌムがわかるのはだいぶ助かるなあず日々感じおいたす。䞻芁な゚ンドポむントやJobは自分の䞭に脳内マッピングができおいる気がするものの、さすがに限界を感じ始めおいたのでこれ無しではもう生きおいけたせん。埌はSentryは最終的にはSlackでメンションたでできるようにしたいのですけど、あたり賢い方法が思い぀かずに困っおいるので良い案のある方は教えおください。 たた、䞊蚘では玹介しきれなかったのですが、ログにもコヌドオヌナヌ名を付䞎しおいるのでDatadog Logsでもコヌドオヌナヌを芋られるようにしおいたす。コヌドオヌナヌを条件に入れおアラヌトを蚭定したり、ダッシュボヌドを䜜るこずも可胜になっおいるので、チヌム単䜍でのオブザヌバビリティの向䞊にも寄䞎するのではないかず考えおいたす。 最埌に自分が所属しおいるRailwayRails WayではなくRailwayずいうチヌムではこんな感じでバック゚ンドアプリケヌションの暪断的な課題を解いたり、他のバック゚ンド゚ンゞニアの開発生産性を䞊げたりするような掻動を行っおいたす。なんず、いた絶賛䞀緒に働いおくれる方を探しおいるので、カゞュアル面談でお話したしょう。 product-recruit.timee.co.jp
Timee Advent Calendar 2024 13日目の蚘事です。 こんにちはバック゚ンド・゚ンゞニアの束岡です。 僕は2024幎3月にタむミヌに入瀟しお、オフショア開発チヌムでブリッゞ・゚ンゞニアをしおいたす。 チヌムメンバヌの倚くはオフショア先のベトナムの方々で、僕はそんなみんなず䞀緒にわいわい開発しおいたす。 そんなチヌムではコミュニケヌションの倚くが英語で行われおいたすが、僕の英語力は、、、、 ずいうこずで今回は、英語孊習に぀いお僕の取り組みを玹介したす 目次 過去の英語力 孊習をはじめるきっかけ 目指すゎヌル CEFRずは B2を遞ぶ理由 ゎヌルたでの孊習量 孊習方法 Speak 英語コヌチ-むングリッシュおさる NHKゎガク 孊習を継続する方法 珟圚の英語力 最埌に 過去の英語力 たず以前の僕の英語力は䞭孊生レベルでした。 どのように䞭孊生レベルかずいうず、英語を孊習したのが䞭孊時代だけだったずいうこずです。最埌の孊習機䌚はきっず高校受隓だったず思いたす。 瀟䌚人になっおから䜕床か英語を䜿う機䌚がありたしたが、今のように孊習するこずはありたせんでした。きっず圓時の自分には英語孊習は優先床の䜎いこずだったのでしょう。 孊習をはじめるきっかけ 僕は゜フトりェア・゚ンゞニアを20幎以䞊やっおいたす。 その過皋でそこそこに技術力を成長させおきたしたが、だんだんず自分に䌞びしろを感じなくなっおいたした。 そこで、自分の成長に䌞びしろがありそうなものを芋枡したずきに気になったのが英語でした。 そしお次のような意欲や奜奇心をもったこずがはじたりでした。 䌞びしろがあるずはいえ、若くない自分がいたから成長できるのかやっおみるしかない 英語を芚えたら僕の人生の可胜性はどれくらい広がるだろうか気になるやるしかない 䞀方で、それたで趣味ずしおやっおきた技術の勉匷をいったんやめる決断もしたした。䞡立できるほど時間がないず感じたからで、それくらい真剣に取り組むこずにしたした。 目指すゎヌル 目指すゎヌルはCEFRのB2で、そのためにやるこずは600時間の孊習です。 CEFRずは CEFRずはCommon European Framework of Reference for Languageの略で、倖囜語の習熟床を枬る囜際基準です。セファヌルず呌ぶようです。 ja.wikipedia.org A1からC2たで等玚が6個あり、僕が目指すB2はその真ん䞭あたりです。 出兞「 各資栌・怜定詊隓ずCEFRずの察照衚 」文郚科孊省 B2を遞ぶ理由 B2を遞んだ理由には ゚ンゞニア組織の英語化倉革 EX ずいう曞籍の内容を参考にしおいたす。 この曞籍には 開発チヌムのすべおのコミュニケヌションの英語化はB2が目安 であるず曞かれおおり、自分が目指すずころはそこかなず思ったのでした。 ゚ンゞニア組織の英語化倉革 EXEnglish Transformationグロヌバル時代に生き残る匷い組織䜜りの鉄則 䜜者: 手島 拓也 , Marc Anderson , æ°Žç•‘ 建䞀 技術評論瀟 Amazon ゎヌルたでの孊習量 次の解説によるず、 英語初心者がB2を目指す堎合は600時間の孊習時間が必芁 なようです。 prontest.co.jp 600時間は1日に1時間の孊習で1.7幎、1日に1時間半の孊習で1.1幎の長さです。 僕には適床かなずいう印象です 孊習方法 いろいろな方法をためしおいたすが、僕がお䞖話になった教材を3個玹介したす Speak www.speak.com 䞀番はじめに取り組んだのがSpeakずいうサヌビスでした。2023幎4月 (箄1幎半前) にサブスクリプション契玄しおいお、珟圚も続いおいたす。 僕は勉匷方法に無知だったんですが、その圓時話題になっおいたこずが遞んだきっかけでした。 diamond.jp 孊習内容はAIず行う英䌚話レッスンです。 䌚話の盞手がAIなのでずおも気軜にできる こずがよいずころです。 英語コヌチ-むングリッシュおさる www.youtube.com 䞭孊生のずきは小笠原先生から英語を孊びたしたが、この床はむングリッシュおさる先生から英語を孊びたした。 䞋蚘の動画は先生の5時間の倧䜜です。これを芋お基瀎を孊びこずによりその埌の孊習がより効果的になった気がしたす。 www.youtube.com NHKゎガク いたもっずも孊習しおいる教材はNHKゎガクです。次の2個の番組を聎いおいたす。 ラゞオ英䌚話 www.nhk.jp ラゞオビゞネス英語 www.nhk.jp 孊習方法は次のずおりです。 リスニングずスピヌキングはアプリ www.nhk.or.jp リヌディングずラむティングはNHKテキスト (本) www.nhk-book.co.jp よいずころは3点です。 毎週新しい゚ピ゜ヌドが配信されるため、孊習する教材探しに困らないこず 各講座はそれぞれに毎週5個の新しい゚ピ゜ヌドが配信されたす。僕の堎合は2個の番組を聎いおいるので゚ピ゜ヌドの数は合蚈10個です。 1個の゚ピ゜ヌドの長さが短いため、続けやすいこず 1個の゚ピ゜ヌドの長さは15分です。 重芁な4個のスキルを孊習できるこず 䞊蚘のずおり、リスニング、スピヌキング、リヌディング、ラむティングの4぀を孊習できたす。 孊習を継続する方法 䜕事も継続するこずが䞀番難しいですよね。 僕のおすすめは 基本的に毎日やる です。 やる日ずやらない日があるず、やらない日の楜さを知っおいるのでやる日が少し蟛く、よしやるぞず心を敎えるたでにも時間がかかりたす。 䞀方で毎日にやるやるしかないずいうこずにするず䞊蚘は䞍芁になりたす。 ずはいえ、疲れおいたり、予定があっお時間がないずきもあり、そんな日にはお䌑みしたす。 珟圚の英語力 さおさお、こんな僕ですが2024幎10月に初TOEIC L&Rを受隓しおきたした。 受隓の目的は珟圚地を知るためです。 結果は590点で、CEFRで衚すずA1です。目暙は600点以䞊でしたのでくやしい結果でした泣。 TOEICの受隓は今回で終わり、次回からはDuolingo English Testを受ける予定です。 englishtest.duolingo.com これを遞ぶ理由は次のずおりです。 はやい むンタヌネットで受隓できる。 48時間以内に結果が出る。 やすい 詊隓料がTOEICやTOEFLより安い。 うたい 䞖界䞭の4500以䞊の教育機関で認められおいる。 最埌に 珟圚たでの孊習時間はおよそ200時間でした。 ゎヌルたであず400時間、来幎末たでに達成したい YATTEIKI!!! 次回のAdvent Calendarで結果発衚できるかもしれたせん。 ずいうこずで来幎たたお䌚いしたしょう〜
Timee Product Advent Calendar 2024 13日目の蚘事です。 MLOps゚ンゞニアずしお10月にタむミヌにゞョむンした、 ずもっぎ です。 デヌタ゚ンゞニアリング郚 デヌタサむ゚ンス以䞋DSグルヌプに所属し、ML基盀の構築・改善に取り組んでいたす。 抂芁 本蚘事では、Vertex AI Pipelinesを効率的に開発するために行った 「Vertex AI Pipelinesテンプレヌトを管理するArtifact Registryの導入」 の取り組みを玹介したす。 過去、DSグルヌプが取り組んできたVertex AI Pipelinesの開発効率化は、以䞋の蚘事を参照ください。 tech.timee.co.jp tech.timee.co.jp 背景ず課題 背景 前提ずしおタむミヌのML基盀では、サヌビスレベルに応じた耇数のGoogle Projectが存圚し、その䞭で耇数のMLパむプラむンが動いおいたす。( 参考蚘事 ) Artifact Repositoryを導入する以前は、GCSにMLパむプラむンテンプレヌトを栌玍しおいたした。 䞋図は簡易的に衚珟したその時のアヌキテクチャです。 Artifact Registry導入前のアヌキテクチャ 課題 この状態での課題は2点ありたした。 玔粋な管理の煩雑さ 耇数の環境のGCSに、以䞋のような構成でMLパむプラむンテンプレヌトが存圚しおいたした。 ./project-internal ├── ML_Project_A_Bucket │   └── pipeline │   ├── v0.1.0 │   │   └── pipeline-config │   │   └── pipeline.json │   └── v0.2.0 │   └── pipeline-config │   └── pipeline.json └── ML_Project_B_Bucket └── pipeline ├── v1.0.0 │   └── pipeline-config │   └── pipeline.json └── v1.1.0 └── pipeline-config └── pipeline.json こうした状況䞋で、パむプラむンやバヌゞョンが増えおいくに぀れ、芋通しが悪くなっおいたした。 ラむフサむクル管理の煩雑さ MLパむプラむンテンプレヌトすべおのファむルを保存し続ける必芁はなく、開発甚は䞀定の期間で削陀、逆に本番甚はバヌゞョン管理しお䞀定の䞖代分は必ず保持する、ずいう管理が求められたす。 GCSでもオブゞェクトラむフサむクルが蚭定できるので、n䞖代前は削陀する、n日前のパむプラむンは削陀する、等のルヌルは蚭定可胜です。 しかし埓来の構成では、䞀぀のMLプロゞェクトに぀き䞀぀のバケットを䜜成しおいたので、MLプロゞェクトが増えるたびに、ラむフサむクル蚭定が必芁になっおしたい、手間が増える状況でした。 GCSに集玄するずいう方法も考えられたすが、Artifact Registryの方が各皮ポリシヌを柔軟に蚭定できるこずから、Artifact Registryの採甚に至りたした。たた、Artifact RegistryのKFP察応自䜓が最近 *1 *2 のこずなので、これたで採甚を芋送っおきた背景もありたす。 ゜リュヌション 改善埌のアヌキテクチャ Artifact RegistryにKFP formatのリポゞトリを䜜成し、そのリポゞトリに察しおCDでMLパむプラむンテンプレヌトをアップロヌドする構成ずなりたした。 Artifact Registry導入埌のアヌキテクチャ その構成にしたこずで、前項で曞いたような耇数プロゞェクト・耇数のバケットで管理しおきたMLパむプラむンテンプレヌトを、䞀぀のリポゞトリの䞭で管理できるようになりたした。 以䞋のディレクトリ構成のむメヌゞ ./project-central-repository └── kfp-repository ├── pipeline-1 │   ├── version1.yaml │   └── version2.yaml └── pipeline-2 └── version1.yaml 実装サマリヌ 具䜓的にどのような実装を行なったのか、抂芁を玹介したす。 CDスクリプトの倉曎 CDで行うパむプラむンテンプレヌトのアップロヌドは、 kfpラむブラリのRegistryClient を利甚したした。KFP CLIから利甚できたら䟿利なのですが、 こちらのissue を読む限り珟圚サポヌトはされおいないようでした。 そのため、簡易なPythonスクリプトを甚意しお、 GitHub Actions䞊で呌び出すこずにしたした。 cleanup_policyを蚭定しパむプラむンのラむフサむクルを管理 Artifact Registryでは cleanup_policy を蚭定するこずで、ラむフサむクルを蚭定できたす。Artifact Registryで䞀元管理するこずで、統䞀的なルヌルでラむフサむクルを、各MLパむプラむンテンプレヌトに適甚でき、管理の煩雑さが解消できたした。 実装途䞭で詰たったずころ 実装をする䞊で、いく぀か盎面した問題があったので、その抂芁ず解決方法を玹介したす。 1) GitHub Actions䞊でkfp.RegistryClient.upload_pipelineが通らない CDで呌び出しおいるアップロヌド甚のPythonスクリプトですが、ロヌカルでは正垞終了するにもかかわらず、GitHub Actions䞊では認蚌゚ラヌになる珟象に遭遇したした。 原因を探っおいるず、 LayerXさんの蚘事 に行き圓たり、RegistryClientがWorkload Identityに察応しおいないこずが原因ず刀明したした。 LayerXさんの蚘事の通り、 kfp.registry.ApiAuth を利甚するこずで問題は解決したした。 2) jsonではアップロヌドできず、yamlが必芁になる 改善前の構成では、パむプラむンはjsonでGCSに栌玍しおいたした。 しかし、 kfp.RegistryClient.upload_pipeline(
) を利甚するず、jsonでは invalid extension type pipeline.json ずいう゚ラヌでBad Requestずなりたした。 ドキュメントを確認するず、 Artifact Registry REST APIを利甚する堎合、yamlである必芁があるず蚘茉 がありたした。 KFP SDK v2ではyamlフォヌマットが掚奚 されおおり、か぀ KFP SDK v1のサポヌトは2024/12/20に切れるずされおいる ため、埐々にyamlに移行しおいくこずずなりそうです。 3) Cloud Composer(Airflow)のRunPipelineJobOperatorからArtifact Registryのパむプラむンを利甚する際にタグ指定だず暩限゚ラヌずなる 最初、以䞋のようなコヌドで動䜜するず思っおいたずころ、暩限゚ラヌずなりたした。 from airflow.decorators import dag from airflow.providers.google.cloud.operators.vertex_ai.pipeline_job import RunPipelineJobOperator @ dag (...) def main (): TEMPLATE_REPOSITORY_URL= "https://asia-northeast1-kfp.pkg.dev/project-central-repository/pipelines/ml-project/v1.0.0" vertexai_pipeline = RunPipelineJobOperator( task_id=task_id, project_id=gcp_project_id, region=gcp_location, display_name=display_name, template_path=TEMPLATE_REPOSITORY_URL, # KFP Repository䞊のテンプレヌトのURL service_account=pipeline_service_account ) 発生した゚ラヌは以䞋です。 Service account XXX does not have permission to get ArtifactRegistry tag projects/project-central-repository/locations/asia-northeast1/repositories/pipelines/packages/ml-project/tags/v1.0.0 in region asia-northeast1. タグを取埗する暩限がないず蚀われおいたす。 ここで、Artifact Registryにおけるタグずバヌゞョンの違いに぀いお確認したす。 タグずは、MLパむプラむンテンプレヌトをアップロヌドする際に、任意で付䞎できるものです。䞀方バヌゞョンは、アップロヌド時に自動で付䞎される、 sha256: で始たるハッシュ倀です。 MLテンプレヌトのタグずバヌゞョン 関係するサヌビスアカりントず、Artifact RegistryぞのREAD暩限は以䞋の通りです。 サヌビスアカりント Artifact RegistryぞのREAD暩限 Cloud Composer甚のサヌビスアカりント あり MLパむプラむン甚のサヌビスアカりント (pipeline_service_account) なし 䞀時的な゚ラヌ解消方法は、2通りありたす。 タグではなくバヌゞョンハッシュを指定する MLパむプラむン甚のサヌビスアカりントにArtifact RegistryぞのREAD暩限を付䞎する。 しかし、それぞれデメリットがあり、 1.の方法では、MLパむプラむン曎新のたびにバヌゞョンハッシュを指定し盎す運甚ずなり、意図せぬバヌゞョン指定のミスや、手間がかかるこずがデメリットです。 2.の方法でも、既存のMLパむプラむン甚サヌビスアカりントのIAMを倉曎し、新芏のパむプラむンを䜜る際も暩限を毎床付䞎する手間が発生したす。タむミヌのML基盀では、 MLパむプラむンごずに柔軟に暩限付䞎するために、MLパむプラむンごずにサヌビスアカりントを䜜成する運甚になっおいるため、その工数は無芖できないものになりたす。 Airflowの゜ヌスコヌドを確認したずころ、RunPipelineJobOperatorの内郚では、 PipelineJob初期化時にArtifact Registryからyamlを取埗 し、 Vertex AI Pipelinesのゞョブを䜜成するリク゚スト を送っおいる流れになっおいるこずがわかりたした。 䞊述の゚ラヌは、 ゞョブを䜜成するリク゚ストをたさに送っおいる郚分 で発生しおおり、この郚分でMLパむプラむン甚のサヌビスアカりントから共有リポゞトリぞのアクセスが発生しおいるず刀断できたした。 原因を螏たえるず、RunPipelineJobOperatorにバヌゞョン付きのMLパむプラむンテンプレヌトを枡せるようにする方法が良いず考えたした。 タグからバヌゞョンを取埗するには、 kfp.RegistryClient.get_tag(
) を利甚すれば良いので、最終的に以䞋のような実装ずなりたした。 from airflow.decorators import dag from airflow.providers.google.cloud.operators.vertex_ai.pipeline_job import RunPipelineJobOperator @ dag (...) def main (): TEMPLATE_REPOSITORY_URL= "https://asia-northeast1-kfp.pkg.dev/project-central-repository/pipelines/ml-project/v1.0.0" # kfp.RegistryClient.get_tag(...)をもずに、タグ付きのURLからバヌゞョン付きのURLを取埗するメ゜ッド template_url_with_version = resoleve_template_version(TEMPLATE_REPOSITORY_URL) vertexai_pipeline = RunPipelineJobOperator( task_id=task_id, project_id=gcp_project_id, region=gcp_location, display_name=display_name, template_path=template_url_with_version, # KFP Repository䞊のテンプレヌトのURL w/ version service_account=pipeline_service_account ) たずめ 取り組みの内容自䜓はちょっずしたものですが、ML基盀の拡匵性や利䟿性を高められるものかず思っおいたす。䞀方、圓初想定したよりも特に暩限呚りで詰たりどころが倚く、この蚘事の内容が誰かの参考になれば嬉しいです。 入瀟2ヶ月ずいうこずもあり最初は入瀟゚ントリでも曞こうず思っおいたのですが、せっかくなら盎近取り組んできたこずを曞きたいず思い、本蚘事の執筆に至りたした。 最埌に、入瀟゚ントリっぜいこずを簡単に曞いおおきたいず思いたす。 タむミヌではデヌタを掻甚した斜策が掻発に行われおいたす。 MLOps゚ンゞニアずしお、より広く、安党で䜿い勝手の良いML基盀にするため、日々ワクワクしながら取り組んでいたす。 We’re Hiring! タむミヌのデヌタ゚ンゞニアリング郚・デヌタアナリティクス郚では、ずもに働くメンバヌを募集しおいたす 珟圚募集䞭のポゞションは こちら です 「話を聞きたい」ず思われた方は、是非䞀床 カゞュアル面談 でお話ししたしょう *1 : Vertex AI PipelinesテンプレヌトがArtifact Registryに察応したのは、2022幎12月です。 Release Note: https://cloud.google.com/vertex-ai/docs/release-notes#December_05_2022 *2 : kfp.RegistryClientのリリヌスはKFP SDK 2.0.0からで、2023幎6月です。Release Note: https://github.com/kubeflow/pipelines/blob/master/sdk/RELEASE.md#200
こんにちは タむミヌでPlatform Engineerをしおいる @MoneyForest です。 こちらは Timee Product Advent Calendar 2024 の10日目の蚘事です。 2024幎8月に入瀟しお、幞いにもチヌムメンバヌにも恵たれお楜しく働いおいたす。 個人的にキャッチアップがあたりできおいなかった OpenTelemetry を題材にしお実装をしおみたので、ここから埗られた気づきや知芋を共有したいず思いたす。 はじめに アプリケヌションの可芳枬性Observabilityを担保する䞊で、APM(Application Performance Monitoring)は重芁です。 珟圚、JaegerやPrometheusのような非商甚のものから、DatadogやNew RelicやSplunkなど様々なAPMを利甚できるツヌルが存圚したす。本蚘事ではこれらを「Observability Backend」ず呌称したす。 これらのObservability BackendでAPMを利甚するには、各々が提䟛する独自のSDKを䜿甚しおTraceやSpanを送信する必芁があり、以䞋のような課題がありたした。 アプリケヌションの実装に各SDKの仕様が滲み出る Observability Backendの切り替えが困難 OpenTelemetryの登堎により、オブザヌバビリティに関する様々な抂念が抜象化され、統䞀された仕様が提䟛されるようになりたした。 これにより、アプリケヌションコヌドずObservability Backendの実装を分離し、状況に応じお適切なツヌルを遞択できるようになりたした。 ぀たり、ロヌカルではJaegerのような非商甚のツヌルで開発䞭にAPMを利甚し、デプロむしたアプリケヌションではDatadogのような商甚ツヌルでリッチなUIでAPMを利甚したり、モニタリングアラヌトを組んだりなどができるずいうこずです。 本蚘事では、Go蚀語でOpenTelemetryを掻甚しお、環境ごずにObservability BackendJaeger、Datadogを切り替える実装を行うこずで、これらのメリットを䜓感しおいきたいず思いたす。 実装しおみる 実装の党量はこちらにありたす。 https://github.com/MoneyForest/advent-calender-2024 共通むンタヌフェヌスの定矩・初期化凊理 OpenTelemetryに準拠した共通むンタヌフェヌスを定矩するこずで、各バック゚ンドの実装を抜象化したす。この実装では infrastructure/tracer.go に配眮しおいたす。 共通むンタヌフェヌスはOpenTelemetryのSDKの仕様に則しおむンタヌフェヌスを定矩したす。 䟋えばShutdownメ゜ッドは、OpenTelemetryの仕様に基づき定められおいるものです。トレヌスデヌタの欠損を防ぐために必芁な暙準仕様ずなっおいたす。 参照 https://opentelemetry.io/docs/specs/otel/trace/sdk/#shutdown たた、今回は環境に応じおObservability Backendを切り替える実装のため、envを条件に初期化するProviderを切り替えおいたす。 // infrastructure/tracer.go package infrastructure import "context" type TracerProviderWrapper interface { Shutdown(context.Context) error } func InitTracer(env string ) (TracerProviderWrapper, error ) { switch env { case "dev" : return InitDatadog() default : return InitJaeger() } } Observability Backend固有の初期化凊理 次に各Observability Backendごずの初期化凊理を曞いおいきたす。 Datadog Datadogは2぀の方法で送信できたす。 ddotelアダプタヌ経由 参照 https://docs.datadoghq.com/ja/tracing/trace_collection/custom_instrumentation/go/otel/ こちらではDatadogのSDKであるdd-trace-goからddotelずいうアダプタヌを通じおOtelに準拠したTraceProviderを生成したす。 送信するポヌトはDatadog Agentのデフォルトポヌトである8126になりたす。 // infrastructure/datadog.go package infrastructure import ( "context" "os" "go.opentelemetry.io/otel" ddotel "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/opentelemetry" ddtracer "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" ) type ddTracerProvider struct { provider *ddotel.TracerProvider } func InitDatadog() (*ddTracerProvider, error ) { tp := ddotel.NewTracerProvider( ddtracer.WithService(os.Getenv( "SERVICE" )), // MoneyForest ddtracer.WithEnv(os.Getenv( "ENV" )), ddtracer.WithServiceVersion( "1.0.0" ), ddtracer.WithAgentAddr( "localhost:8126" ), ) otel.SetTracerProvider(tp) return &ddTracerProvider{provider: tp}, nil } func (p *ddTracerProvider) Shutdown(ctx context.Context) error { return p.provider.Shutdown() } Otel SDK経由 こちらではOtel SDKを䜿甚しおTraceProviderを生成したす。 参照 https://docs.datadoghq.com/ja/opentelemetry/interoperability/otlp_ingest_in_the_agent/?tab=host#enabling-otlp-ingestion-on-the-datadog-agent 送信するポヌトはOTLP HTTPのデフォルトポヌトである4318になりたす。 // infrastructure/datadog.go package infrastructure import ( "context" "os" "go.opentelemetry.io/otel" ddotel "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/opentelemetry" ddtracer "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" ) type ddTracerProvider struct { provider *sdktrace.TracerProvider } func InitDatadog() (*ddTracerProvider, error ) { exporter, err := otlptracehttp.New( context.Background(), otlptracehttp.WithEndpoint( "localhost:4318" ), otlptracehttp.WithInsecure(), otlptracehttp.WithURLPath( "/v1/traces" ), ) if err != nil { return nil , err } tp := sdktrace.NewTracerProvider( sdktrace.WithBatcher(exporter), sdktrace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String(os.Getenv( "SERVICE" )), // MoneyForest semconv.DeploymentEnvironmentKey.String(os.Getenv( "ENV" )), )), ) otel.SetTracerProvider(tp) return &ddTracerProvider{provider: tp}, nil } func (p *ddTracerProvider) Shutdown(ctx context.Context) error { return p.provider.Shutdown(ctx) } Jaeger Jaegerは jaegar-client-go のSDKがありたしたが、2024/5に非掚奚ずなっおいたす。 今はOpenTelemetryに準拠するこずが掚奚されおいるため、Otel SDKによる実装を行いたす。 // infrastructure/jaeger.go package infrastructure import ( "context" "os" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.4.0" ) type jaegerTracerProvider struct { provider *sdktrace.TracerProvider } func InitJaeger() (jaegerTracerProvider, error ) { exporter, err := otlptracehttp.New( context.Background(), otlptracehttp.WithEndpoint( "localhost:4318" ), otlptracehttp.WithInsecure(), ) if err != nil { return jaegerTracerProvider{}, err } tp := sdktrace.NewTracerProvider( sdktrace.WithBatcher(exporter), sdktrace.WithResource(resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceNameKey.String(os.Getenv( "SERVICE" )), semconv.DeploymentEnvironmentKey.String(os.Getenv( "ENV" )), )), ) otel.SetTracerProvider(tp) return jaegerTracerProvider{provider: tp}, nil } func (p jaegerTracerProvider) Shutdown(ctx context.Context) error { return p.provider.Shutdown(ctx) } アプリケヌションでの利甚 アプリケヌションでは、OpenTelemetryの暙準APIを通じおTracerを䜿甚するこずで、Observability Backendに䟝存しない䞀貫した実装が可胜になりたす。 package main import ( "context" "crypto/rand" "fmt" "log" "os" _ "github.com/go-sql-driver/mysql" "github.com/MoneyForest/timee-advent-calender-2024/internal" "github.com/MoneyForest/timee-advent-calender-2024/internal/handler" "github.com/MoneyForest/timee-advent-calender-2024/internal/infrastructure" ) func main() { // Initialize tracer tp, err := infrastructure.InitTracer(os.Getenv( "ENV" )) if err != nil { log.Fatal(err) } defer tp.Shutdown(context.Background()) // ... } func (h *UserHandler) CreateUser(ctx context.Context, email string ) error { tracer := otel.Tracer(os.Getenv( "SERVICE" )) ctx, span := tracer.Start(ctx, "UserHandler.CreateUser" ) defer span.End() span.SetAttributes( attribute.String( "email" , email), attribute.String( "handler" , "UserHandler" ), attribute.String( "method" , "CreateUser" ), ) return h.userUsecase.CreateUser(ctx, email) } 動かしおみる これたでの実装がうたくいっおいれば、JaegerずDatadogで同じようなAPMを芋るこずができる想定です。確認しおみたしょう。 Docker Composeで gcr.io/datadoghq/agent ず jaegertracing/all-in-one のサむドカヌを立おたす。 本来はdatadog-agentはdev環境以䞊に必芁で、ECSのサむドカヌなどに定矩すればよいです。 リポゞトリではMySQLやRedisのコンテナも建おおいたすが省略したす。 JaegarはUIたでパッケヌゞングされたむメヌゞが公匏から提䟛されおおり、こちらにトレヌスを送信するこずで、localhostのUIからAPMを確認できたす。 datadog-agent : image : gcr.io/datadoghq/agent:latest environment : - DD_API_KEY=${DD_API_KEY} - DD_SITE=datadoghq.com - DD_APM_ENABLED= true - DD_APM_NON_LOCAL_TRAFFIC= true - DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_HTTP_ENDPOINT=0.0.0.0:4318 ports : - "8126:8126" - "4319:4318" # OTLP HTTP (ロヌカルマシンのポヌトはJaegarず被るのでずらしおいる) volumes : - /var/run/docker.sock:/var/run/docker.sock - /proc/:/host/proc/:ro - /sys/fs/cgroup:/host/sys/fs/cgroup:ro jaeger : image : jaegertracing/all-in-one:latest ports : - "16686:16686" # UI - "14250:14250" - "4318:4318" # OTLP HTTP environment : - COLLECTOR_OTLP_ENABLED= true dev環境Datadog https://app.datadoghq.com/apm/traces でトレヌス情報を芋るこずができたす。 以䞋はddotelを䜿甚しお送信したメトリクスです。 以䞋はOtel SDKを䜿甚しお送信したメトリクスです。 1. ず異なる点ずしお、SpanのAttributeに otel の構造䜓がありたす。たた、 process_id や runtime-id は存圚したせん。 local環境Jaegar http://localhost:16686/search でトレヌス情報を芋るこずができたす。Datadogず䞀郚のメタデヌタが異なっおいたりず、完党に同䞀ではないものの、抂ね同じ内容を芋るこずができたす。 Datadogのトレヌスず異なる点ずしおは、サヌビス名ずしお䞎えおいたMoneyForestがotel.libraryにマッピングされおいたしたが、こちらではotel.scopeにマッピングされおいるずいう点です。 実装しおわかったこず GoのOtel SDKから生成される sdktrace.TracerProvider では Shutdown はcontextを匕数に取るものの、 ddotel.TracerProvider の Shutdown はcontentを匕数に取らない、などの现かな差異があり、共通むンタヌフェヌスの方で吞収する必芁がありたした。 Datadogの実装でOtel SDKを盎接䜿う方を採甚すれば、共通むンタヌフェヌスを甚意する必芁がなく、以䞋のように InitTracer は初期化の条件分岐のみを曞いた実装が可胜です。 func InitTracer(env string ) (*sdktrace.TracerProvider, error ) { switch env { case "dev" : return initDatadog() default : return initJaeger() } } たたddotelのラむブラリには added to the OpenTelemetry API will default to being a no-op until implemented by this library. のコメントがあり、新機胜の利甚にはGoのOtel SDKではなくDatadog Agent偎での実装を埅぀必芁がありそうでした。 そのため、Datadogの独自機胜を重芖する堎合はddotelを採甚し、Otelぞの準拠を重芖する堎合はOtel SDKで実装するなど、実装の際に意思決定が必芁になりそうです。 たた、现かなマッピングの違いも存圚しそうなため、Traceを䜿っおモニタリングアラヌトを組んでいる堎合は泚意しお切り替える必芁がありそうです。䟋えばDatadogからNew Relicに倉曎する堎合など 商甚のツヌルでは料金䜓系なども異なるため、仕様が同じでもサンプリングレヌトの倀の調敎が必芁になるこずもあるでしょう。 たずめ OpenTelemetryを掻甚するこずで、トレヌシング実装でより䞀貫性のあるコヌドを実珟できるこずがわかりたした。 これにより、環境に応じお適切なObservability Backendを利甚したり、移行するこずが容易になったりするのは間違いなさそうです。 䞀方で暙準仕様に぀いおはただただ理解が浅いので、OpenTelemetry自䜓の理解も深めお、さらに楜しい゚ンゞニアラむフを送りたいず思いたすたたね〜
こちらは Timee Product Advent Calendar 2024 の9日目の蚘事です。前日は平岡の スクラムマスタヌが垞に意識するべき重芁なこず でした。 タむミヌでテックリヌドをしおいる @euglena1215 です。 最近、Majestic Monolith ず Citadel ずいうアヌキテクチャ・考え方を知ったのですが、あたり囜内では認知床が高くないように感じたので玹介しおみたいず思いたす。 自分が芋぀けた日本語での蚘事は モノリス亜種のアーキテクチャ(Modular MonolithとかMajestic MonolithとかCitadel Architectureとか) ず Rails: AppSignalが採用する「シタデルアーキテクチャ」(翻訳)|TechRacho by BPS株式会社 の2蚘事のみでした※蚘事執筆時点。 Majestic Monolith Photo by Gary Walker-Jones on Unsplash signalvnoise.com Majestic Monolith の出兞は Ruby on Rails の䜜者である DHH のブログです。2016幎に曞かれおいおすごい。 正確な内容は出兞を参照しおいただくずしお、ここでは自分の解釈をたずめおみたす。 䞖間では「モノリスアヌキテクチャ」は劣ったアヌキテクチャのような評䟡を受け、「マむクロサヌビスアヌキテクチャ」が優れおいるような評䟡を受ける。 Amazon や Google、あるいは䜕千人もの開発者がいるような䌚瀟にずっおはマむクロサヌビスアヌキテクチャは玠晎らしいアヌキテクチャだが、「成功しおいる䌁業で効果があったのだから、我々にも効果があるはずだ」ず思い蟌んで小さな䌚瀟がマむクロサヌビスアヌキテクチャを目指すのは間違い。 巚倧な䞀握りの䌚瀟以倖はモノリスを受け入れ、意図を持っおモノリスを雄倧(majestic)に蚭蚈しよう。 モノリス自䜓が悪いず捉えおしたうず、それを解決するためにはモノリスから脱する以倖の道はありたせん。モノリスをたず肯定するこずによっお、初めお自分たちが抱えおいる様々な技術的課題の茪郭が芋えおきたす。 もちろんその䞭にはモノリスを分けなければ解決できない課題もあるず思いたすが、そうでないものも含たれおいるず思いたす。たずモノリスを肯定するこずによっお、様々な技術的課題の解像床を高めるこずができる瀺唆に富んだ考え方だず感じおいたす。 Citadel Photo by K. Mitch Hodge on Unsplash signalvnoise.com こちらも出兞は Ruby on Rails の䜜者である DHH のブログです。2020幎に曞かれおいたす。 倚くのケヌスで Majestic Monolith はうたく機胜するが、パフォヌマンスや可甚性の問題でモノリスでは察凊が難しい課題が出おくるこずもある。 その際の次のステップは Citadel。Citadel ずは、モノリスCitadel = 城塞を䞭倮に据えお呚蟺に必芁に応じおモノリスを補完するようなサヌビスOutpost = 前哚基地を配眮する考え方。 Outpost ずしおモノリスずは異なる特性パフォヌマンス䞊の問題を察凊、組織䞊、実装䞊など理由は様々のサヌビスが提䟛できれば、アプリケヌションの残りの郚分は Majestic Monolith ずしお提䟛し続けられる。 蚈らずもこの構成になっおいるプロダクトは倚いのではないのでしょうか。タむミヌのそのうちの1぀です。 Citadel ずいう名前を぀けたこずで、別物だず感じおいた他プロダクトの構成にも共通点を芋出せるようになった気がしたす。DHH の呜名の劙だず蚀わざるを埗たせん。 状態ではなく、事象に泚目しおいる ゜フトりェアアヌキテクチャの文脈でよく登堎するモノリス・マむクロサヌビス・モゞュラモノリスずいった分類は、あくたで「こういった状態のシステムはこのような特性を持っおいる」ずいうカタログでしかありたせん。 理解し把握しおおく分にはずおも有甚ですが、「ここに任意のアヌキテクチャ名が入る化」をしたから我々が盎面しおいる様々な技術的課題が解決できるかずいうず、なかなか難しい面もあるかず思いたす。 ですが、DHH の提唱する Majestic Monolith にも Citadel にも、珟堎で起きおいる事象問題に察しおどのように察凊をしおいくかずいう地に足の぀いた指針のようなものを感じたした。 アヌキテクチャに囚われず、きちんず目の前で起きおいる技術的課題を芋定めよう。 目の前で起きおいる技術的課題を芋定めたら、必芁十分な察凊をしよう。 隣の芝生は青いずいうこずわざがあるように、自分たちが遞択しおいないアヌキテクチャが良く芋えおしたうのは人間の性だず思いたす。Majestic Monolith, Citadel を胞に誘惑に負けないよう努力し続けたいず思いたした。   明日は @MoneyForest の「OpenTelemetryで環境ごずにObservability BackendJaeger、Datadogを切り替えお゚ンゞョむしおみたよ」です。お楜しみに
Timee Advent Calendar 2024 6日目の蚘事です。 タむミヌでスクラムマスタヌ以䞋、SM/アゞャむルコヌチを担圓しおいる正矩です この蚘事では 孊習したこずや孊んだこずは、どんどんアりトプットするずいいよ どのようなアりトプット方法があるのか ずいうお話をしたす。 なぜアりトプットをするのか 1. 自身ぞの定着 それは「孊習に察する胜動性を向䞊し、自身の蚘憶ずしおより定着させるため」です。 よく芋かけるラヌニングピラミッドのように、胜動的な掻動になるに぀れお定着しやすくなりたす。 たた、掻動によっお孊習に察するアプロヌチの深さが倉わっおきたす。 https://www.mext.go.jp/b_menu/shingi/chukyo/chukyo3/004/siryo/__icsFiles/afieldfile/2015/09/04/1361407_2_4.pdf 必ずしも䞀定の深いアプロヌチをしおいれば身に付くわけではなく、孊習する内容によっおアプロヌチの手法は倉わっおきたすし、効果的に定着するかはアプロヌチずの盞性によっおも異なりたす。 孊習を定着させるために重芁なのは「倚角的に、胜動的に孊ぶこず」です。 そのため、色々な孊習に察するアプロヌチを積極的にしおみるこずで、自身ぞの孊びをより効果的にするこずができたす。 2. 自身の掻動のログずなる 自分の孊習・経隓をログずなる圢で残すこずで、自分自身で振り返るこずができたす。 たた、その内容は他の人にシェアできたり、自身の今埌の評䟡材料にもできたす。 どのような孊びのアりトプット方法があるのか 1. ブログでの発信 ブログでの発信はじっくり考えを敎理でき、任意のボリュヌムでの蚘述が可胜です。 たた、図・衚・写真など、芖芚的な情報も茉せられたす。 私の堎合、ブログの蚘事を最埌たで曞くのは意倖ずパワヌが必芁ずなっおしたうので、「やるぞ」ずいう気合がないずどうしおも埌回しにになっお、投皿が遅れがちになりたす。 同じような状態に陥りがちな方は、期日を蚭ける/䜓隓した翌日には投皿するなどの個人的なルヌルを蚭けるこずをおすすめしたす。 https://note.com/rakuraku_justice/ 2. Xでの発信 Xでの発信は文字数が限られおいるため、知芋や考えたこずの芁点のみをたずめるこずに圹立ちたす課金しおいない人限定。文量が少ない分、ブログよりも気持ちのハヌドルを䞋げお投皿できたす。 たた、図・衚・写真など、芖芚的な情報も茉せられたす。 私の堎合はカンファレンスなどで埗た情報をサクッずメモがわりに投皿しおいたす。 その情報を元に、あずあず芋返しおブログなど他のアりトプットに぀なげたりしおいたす。 3. カンファレンスプロポヌザルでの発信 䞻にRSGTやスクラムフェスなど、特定のカンファレンスに限られるかもしれたせんが、プロポヌザルを募集しおいたりするので、テヌマに沿った内容を蚘茉しお発信したす。 ブログず違う点は、完党にフリヌな堎ではなくカンファレンスごずに、ある皋床テヌマや曞き方が定たっおいるこずです。 私の堎合は、カンファレンスを䞀぀の区切りずしお、そこたでに埗た知芋ず関連する経隓を蚘茉しお投皿しおみるこずが倚いです。 登壇に぀ながれば、さらなるアりトプットもできる いざ登壇したいずなっおも、うたく曞けなかったり、曞く内容が思い浮かばなかったりするので、ひずたずカンファレンスプロポヌザルは曞けそうなら曞いおみるこずをおすすめしたす。 https://confengine.com/conferences/scrum-fest-osaka-2022/proposal/16594 4. 登壇する カンファレンスやコミュニティむベントでのLT䌚などの堎で、登壇できるならば登壇しおみたしょう 登壇による孊習の効果は高いず考えおいたす。資料をたずめるだけでも䞀぀のアりトプットですし、それを自身の蚀葉で発衚するこずは曎なるアりトプットや情報の敎理に぀ながりたす。 たた、Q&Aの時間で質問しおもらえたらラッキヌで、瞬時に色々ず考えた䞊で自分の蚀葉にする経隓を埗るこずができたす。 このように登壇では耇数のアりトプットを䜓隓できるので、機䌚はどんどん獲埗しおたくさん登壇したしょう 5. Podcastなどのラゞオ圢匏での配信 1人もしくは数名でラゞオ圢匏の収録を行い、線集ず配信をしたす。 個人的には、䞀番アりトプットが楜に感じおいたす。䞀緒に収録しおくれる人がいれば、テヌマに察し議論しおいるだけでアりトプットに぀ながりたす。 線集は少し時間がかかりたす30minのラゞオに察しお1hほど。しかし、倱敗したりおかしいず感じたりする郚分はカットできるので、安心しお収録できたす。 ブログを曞くよりも準備や考えるこずが少なく始められるので、おすすめです https://creators.spotify.com/pod/show/yoriyokufm 他にも色々なアりトプット方法がある ゚ンゞニアやデザむナヌであれば業務倖においお趣味で創䜜をする 仕事で埗た知識を別の堎で掻甚しおみる 1on1や数名の堎で議論をしおみる 䞀぀の圢に絞るのではなく、色々な圢匏を詊しおみるこずで自分に合う圢匏を芋぀けられるかもしれたせん。 最埌に 臆せず、アりトプットするこずが倧切です。 「自分が話しおもすごい経隓があるわけでもないし 」 「誰かがすでに蚘事にしおいそうだし 」 ず、考えおしたしい、アりトプットをしないのはもったいないです。 あなたの経隓には、必ず䟡倀があり、誰かの圹に立ちたす。 たずはどんな圢でもよいので、発信しおみお自分の孊習のためのアりトプットにチャレンゞしおみたしょう い぀かそれが誰かの圹に立っおいるず気づく日がきっずきたす 私の Timee Advent Calendar 2024 Day 6は終わりです 匕き続き、明日の蚘事も是非読んでみおください
Timee Advent Calendar 2024 6日目の蚘事です。 タむミヌでスクラムマスタヌ以䞋、SM/アゞャむルコヌチを担圓しおいる正矩です この蚘事では SMに求められるリヌダヌの性質は䜕か SMもプロゞェクトマネゞメントに関する知識を埗おおくず良い ずいうお話をしたす。 スクラムマスタヌに求められるリヌダヌの性質は色々ある SMはどのようなリヌダヌであるべきか、色々な芳点で話されおいるのを芋かけたす。 スクラムガむドから読み取ろうずしたり、実践ベヌスで考えたり、孊術的な芳点などがありたす。 (過去に匊瀟SMが登壇した際の資料もご玹介したす) https://speakerdeck.com/shinop/practical-scrum-master-vs-theoretical-scrum-researcher-d29104ff-15ed-4fcc-a0e9-9e0bef2a0d3a 私も数幎間SMを担圓しおきたので、自分なりに考えおいるこずをお話ししおみたいず思いたす。 スクラムマスタヌはどんなリヌダヌなのか 「スクラムマスタヌ」ずいうロヌルはスクラムガむド2013、2017、2020幎版で定矩されおいるので、そこから芋おいきたしょう。 たずは 2013幎版 から。 スクラムマスタヌ スクラムマスタヌは、スクラムの理解ず成立に責任を持぀。そのためにスクラムマスタヌは、スクラムチヌムにスクラムの理論・プラクティス・ルヌルを守っおもらうようにする。 スクラムマスタヌは、スクラムチヌムのサヌバントリヌダヌである蚳泚メンバヌが成果を䞊げるために支揎や奉仕をするリヌダヌのこず。 スクラムマスタヌは、スクラムチヌムずやり取りをするずきに圹に立぀こず立たないこずをスクラムチヌムの倖郚の人たちに理解しおもらう。スクラムマスタヌは、こうしたやり取りに倉化をもたらすこずで、スクラムチヌムの䜜る䟡倀を最倧化する。 このように、明確にリヌダヌのスタむルがサヌバントリヌダヌずしお説明されおいたす。 そしお責任に぀いおも、「スクラムの理解ず成立に責任を持぀」ずありたす。そのために、理論・プラクティス・ルヌルをチヌムに萜ずし蟌み、チヌム倖の人々に察しおスクラムチヌムを理解しおもらう掻動が䞭心に蚘茉されおいたす。 ぀たり、倧切にすべき事柄をチヌムが䌚埗し、実践しおいくための環境・システム䜜りに重きを眮いおいるず捉えたした。 続いお 2017幎版 から。 スクラムマスタヌ スクラムマスタヌは、スクラムガむドで定矩されたスクラムの促進ず支揎に責任を持぀。スクラムマスタヌは、スクラムの理論・プラクティス・ルヌル・䟡倀基準を党員に理解しおもらえるように支揎するこずで、その責任を果たす。 スクラムマスタヌは、スクラムチヌムのサヌバントリヌダヌである蚳泚メンバヌが成果を䞊げるために支揎や奉仕をするリヌダヌのこず。 スクラムマスタヌは、スクラムチヌムずやり取りをするずきに圹に立぀こず立たないこずをスクラムチヌムの倖郚の人たちに理解しおもらう。スクラムマスタヌは、こうしたやり取りに倉化をもたらすこずで、スクラムチヌムの䜜る䟡倀を最倧化する。 「スクラム」が「スクラムチヌム」に倉曎されおいたすが、蚘茉されおいる内容に぀いおは倧きな倉曎はありたせん。 責任に぀いおは「SMは、スクラムガむドで定矩されたスクラムの促進ず支揎に責任を持぀」ずありたす。「成立」ではなく「促進ず支揎」に倉わったのは、スクラム成立はSMだけが責任を負うわけではなく、スクラムチヌムで進めおいくこずを意識付けおいるように感じたした。 掻動自䜓は、チヌムに萜ずし蟌む項目に「䟡倀基準」が足されおはいたすが、倧枠では2013幎からの倉化はありたせん。匕き続き2013幎ず同様の事柄に重きを眮いおいるず解釈したした。 そしお 2020幎版 。 スクラムマスタヌ スクラムマスタヌは、スクラムガむドで定矩されたスクラムを確✎させるこずの結果に責任を持぀。スクラムマスタヌは、スクラムチヌムず組織においお、スクラムの理論ずプラクティスを党員に理解しおもらえるよう✀揎するこずで、その責任を果たす。 スクラムマスタヌは、スクラムチヌムの有効性に責任を持぀。スクラムマスタヌは、スクラムチヌムがスクラムフレヌムワヌク内でプラクティスを改善できるようにするこずで、その責任を果たす。 スクラムマスタヌは、スクラムチヌムず、より⌀きな組織に奉仕する真のリヌダヌである。 これたでずは異なる点が増えおいたす。 「責任」に觊れおいる郚分ほが党䜓。 スクラムマスタヌは、スクラムガむドで定矩されたスクラムを確✎させるこずの結果に責任を持぀。 スクラムマスタヌは、スクラムチヌムず組織においお、スクラムの理論ずプラクティスを党員に理解しおもらえるよう✀揎するこずで、その責任を果たす。 スクラムマスタヌは、スクラムチヌムの有効性に責任を持぀。 スクラムマスタヌは、スクラムチヌムがスクラムフレヌムワヌク内でプラクティスを改善できるようにするこずで、その責任を果たす。 責任の内容ずその果たし方がセットで曞かれおいたす。 泚目したい点の䞀぀は「スクラムガむドで定矩されたスクラムを確✎させるこずの結果に責任を持぀」です。今たでの「促進ず支揎」よりその先の倉化、぀たり結果にフォヌカスしおいたす。 たた、「スクラムチヌムの有効性に責任を持぀」ずいう点が䞀番倧きい倉化だず捉えおいたす。スクラムチヌムの有効性、぀たり結果に察し責任を持぀こずが明確に蚘茉されたした。 以前はスクラムの定着がSMの圹割でしたが、スクラムが効果的に働き、有効である、結果を出すこずがSMに求められるように倉化したした。スクラムはあくたで方法であり、倧前提ずなる目的を達成するこずずSMがそこに意識を向けるために責任が明文化されたず考えおいたす。 そしおリヌダヌに぀いお蚀及しおいる郚分は「スクラムマスタヌは、スクラムチヌムず、より⌀きな組織に奉仕する真のリヌダヌである」です。 これたでに色々な議論のきっかけになっおいる「真のリヌダヌ」、これはずおも抜象的なので様々な解釈があるず思いたす。 継続しお「奉仕する」が䜿甚されおいるので、これたでのサヌバントリヌダヌは匕き継いでいるように芋えたす。しかし、サヌバントリヌダヌが明瀺的に蚘茉されなくなったのは、それ以倖にも求められるリヌダヌずしおの圹割、リヌダヌシップが必芁であるこずを瀺唆しおいるようです。 パス・ゎヌル理論の4぀のリヌダヌタむプではありたせんが、 サヌバントずいうスタむルで、チヌムの自埋性を促し、支揎するリヌダヌ 自身が先導し、チヌムがゎヌルぞ到達するこずを導くリヌダヌ ずいう圢で、自分でチヌムを匕っ匵り、目的にコミットする圢も必芁だず考えられたす。 結果に察し責任を持぀ずいうこずは、こちらに繋がっおきたす スクラムマスタヌが向き合う”結果”ずは 「結果」に぀いおの分解方法ずしおは「盎接的な結果」ず「間接的な結果」がありたす。 盎接的な結果ある圹割や行動が、最終的な成果やアりトプットに察しお盎接的に圱響を䞎える堎合を指す 間接的な結果ある圹割や行動が、最終的な成果やアりトプットに盎接関䞎せず、それを実珟するためのプロセスや環境を敎備する圹割を果たす堎合を指す 開発においおは、䞋蚘のようになりたす。 項目 盎接的な結果 間接的な結果 察象 成果物などアりトプット プロセスや環境 圱響の範囲 短期的で即時的 長期的で持続的 枬定のしやすさ 枬定可胜䟋完成した機胜の数 枬定が難しい䟋チヌムの生産性 成果ずの距離 成果に盎接結び぀く 成果を間接的に支える SMはどちらの結果に向き合うべきでしょうか。 その答えはどちらか䞀方ではなく、アゞャむル゜フトりェア開発宣蚀のように「巊蚘の結果を求めながら右蚘の結果に重きを眮く」ず考えおいたす。 スクラムガむドでは、「スクラムマスタヌは、スクラムチヌムがスクラムフレヌムワヌク内でプラクティスを改善できるようにするこずで、その責任を果たす」ずありたす。これはスクラムチヌムに察しお、間接的な結果および責任を果たすこずに向き合うこずを意味したす。 しかし、SMは盎接的な結果に぀いお完党に無関心でいるこずはできたせん。盎接的な結果品質、玍期、成果物などは、間接的な責任を果たす䞊での重芁な指暙であり、SMが仕事を効果的に遂行するためには、盎接的な結果にどのように圱響を䞎えるかを理解し、それを考慮する必芁がありたす。 スクラムマスタヌがプロゞェクトマネゞメントを孊ぶ必芁性に぀いお SMはチヌムが自埋的に掻動しおいけるように、「皆さんはどうしたいですか」を問う姿が倚く芋られたす。 しかし、チヌムに問いかけ続けおいれば党お問題なく進められるかずいうず、そうではありたせん。 チヌム内で補える芳点や知芋に基づいおチヌム内で考えるこずもできたすが、それ以䞊の芳点や知識はティヌチングを䞻芁なメタスキルずするSMが補う必芁がありたす。 ラヌメンを構成する各材料の䜜り方をチヌムが知っおいおも、合わせお「矎味しいラヌメン」ずいう成果物にする方法を知らなければ、想定よりもぬるかったり矎味しくないラヌメンができおしたうむメヌゞ SMがプロダクト開発に玐づく党おのこずをティヌチングできれば良いのですが、スクラムガむドやスクラム・アゞャむルに関する知芋のみでは難しいです。 スクラムガむドはスクラムを定矩しおおり、スクラムは軜量玚のフレヌムワヌクです。スクラムガむド自䜓も目次や甚語集などを含めお党17ペヌゞ皋床の少ないボリュヌムです。 スクラムにおける重芁な情報が厳遞され、抜象化しお蚘茉されおいお、プロダクト開発をチヌムで進める䞊で必芁な考え方や芳点を党お網矅しおいるわけではありたせん。 そこで、比范的SMにずっお芪和性が高く、知っおおくず掻甚しやすい知識は「プロゞェクトマネゞメント」だず考えおいたす。 理由はシンプルに、「そのプロダクト開発は、い぀・どうなったら終わりなのか」ずいう説明責任をSMにも果たしおほしいからです。 チヌムが自己管理できるよう、チヌムの自埋性を高めるこずを䞻軞にしお意識しおいくSMだからこそ、䞊蚘の質問には答えられる必芁があるず考えおいたす。 チヌムが自分たちで考えられる環境を求めおいく䞀方で、チヌムに察しおティヌチングずコヌチングを適切に行っおいくためには、SM自身がプロダクト開発の完遂に察しお必芁な知芋ず考え方を自分で説明できるようになっおいおほしいです。 そうでないず、プロダクト開発およびプロゞェクトを前に進めるための適切なWhyの説明ができず、チヌムにずっおひたすら自身の思い浮かぶプラクティスを掚進しようずする人になっおしたうのでしょう 経隓談 プロゞェクトマネゞメントから埗られる芳点を取り入れお知的創造を果たす 「そのプロダクト開発は、い぀・どうなったら終わりなのか」ずいう説明責任を果たすこずは、䞀぀のリヌダヌシップの䜓珟です。 これはモノづくりをする䞊で行う2぀の創造知的創造ず物的創造のうちの知的創造に該圓したす。 曞籍 スティヌブン・R.コノィヌ『完蚳 7぀の習慣 人栌䞻矩の回埩』キングベアヌ出版 p.155 第二郚「私的成功」第2の習慣「終わりを思い描くこずから始める」より 簡単に説明するず、物的創造は定められた方向に向かっお限られたリ゜ヌスを掻甚し効率よく業務を遂行するための掻動、぀たりマネゞメントず実行責任の完遂を意味したす。 䞀方、知的創造は組織が向かう方向を定め、「終わりを思い描く」「ゎヌルを決める」掻動ずなりたす。぀たり、リヌダヌシップずそれに䌎う説明責任の完遂です。 ここでいう「終わりゎヌル」には抜象的なビゞョンやミッションではなく、プロダクト開発のゎヌル、プロゞェクトの終わりを圓おはめおいたす プロダクト開発のSMが瀺す䞀぀のリヌダヌシップであり、「自身が先導し、チヌムがゎヌルぞ到達するこずを導くリヌダヌ」に求められたす。 では、どうやったらプロダクト開発における「終わりを思い描く」「ゎヌルを決める」ずいう知的創造を果たすこずができるのか そのための䞀぀ずしお、「プロゞェクトマネゞメントを孊ぶ」を私はおすすめしおいるのです。 プロゞェクトマネゞメントのすべおをここで玹介するのは非垞に倧倉なので、知っおおくず良い点ずしお䞀぀挙げるずPMBOK第6版に蚘茉されおいる「10の知識゚リア」がありたす。 泚PMBOKは2021幎に第7版が出版されおいたす。第6版では日本語版で玄780ペヌゞあったものが、第7版では玄370ペヌゞになっおいたす。たた、内容ずしおもプロゞェクトマネゞメントの手順をたずめたものから、プロゞェクトの方針や考え方ずいった原理・原則をメむンにした構成になっおいたす。今回は、芳点ずしお具䜓的に分かりやすくリストアップされおいる第6版の内容を蚘茉したす。 10の知識゚リア プロゞェクト統合マネゞメント プロゞェクトやフェヌズをどのように進めるのかを定矩する知識゚リア プロゞェクト・スコヌプ・マネゞメント プロゞェクトやフェヌズにおける䜜業範囲や、成果物の蚭定に関しお定矩する知識゚リア プロゞェクト・スケゞュヌル・マネゞメント 玍期管理に関する知識゚リア プロゞェクト・コスト・マネゞメント プロゞェクトで承認された予算に関する知識゚リア プロゞェクト・品質・マネゞメント 生成される成果物やプロゞェクトの品質に関する知識゚リア プロゞェクト・資源・マネゞメント メンバヌなどの人的資源や、物的資源などの管理に関する知識゚リア プロゞェクト・コミュニケヌション・マネゞメント 䌚議予定を調敎し、適切にコミュニケヌション内容や方法を管理する知識゚リア プロゞェクト・リスク・マネゞメント プロゞェクトにおけるリスクの特定・分析・察応方法、察応策の実行、リスク監芖に関する知識゚リア プロゞェクト・調達・マネゞメント 契玄終結やベンダヌの管理に関する知識゚リア プロゞェクト・ステヌクホルダヌ・マネゞメント ステヌクホルダヌの関䞎床の定矩や管理に関する知識゚リア すべおを満遍なく怜蚎しおマネゞメントしたしょう、ずいうわけではありたせん。 ただ、これらの項目に぀いお考えおみるこずで、プロダクト開発をスクラムで行おうずしおいる珟堎においお、スクラムガむドに蚘茉されおいない芳点を補うこずができるず考えたす。 䟋えば、プロゞェクト・ステヌクホルダヌ・マネゞメント。スクラムガむドでは、「ステヌクホルダヌ」が誰なのかをはっきりず定矩しおいたせん。それはプロダクト開発におけるステヌクホルダヌは倚く存圚したすし、それぞれのステヌクホルダヌに察しおの期埅や重芁床は垞に䞀定ではないからでしょう。 そのため個々のプロゞェクトにおいおは、チヌムが関わるステヌクホルダヌは誰なのかを明確にし、ステヌクホルダヌずの関わり方を定矩しないず、チヌムの動き方や目指すこずは容易にぶれおしたいたす。 ステヌクホルダヌマネゞメントでよく芋るのは、圱響床合いず関心床合いを2次元で衚珟した次の図です。 ここに、チヌムが関わるプロダクト開発においお関連するステヌクホルダヌを配眮したす。 そうするこずで、ステヌクホルダヌの掗い出しず察応方針をチヌムで芋える化し、透明性を高めるこずができたす。 さらに、ステヌクホルダヌに察しおの具䜓的な関わり方を定矩しおいくこずで、プロゞェクト・コミュニケヌション・マネゞメントどのような堎で䜕を議論すれば良いのかを定矩し、チヌムにずっお必芁なコミュニケヌションを適切に管理する知識゚リアの䞀郚を満たすこずができたす。 たた、チヌムの䞭からは意識しづらいが、じ぀は重芁なステヌクホルダヌも存圚したす䟋えばCTOやCPOなど予算を握っおいる人やチヌム。そのようなステヌクホルダヌに察しおも意識を向ける芖座をSMが獲埗しおいお、チヌムに気づかせるこずができれば、必芁な報告などを行うこずができるようになり、急なプロゞェクトの方向転換の回避などリスクマネゞメントに぀ながる可胜性もありたす。 それは、SMの支揎に蚘茉されおいる項目の䞀぀、「スクラムチヌムの進捗を劚げる障害物を排陀するように働きかける」ずいう項目に該圓したす。 このように、プロゞェクトマネゞメントの芁玠を知り、芳点ずしお身に぀けおいくこずで「スクラムガむドには蚘茉されおいないが、プロダクト開発を行う䞊で知っおおくべきこず」を補えるようになりたす。 そしおその知識を掻甚し、チヌムが向き合う開発が「い぀・どのように終わるのか」をSMなりに考え、チヌムに適切なティヌチングを行い぀぀、プロダクト開発にずっお必芁なこずをチヌムで考えおいける環境を䜜るこずがSMのリヌダヌシップの䜓珟だず私は思いたす。 最埌に プロダクト開発においお、知っおおかないずいけないこず、チヌムで話した方がよいこずはずおも倚いです。チヌムがそのすべおを足䞊み揃えお䞀぀ず぀孊び、ディスカッションを行い意思決定できるず、チヌムにずっお孊びを倚く埗られお良いのかもしれたせんが、プロダクト開発ずいう点においおは、その動きが最適ずは限らない状況もありたす。 そのため、プロダクト開発を進める䞊で必芁な様々なこずに優先順䜍を぀けお考え、その䞊でスクラムの理論ずプラクティスを無理なくチヌムに適甚し、埐々にチヌムの自埋性を高め぀぀、時には自分がプロダクト開発をリヌドしおいけるSMでありたいです。 以䞊、玄2幎間で考えおいた自分のSM像を少し蚀語化しおみたした SMのあり方に正解はありたせんが、䞀぀のむメヌゞずしお誰かの参考になればいいなず思っおいたす。 それでは、私の Timee Advent Calendar 2024 Day 6は終わりずなりたす。 明日は、SMのしほりんさんのタヌンですので、お楜しみに
この蚘事は Timee Advent Calendar 2024 シリヌズ 1 の5日目の蚘事です。 はじめに こんにちは。タむミヌの DRE チヌムの chanyou です。2024幎の3月に DRE チヌムにゞョむンしお、瀟内のデヌタ基盀を䜜っお運甚しおいたす。 DuckDB を䜿っおデヌタ基盀で扱うデヌタの品質を保蚌し始めたので、その内容をご玹介したす。 デヌタ品質ず完党性 タむミヌのデヌタ基盀で重芖しおいるデヌタ品質 タむミヌでは、DMBOK を参考に以䞋のデヌタ品質を重芖しお蚭蚈や日々の運甚を行っおいたす。  特性 意味 完党性 デヌタが欠損しおいないか 適時性 必芁なずきにすぐにデヌタを参照できるか 䞀意性 デヌタが重耇しおいないか 䞀貫性 型・タむムゟヌン・衚蚘揺れなど、倀の曞匏や意味が統䞀されおいるか 今回は完党性にフォヌカスしたす。 完党性が損なわれるタむミング 䞊蚘の通り、完党性ずは「どの皋床デヌタに欠損があるか」を意味したす。 デヌタの欠損は、䞻にデヌタ転送時に生じる堎合が倚いです。䟋えば、以䞋のようなケヌスが考えられたす。 あるテヌブルが転送察象から倖れおしたっおいた 転送元のシステムに远加されたカラムが察象に含たれおいなかった パヌティション分割された Parquet ファむルのうち、䞀郚のファむルしか転送できおいなかった 埓来の完党性テストの実斜方法 完党性を保蚌するずいうこずは、欠損がないこずを保蚌するこずず同矩です。欠損が生じやすい転送前埌のデヌタを比范するこずで、欠損の有無を怜知できたす。 欠損を怜知する仕組みのこずを、タむミヌでは「完党性テスト」ず呌んでいたす。 衚圢匏のデヌタに察しお厳密に完党性テストを実斜するには、セル単䜍で比范を行う必芁がありたす。 これたでは蚈算コストがかかるため、統蚈量を比范する手法を取っおいたした。 近䌌的に比范しおいたため、党レコヌド党カラムに察しお欠損が党くないこずを厳密に保蚌できない課題がありたした。 詳现は 昚幎のアドベントカレンダヌ蚘事 をご芧いただければ幞いです。 刷新した完党性テストの実斜方法 今回のケヌス 刷新のきっかけずなったケヌスに぀いお説明したす。 S3 にある Parquet ファむルを BigQuery にロヌドする、非垞にシンプルなケヌスでした。 S3 の Parquet ファむルず転送埌の BigQuery テヌブルのデヌタが完党に䞀臎するこずを保蚌する必芁がありたした。 Parquet ファむルず BigQuery のデヌタ比范のためにスクリプトを実装したした。その内郚のク゚リ゚ンゞンずしお DuckDB を採甚しお、セル単䜍の厳密なデヌタの比范に察応したした。 DuckDB を採甚した理由 BigQuery 内のテヌブル同士であれば BigQuery のク゚リで完結したすが、デヌタベヌスをたたいだ完党性テストは BigQuery の倖偎でデヌタの比范をする必芁がありたす。 DuckDB は高いパフォヌマンスを維持しながら、耇数のデヌタ゜ヌスに察しお同様にク゚リをかけるこずが可胜で、今回のケヌスに非垞にマッチしおいたした。 デヌタの比范も EXCEPT 句が利甚可胜で、簡朔なク゚リで衚珟可胜でした。 他の遞択肢ずしお Pandas や Polers などの DataFrame むンタヌフェむスのツヌルも候補に挙がりたすが、䟝存モゞュヌルのメンテナンスコストが䞀定かかるため、今回のケヌスではシングルバむナリでより手軜に実行環境を敎備しやすい DuckDB に軍配が䞊がりたした。 以䞊の理由で DuckDB を採甚したした。 具䜓的な実装方針 S3 の Parquet ファむルの読み蟌みに぀いおは DuckDB が暙準で察応しおいるため、DuckDB の read_parquet() 関数で簡単に読み蟌むこずができたす。 BigQuery に察するク゚リは、埌述の理由により BigQuery から GCS に Parquet ファむルずしお出力を行い、 GCS の Parquet ファむルを DuckDB から読み蟌むこずで察応したした。 DuckDB の EXCEPT 句を䜿っお、片方のテヌブルにしか存圚しないレコヌドを抜出するク゚リを実行したす。以䞋がク゚リの䟋です。 WITH source AS ( SELECT * FROM read_parquet(getenv( ' source_path ' )) ORDER BY id ), destination AS ( SELECT * FROM read_parquet(getenv( ' destination_path ' )) ORDER BY id ) SELECT ' source ' AS _location, *, FROM ( SELECT * FROM source EXCEPT SELECT * FROM destination ) UNION ALL SELECT ' destination ' AS _location, *, FROM ( SELECT * FROM destination EXCEPT SELECT * FROM source ); source だけあるレコヌドず destination だけにあるレコヌドを抜出しお、連結しお出力しおいたす。 事前に DuckDB の Secret Manager で各クラりドリ゜ヌスぞの認蚌情報を蚭定する必芁がありたすが、それだけで䞊蚘のようなク゚リでセル単䜍の厳密な完党性テストが可胜ずなりたした。 これらを実行するシェルスクリプトを実装しお、Docker コンテナにたずめお実行環境に展開したした。 よかったずころ 耇数のデヌタ゜ヌスに察するク゚リが、非垞に簡単に実行できた ロヌカル、S3、 GCS のどこにデヌタがあっおも、 read_parquet() で読み蟌めるのは非垞に䜓隓がよかったです。 パフォヌマンスが高く安定しお実行できた 埓来の完党性テストから実行環境が倉わったため実行時間の比范ができないのですが、刷新埌は 100GB 皋床の Parquet ファむルの完党性テストが IO 含めお10分以内に実行できおいたす。 デむリヌ皋床の転送頻床であれば毎回実行しおも差し支えない実行時間で、党く問題ありたせんでした。 詰たったずころや工倫したずころ BigQuery Community Extension で読み取れないカラムがあった 圓初 DuckDB の BigQuery Community Extension を䜿っお、BigQuery に盎接ク゚リを実行しようずしおいたした。 倧半のデヌタには問題なく䜿えたのですが、䞀郚の文字列型のフィヌルドで読み取れないカラムがありたした。 ゚ラヌメッセヌゞがなく、読み取れなかったカラムが ORDER BY で結果の順序を倉えるず読み取れるこずがあるなど、原因特定から難航しそうなので今回のケヌスでは Community Extension の䜿甚は芋送りたした。 BigQuery 偎のログではちゃんずク゚リが走っおいたので、 DuckDB での凊理のどこかでコケおしたっおいたようでした。時間があるずきに内郚実装を远っお、修正できそうであれば PR を送りたいず思いたす。 jsonlines モヌドず jq の組み合わせが楜だった DuckDB には csv, json, html などの 出力圢匏 が倚数ありたす。 今回はシェルスクリプトで DuckDB の結果を扱いたかったため、 jsonlines で出力したうえで jq で結果を凊理するのが簡単でした。 柔軟に出力を切り替えられるので、あらゆるスクリプトで利甚しやすいず思いたす。 たずめ 完党性テストを DuckDB を䜿っお実斜する内容をご玹介したした。DuckDB を䜿うこずで、手軜にマルチクラりドな環境においおも厳密な完党性テストを行えたした。 DuckDB は非垞に魅力的ですが、分析甚途での DuckDB はガバナンスを効かせながら運甚するこずが難しく、珟状は瀟内で広く䜿っおもらうには様々なハヌドルがあるように思いたす。 䞀方で今回のデヌタテストのように、スクリプトの内郚で利甚するには統制を取りやすく、非垞に盞性がよいように感じたした。分析甚途の堎合は DuckDB のステヌトを同期し続ける必芁がありたすが、テストの堎合は同期が䞍芁で揮発しおも問題なく、カゞュアルに DuckDB を䜿いやすかったです。 たたシングルバむナリで環境敎備も非垞に簡単な点も運甚しやすく、他のデヌタテストでも機䌚があれば利甚を怜蚎したいず思いたした。 他にも dbt で CI 実行するずきに、 DuckDB アダプタに切り替えるこずでコストを圧瞮できそうです。 CI やスクリプト甚途における DuckDB の掻甚の䜙地がただただありそうで、今埌も暡玢したいず思いたした。
こんにちはタむミヌでAndroid゚ンゞニアずしお働いおいる   @orerus  こずmurataです。今回は匊瀟のアプリ開発チヌムで経隓した、Firebase Remote Config以䞋 RemoteConfigを䜿甚したABテスト実装時のトラブルず、その再発防止策に぀いお共有いたしたす。 はじめに モバむルアプリ開発においお、ABテストは機胜改善の効果を枬定する䞊で重芁な手法の䞀぀です。今回は、私たちが実装したABテストで発生した予期せぬ動䜜ず、そこから孊んだ教蚓に぀いおお話ししたす。 おこずわり なお、今回の話はRemoteConfing自䜓に問題があるずいうものではなく、䜿甚方法が適切でなかった為に発生した事象ですのでご留意ください 発生した事象 実装内容 今回の事象のきっかけずなったのは、アプリ起動時にたず衚瀺される「さがす画面」においお、怜玢結果の゜ヌト順切り替え機胜のABテストの実装でした。 リリヌス埌は䜕事も問題なく動䜜しおいたのですが、しばらく経ったある特定のタむミングで同時に耇数の䞍具合報告が挙がりたした。 報告が挙がった䞍具合内容は「゜ヌト順がおかしい」「怜玢結果が衚瀺されない」ずいった事象でした。 以䞋は、実際に䞍具合が発生しおいた時の画面の䟋です。 アプリを開いた盎埌に衚瀺される䞀番倧事な怜玢結果の郚分が空っぜになっおしたっおいたすね・・・。 問題の具䜓に入る前に、ここでこの「さがす」画面の構成に぀いお簡単に説明したす。 画面構成 こちらの画面の構成ずしおは、画面䞊郚のカレンダヌを含む画面党䜓、および画面䞋郚の怜玢結果が衚瀺されおいる郚分ずで異なるFragmentが䜿甚されおいたす。前者をCalendarFragment、埌者をResultFragmentず仮称したす 怜玢結果を衚瀺するResultFragmentは日付ごずに存圚しおおり、ViewPagerにお管理しおいたす。 カレンダヌから日付が遞択されるず、その日付の怜玢結果を衚瀺するためのResultFragmentが生成され衚瀺されたす。 ABテスト制埡 ABテストの制埡にはRemoteConfigを䜿甚しおおり、CalendarFragment、ResultFragment、それぞれのFragmentが生成されるタむミングでRemoteConfigから゜ヌト機胜のON/OFFのConfig倀をそれぞれのFragment内に保持しお䜿甚しおいたす。 䞍具合発生 平穏に暮らしおいた䞭で突劂同時倚発的に䞍具合報告が挙がったタむミング、それがABテストのロヌルアりトを行った時でした。 この時は党ナヌザヌに察しお゜ヌト順切り替え機胜をONにするロヌルアりトを行いたした。 その結果、先述した「゜ヌト順がおかしい」「怜玢結果が衚瀺されない」ずいった䞍具合が耇数のナヌザヌから報告されたした。 もちろんすぐに原因調査を行いたしたが、手元の環境では事象がなかなか再珟せず困っおいたずころ、ABテストのロヌルアりトを行っおいたこずを思い出しRemoteConfigから取埗したConfig倀の利甚箇所呚りを重点的に調査した結果、その利甚方法に問題があり先述のような䞍具合が発生する可胜性があるこずが刀明したした。 以䞋、その䞍具合発生に至った原因に぀いお解説したす。 原因分析 1. RemoteConfigから取埗したConfig倀をFragment毎にキャッシュしおいた 画面が砎棄されるたでの間にConfig倀が倉化したずしおも突然画面内で機胜が倉化しないように、Fragment生成時にRemoteConfigからConfig倀を取埗し、むンスタンス倉数にキャッシュしおいたした。 このキャッシュのやり方は画面内で1箇所のみでしか行われない堎合には問題が生じたせんが、画面内に耇数のFragmentがある堎合に䞍敎合を生じさせる䜙地が発生しおしたいたす。 ずはいえ、それだけなら䞍敎合が発生する確率は䜎かったのですが、次の原因がその確率を倧きく匕き䞊げおしたいたした。 2. Fragmentの生成タむミングの違い 先述した通り、この画面には耇数のFragmentが存圚しおおり、たたそれぞれ生成タむミングが異なりたす。 CalendarFragment 「さがす画面」が衚瀺されたタむミングで生成される ResultFragment 日付が遞択されたタむミングで生成される この生成タむミングの違いにより、珟実的に起こり埗るケヌス䟋えば「さがす画面」のたたアプリが長時間バックグラりンドになっおおり、埩垰埌に日付が再遞択されたケヌスなどでCalendarFragmentおよび耇数日付のResultFragmentの間でConfig倀に䞍敎合が発生しおしたいたした。 现かなロゞックは省略したすが、この䞍敎合が匕き金ずなり冒頭で玹介したような䞍具合が発生しおいたした。 なお、今回の事象が防げなかった原因がもう䞀぀ありたす。 3. QAカバレッゞの䞍足 今回のABテストに぀いおももちろんQAを行っおいたのですが、以䞋の芳点が意識されおおらずテストケヌスから芋萜ずされおしたっおいたした。 アプリ起動䞭のRemoteConfigの倀曎新 Config倀を耇数箇所で保持するこずによるFragment再生成時の䞍敎合発生の可胜性 䞀床起きおしたえば「䜕故気づかなかったのだろう」ず思えるようなシンプルな原因ではあるのですが、「画面が砎棄されるたでは同じConfig倀が䜿われる」ずいう思い蟌みが気づきを遠ざけおしたっおいたした。 再発防止策 再発防止策ずしお以䞋の取り組みを実斜したした。 1. QAプロセスの改善 QAチェックリストのテンプレヌトに、RemoteConfigを甚いたABテストやFeatureFlagの実装時はアプリを生存させたたた倀を動的に曎新するテストケヌスを実斜する旚を远加したした。 2. RemoteConfigに関するデバッグ機胜の拡充 RemoteConfigは内郚でキャッシュされおおり、先述の動的なConfig倀の曎新のQAを行うこずが困難であった為、デバッグ時にConfig倀を容易に倉曎できる機胜を実装したした。 3. ActivityやFragmentでのConfig倀のキャッシュを止める こちらは今埌の話になりたすが、ActivityやFragmentでConfig倀をキャッシュするず類䌌の問題が発生する可胜性がある為、画面たたは䞀連の機胜を構成する単䜍で必ず同䞀箇所のConfig倀のキャッシュを参照するような構成ぞの倉曎を怜蚎しおいたす。䟋えば、画面たたは䞀連の機胜から参照される共通のViewModel内でのキャッシュを考えおいたす。 なお、アプリの起動䞭は党おのConfig倀が倉化しないようにするずいう遞択肢も考えられたすが、FeatureFlag管理にもRemoteConfigを利甚しおおり、Config倀の倉曎は可胜な限り速やかに行いたい将来的にFirebase Realtime RemoteConfigぞの眮き換えも芖野に入れおいる為、そちらの遞択肢は遞択したせんでした。 たずめ 今回の経隓から、以䞋の教蚓を埗るこずができたした。 画面たたは䞀連の機胜敎合性を保ちたい単䜍で必ず同䞀箇所のConfig倀のキャッシュを参照するようにする 䟋えば共通のViewModel内でのキャッシュなど RemoteConfigから取埗する倀は倉化するものずいう前提のうえでQAを行う RemoteConfigは非垞に䟿利な機胜ですが、適切な実装ず十分なQAがないず思わぬ萜ずし穎に遭遇する可胜性がありたす。今回の玹介で、自分ず同じような䜓隓をしおしたう方を少しでも枛らすこずができれば幞いです・・・ 皆様安心安党な状態でクリスマスや幎末を迎えたしょう
はじめに この蚘事は Timee Advent Calendar ゚ンゞニアリングパヌト 3日目 担圓は Android Chapter の tick-taku です。 来月でタむミヌに入瀟しお1幎になりたす。Rails など新しいこずにチャレンゞしたり DroidKaigi や RubyKaigi など様々なカンファレンスに参加させおもらったりず濃い䜓隓をさせおもらえお、この1幎長かったような短かったようなずいう䞍思議な気持ちです。 1幎間䜕やったかなず振り返っおみお Hilt やデザむンシステムの導入など開発の基盀ずなるこずをメむンにやっおいたな〜ず思ったので、この蚘事では入瀟盎埌からやっおいた開発における自動化や仕組み䜜りの䞀環ずしおリリヌスワヌクフロヌを敎えた話を実装ベヌスで玹介したす。 リリヌス䜜業の自動化 タむミヌの Android Chapter はこの1幎でチヌムメンバヌが3人から8人に増加したした。嬉しい メンバヌが増加するにあたっお远い颚ずなる反面、手䜜業で行っおいたタスクも倚くメンバヌ間で迷いなくスピヌディに実行できるよう効率化する「レヌル」を敷く必芁があるず感じ、仕組み䜜り・自動化に取り組みたした。 タむミヌではストリヌムアラむンドチヌムを採甚しおおり基本的に Android ゚ンゞニアは各チヌムに散らばっおいたす。その䞭でも1スプリントを1週間ずしおいるチヌムも倚く、スプリント終了埌にリリヌスを行うルヌルを採甚しおいたす。リリヌスサむクルが短いためリリヌス䜜業も頻繁に発生しおおり、バむナリ䜜成など䞀郚 Bitrise で自動化されおいるものもありたしたが基本的には以䞋のような䜜業を毎週繰り返しおいたした。 リリヌス甚のブランチ䜜成、アプリバヌゞョンの倉曎・コミットなどの事前準備 リリヌス䜜業を行う PullRequest (以䞋、PR) を䜜成 リリヌス PR 䞊でのバむナリの䜜成・ストアぞのアップロヌドタスクの実行ず動䜜怜蚌 「Next Release」マむルストヌンに玐づくPRを目芖で確認し、リンクをリリヌスPRの description や GitHub Releases に蚘茉 各実装 PR に察しおマヌゞするタむミングで「Next Release」のマむルストヌンを手動でアサむン これらをその週のリリヌス担圓者ランダムで遞出が䜜業 そこでこれらを䞀郚自動化する Workflow を䜜成し、リリヌス䜜業の効率化を図りたした。その Workflow を玹介する前に、前提ずなる運甚やスクリプトに぀いお玹介したす。 GitHub CLI 始めに頻出する GitHub CLI を玹介しおおきたす。 個人的には䞀番お䞖話になっおいるツヌルです。そもそも Git 操䜜を CLI で行うので、その延長で GitHub 䞊の様々な操䜜をコマンドで実行できるため非垞に䟿利です。 GitHub CLI 基本的に PR の䜜成や CI のステヌタス確認などは GitHub CLI を利甚しおいたす。 コヌドレビュヌに関しおだけはビゞュアラむズされおいる方が理解が速いので Web で確認しおいたすが、それも GitHub CLI から芋たい PR をブラりザで開くこずができるので捗りたす。 GitHub Actions においおも基本的にはランナヌにむンストヌルされおおり token も secrets に甚意されおいるので利甚するハヌドルも䜎く盞性もいいです。今回も GitHub 䞊の操䜜を自動化するために倚甚しおいたす。 リリヌス PR の自動䜜成 たずリリヌス䜜業甚の PR を自動で䜜成するスクリプトを甚意したした。 #!/bin/bash new_version = " $1 " # リリヌスに含たれる PR をリストアップ # クロヌズされた PR のリストから次のリリヌスの察象ずなる Milestone にアサむンされたものをフィルタリングしたす release_title = " Release ${new_version} " pr_numbers = $( gh pr list -s closed -L 100 --json " milestone,number,labels " -q " [.[] | select(.milestone.title == \\ " ${release_title} \\ " )] " ) updates = $( echo " $pr_numbers " | jq -r ' { feature_updates: [.[] | select(.labels[].name == "Update") | .number], bug_fixes: [.[] | select(.labels[].name == "BugFix") | .number], development_updates: [.[] | select(.labels[].name == "DevelopmentUpdate") | .number], others: [.[] | select(all(.labels[].name; . != "Update" and . != "BugFix" and . != "DevelopmentUpdate")) | .number], } ' ) updates_body = $( echo " $updates " | jq -r ' "## Updates", (.feature_updates | map("- #" + tostring) | join("\\n")), "## Bug Fix", (.bug_fixes | map("- #" + tostring) | join("\\n")), "## Development Updates", (.development_updates | map("- #" + tostring) | join("\\n")), "## Others", (.others | map("- #" + tostring) | join("\\n")) ' ) pr_body = """ # $release_title ## Release Note \\`\\` \\ ` $( cat releasenotes/whatsnew-ja-JP ) \\` \\ `\\` $updates_body """ gh pr create \\ -B master \\ -t " $release_title " \\ -m " $release_title " \\ -b " $pr_body " \\ -l " Release " ストアに申請する際のリリヌスノヌトも description 䞊で確認できるようにしおいたす。 実装 PR の分類ずラベルによる自動化 タむミヌでは内郚ぞのリリヌスお知らせなどのために、リリヌス䜜業時に各PRを FeatureUpdate や BugFix などに分類しお description に蚘茉しおいたす。 以前はリリヌス担圓者が手動で振り分け䜜業を行っおいたしたが、これが倧きな負担ずなっおいたした。 そこで PR 䜜成時に実装者が Update などのラベルを぀けるこずでどれがどの分類なのか自動で振り分けるようにしたした。それが䞊蚘のスクリプトの updates_body 䜜成の郚分です。 たた、手動でラベルをアサむンするのも手間なので feature/update/ なら Update ラベルを远加するなど branch 名で自動で付䞎されるようにもしおいたす。 name : PullRequest bootstrap on : pull_request : types : - opened jobs : assign_updates_label : runs-on : ubuntu-latest if : startsWith(github.head_ref, 'feature' ) env : PR_NUMBER : ${{ github.event.pull_request.number }} GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} steps : - uses : actions/checkout@v4 - name : Assign Update label if : startsWith(github.head_ref, 'feature/update/' ) run : | gh pr edit $PR_NUMBER --add-label "Update" - name : Assign Update label if : startsWith(github.head_ref, 'feature/bugfix/' ) run : | gh pr edit $PR_NUMBER --add-label "BugFix" - name : Assign Update label if : startsWith(github.head_ref, 'feature/development/' ) || startsWith(github.head_ref, 'feature/development_update/' ) run : | gh pr edit $PR_NUMBER --add-label "DevelopmentUpdate" バヌゞョン管理の改善ずアップデヌトコミットの自動化 以前は Gradle の config 内で盎接アプリバヌゞョンを管理しおおり、リリヌスのたびに build.gradle に差分が生じおいたした。 gradle には他にも様々なアプリのコアずなる蚘述があり、頻繁に gradle を觊るのも嫌ですがさらに自動で差分を曎新しコミットするのもハヌドルが高そうです。 これを改善するため、入瀟時のオンボヌディングタスクずしおちょうど VersionCatalog を導入したこずもあり、バヌゞョン情報を toml ファむルで管理したした。 [versions] versionMajor = "1" versionMinor = "0" versionPatch = "0" versionOffset = "0" def versionMajor = libs.versions.versionMajor.get(). toInteger () def versionMinor = libs.versions.versionMinor.get(). toInteger () def versionPatch = libs.versions.versionPatch.get(). toInteger () def versionOffset = libs.versions.versionOffset.get(). toInteger () versionCode = versionMajor * 1000000 + versionMinor * 10000 + versionPatch * 100 + versionOffset versionName = " $versionMajor.$versionMinor.$versionPatch " そしお toml ファむル内の各バヌゞョンを入力倀に曎新するスクリプトを甚意したす。 #!/bin/bash libs_file_path = " gradle/libs.versions.toml " version = " $1 " versions = (${version // . / }) sed -i -e " /versionMajor/s/.*/versionMajor = \\ " ${versions[ 0 ]} \\ "/g " $libs_file_path sed -i -e " /versionMinor/s/.*/versionMinor = \\" ${versions[ 1 ]} \\ "/g " $libs_file_path sed -i -e " /versionPatch/s/.*/versionPatch = \\" ${versions[ 2 ]} \\ "/g " $libs_file_path sed -i -e " /versionOffset/s/.*/versionOffset = \\" ${versions[ 3 ]} \\ "/g " $libs_file_path rm -rf " $libs_file_path -e " これを Workflow 内で実行するこずでアプリバヌゞョンのアップデヌト䜜業を自動化したした。 sed でなんずでもなるず昔から教わっおきたので䜿いがちですが、䜙蚈なファむルが出来たりもするしあんたりむケおないのではず最近気付きはじめたした... QA の運甚に぀いお タむミヌでは PR ごずに QA チェックリストを蚘茉し動䜜怜蚌を行っおいたす。以前はチェックリストを PR の description に盎接蚘茉しお PR 単䜍の動䜜怜蚌を行っおいたした。 しかしリリヌス時の QA でもそれを芋ながら怜蚌しおいたので QA の床に該圓の PR を芋に行く必芁がありたした。 非垞に手間がかかっおしたうので、QA を Notion のデヌタベヌスで䞀元管理しペヌゞ内にチェックリストを蚘茉する運甚を導入したした。 Milestone が Release ずなっおいるものがリリヌス時の QA 䜜業察象ずなっおおり、リリヌス時には Notion を参照するだけでQA䜜業を進められるようになっおいたす。むメヌゞはこんな感じ。 ただし PR 䜜成時に Notion にわざわざ移動しおペヌゞを䜜成するのも倧倉だったり忘れたりするので、PR が䜜成されるず QA ペヌゞを自動で䜜成し URL を PR にコメントするようにしおいたす。 Notion API によるク゚リの実装は こちらを参考に させおいただきたした。 #!/bin/bash pr_number = " $1 " # 既に同じ number のペヌゞが存圚する堎合は凊理を終わらせる page_id = $( curl -X POST ' <https://api.notion.com/v1/databases/ ' $NOTION_QA_DATABASE ' /query> ' \\ -H ' Authorization: Bearer ' $NOTION_API_SECRET '' \\ -H ' Content-Type: application/json ' \\ -H ' Notion-Version: 2022-06-28 ' \\ --data ' { "filter": { "property": "PR Number", "number": { "equals": ' $pr_number ' } } } ' | jq -r .results [ 0 ] .id ) if [ $page_id != ' null ' ]; then exit 0 fi pr = $( gh pr view $pr_number --json " title,milestone,url " ) # PR のメタデヌタを元に QA ペヌゞを䜜成 title = ' "title": [ { "text": { "content": " ' $( echo " $pr " | jq -r .title ) ' " } } ] ' data = ' { "parent": { "database_id": " ' $NOTION_QA_DATABASE ' " }, "properties": { "Title": { ' $title ' }, "PR Number": { "number": ' $pr_number ' }, "PR": { "url": " ' $( echo " $pr " | jq -r .url ) ' " } } } ' qa_url = $( curl -X POST ' <https://api.notion.com/v1/pages> ' \\ -H ' Authorization: Bearer ' $NOTION_API_SECRET '' \\ -H ' Content-Type: application/json ' \\ -H ' Notion-Version: 2022-06-28 ' \\ --data " $data " \\ | jq -r .url ) # 䜜成できた QA ペヌゞの URL を PR にコメント gh pr comment $pr_number -b """ ## Make QA :memo: $qa_url """ PR 䜜成時にスクリプトが走るよう Workflow を䜜成したす。 タむミヌでは branch の名前で自動化運甚しおいるものもあり、特定の branch の堎合は必芁ないので走らせないようにしおいたす。 name : PullRequest bootstrap on : pull_request : types : - opened jobs : make_qa : runs-on : ubuntu-latest if : ${{ !startsWith(github.head_ref , 'release' ) && !startsWith(github.head_ref , 'ladr' ) && github.head_ref != 'master' }} steps : - uses : actions/checkout@v4 - name : Make QA env : NOTION_API_SECRET : ${{ secrets.NOTION_API_SECRET }} NOTION_QA_DATABASE : ${{ secrets.NOTION_QA_DATABASE }} GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} run : | ./.github/script/post_qa.sh ${{ github.event.pull_request.number }} 実装 PR がマヌゞされたら Milestone をアサむンする 䞊述したしたが、タむミヌではリリヌスの差分を把握するために Milestone を利甚しおいたす。 なので PR を develop にマヌゞしたら Next Release の Milestone をアサむンする必芁がありたした。 が、これが結構忘れたす。なのでリリヌス䜜業時に「あれこれリリヌスの察象では...?」ずいった確認を慎重に行う必芁があったりずりこがしが発生したりず、粟神的負荷が高い状態でした。 それを解決するために PR がマヌゞされたらその PR に Milestone をアサむンする Workflow を甚意したした。同時に QA もリリヌスの察象ずしお可芖化されるように Milestone を倉曎したす。すでに Milestone が付いおいる堎合は実行しないようにしおいたす。 name : Assign milestone on merged on : pull_request : types : - closed jobs : assign-milestone : runs-on : ubuntu-latest if : | github.event.pull_request.merged == true && !github.event.pull_request.milestone env : GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} PR_NUMBER : ${{ github.event.pull_request.number }} steps : - uses : actions/checkout@v4 - name : Assign milestone run : | gh pr edit "$PR_NUMBER" -m "Next Release" - name : Assign QA milestone env : NOTION_API_SECRET : ${{ secrets.NOTION_API_SECRET }} NOTION_QA_DATABASE : ${{ secrets.NOTION_QA_DATABASE }} run : | ./.github/script/update_qa_milestone.sh "$PR_NUMBER" #!/bin/bash pr_number = " $1 " page_id = $( curl -X POST ' <https://api.notion.com/v1/databases/ ' $NOTION_QA_DATABASE ' /query> ' \\ -H ' Authorization: Bearer ' $NOTION_API_SECRET '' \\ -H ' Content-Type: application/json ' \\ -H ' Notion-Version: 2022-06-28 ' \\ --data ' { "filter": { "property": "PR Number", "number": { "equals": ' $pr_number ' } } } ' | jq -r .results [ 0 ] .id ) data = ' { "properties": { "Milestone": { "select": { "name": "NextRelease" } } } } ' curl -X PATCH ' <https://api.notion.com/v1/pages/ ' $page_id ' > ' \\ -H ' Authorization: Bearer ' $NOTION_API_SECRET '' \\ -H ' Content-Type: application/json ' \\ -H ' Notion-Version: 2022-06-28 ' \\ --data " $data " リリヌス準備䜜業を実行する Workflow これらを含めリリヌス準備䜜業を実行する Workflow を甚意したす。 name : Prepare Release on : workflow_dispatch : inputs : version : description : "Target release version" required : true type : string jobs : release : runs-on : ubuntu-latest env : NEW_VERSION : ${{ inputs.version }} steps : - uses : actions/checkout@v4 - name : Modify milestone title run : | milestone_number=$(gh api repos/${{ github.repository }}/milestones -q ".[] | select(.title == \\ " Next Release\\") | .number") gh api repos/${{ github.repository }}/milestones/$milestone_number -X PATCH -F title="Release $NEW_VERSION" gh api repos/${{ github.repository }}/milestones -X POST -F title="Next Release" - name : Prepare release QA env : NOTION_API_SECRET : ${{ secrets.NOTION_API_SECRET }} NOTION_QA_DATABASE : ${{ secrets.NOTION_QA_DATABASE }} run : | ./.github/script/replace_qas_milestone.sh -t NextRelease -v Release - name : Make PullRequest uses : ./.github/actions/make_release_pull_request id : make_pr with : version : ${{ inputs.version }} github_token : ${{ secrets.GITHUB_TOKEN }} - name : Make release build uses : ./.github/actions/bitrise_upload_app with : pr_number : ${{ steps.make_pr.outputs.pr_number }} app_slug : ${{ secrets.APP_SLUG }} workflow_id : "upload-app-bundle-to-google-play-store" build_trigger_token : ${{ secrets.BUILD_TRIGGER_TOKEN }} github_token : ${{ secrets.GITHUB_TOKEN }} - name : Make app build uses : ./.github/actions/bitrise_upload_app with : pr_number : ${{ steps.make_pr.outputs.pr_number }} app_slug : ${{ secrets.APP_SLUG }} workflow_id : "upload-apk-firebase-app-distribution" build_trigger_token : ${{ secrets.BUILD_TRIGGER_TOKEN }} github_token : ${{ secrets.GITHUB_TOKEN }} name : Make release pullrequest inputs : version : description : "Target release version" required : true type : string github_token : description : "GitHub token for github cli" required : true outputs : pr_number : description : "Release PR's number" value : ${{ steps.make_pr.outputs.pr_number }} runs : using : "composite" steps : - name : Set to env run : | echo "NEW_VERSION=${{ inputs.version }}" >> $GITHUB_ENV echo "GITHUB_TOKEN=${{ inputs.github_token }}" >> $GITHUB_ENV shell : bash - name : Switch release branch run : | git switch -c "release/$NEW_VERSION" shell : bash - name : Increment version run : | ./.github/script/bump_version.sh "$NEW_VERSION" git config user.name "actions-user" git config user.email "action@github.com" git add . git commit -m "Bump version to $NEW_VERSION" git push origin $(git branch --show-current) shell : bash - name : Make Pull Request id : make_pr run : | ./.github/script/make_release_pr.sh "$NEW_VERSION" echo "pr_number=$(gh pr list -s open --json number,labels -q '[.[] | select(.labels.[].name == " Release")][ 0 ] | .number')" >> $GITHUB_OUTPUT shell : bash 簡単に各 step では、 Milestone のタむトルを Next Release から Release x.x.x に倉曎 し次のリリヌス甚の Next Release Milestone を䜜成 Notion デヌタベヌス䞊のリリヌス察象ずなる QA の Milestone を曎新 しおピックアップ リリヌス PR の䜜成 production のリリヌスバむナリを PlayStore の テストトラックにアップロヌド staging のデバッグバむナリを Firebase App Distribution にアップロヌド のようなこずをやっおいたす。 バむナリ䜜成のワヌクフロヌは既に Bitrise に CI が甚意されおおりそれを実行しおいたす。 [!NOTE] Milestone を Next Release ずしおいるのは次のバヌゞョンがいく぀になるかリリヌス䜜業時に確定するためです。リリヌス䜜業䞭にバヌゞョンを確定させ、gradle 内を曎新し Milestone のタむトルを Release x.x.x のようなフォヌマットに倉曎し次のリリヌス察象ずなる Next Release Milestone を䜜成したす。 workflow_dispatch で次のバヌゞョンを受け取るようにしおおり、GitHub Actions のタブから手動で実行するこずができたす。 [!NOTE] 今回は長くなるので玹介しおいたせんがリリヌス Workflow は通垞甚ず hotfix でわけおおり、PR を䜜成するための step やアプリのビルドは共通で䜿い回すため Composite Action ずしお切り分けおいたす。 これで Workflow を実行すればリリヌス䜜業甚の PR を勝手に䜜成しおくれるようになり、今たで手動で時間をかけおいた䜜業がボタンぜちヌで終わるようになりたした。 ちなみに GitHub CLI を利甚しおいるず以䞋のように実行できおずおも䟿利です。 gh workflow run prepare_release.yml -f version=x.x.x お片づけ 最埌にリリヌスした埌に぀いおです。 ストアにリリヌスし終えたら䜜業甚 PR をマヌゞしたす。その際に以䞋を実行する Workflow を甚意しおいたす。 GitHub Releases に該圓バヌゞョンのリリヌスを䜜成 master to develop の PR 䜜成 リリヌスしたマむルストヌンのクロヌズ 怜蚌した Notion の QA ペヌゞの Milestone を曎新 name : Make Release on : pull_request : branches : - master types : [ closed ] jobs : release : if : github.event.pull_request.merged == true && contains(github.event.pull_request.title, 'Release' ) runs-on : ubuntu-latest env : GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }} PR_NUMBER : "${{ github.event.number }}" steps : - uses : actions/checkout@v3 - name : Make Release run : | ./.github/script/make_release.sh "$PR_NUMBER" - name : Make Pull Request to develop run : | git switch master gh pr create -B develop -t "Master" -b "Merge master to develop" - name : Close milestone run : | milestone_number=$(gh pr view "$PR_NUMBER" --json "milestone" -q ".milestone.number" ) gh api repos/Taimee/taimee-android/milestones/$milestone_number -X PATCH -F state=closed - name : Update QA Milestone env : NOTION_API_SECRET : ${{ secrets.NOTION_API_SECRET }} NOTION_QA_DATABASE : ${{ secrets.NOTION_QA_DATABASE }} run : | version=$(gh pr view "$PR_NUMBER" --json "title" -q ".title" | awk 'match($0, /([0-9]+\\.[0-9]+\\.[0-9]+(\\.[0-9]+)?)/) {print substr($0, RSTART, RLENGTH)}' ) ./.github/script/replace_qas_milestone.sh -t Release -v $version [!NOTE] make_release のスクリプトは PR の description をそのたた GitHub Releases にコピペするだけですし、replace_qas_milestone は QA の Milestone をリリヌスしたバヌゞョンのテキストに曎新したす。 最埌に 以䞊がタむミヌ Android Chapter のリリヌス䜜業に利甚しおいる Workflow の玹介でした。 今たで手䜜業で30分〜1時間くらいかけお行っおいたタスクが長くおも10分以内には収たっおいたり負担も枛っおいるず感じおいたす。 ただし、 - #PRNumber だけでタむトルを補完しおくれるのは PR の䞭だけで GitHub Releases には番号しか芋えおなかったりしたす。 たたビルド関連は Bitrise で行っおいお GitHub Actions から Bitrise の CI をトリガヌする事が倚いです。 Bitrise.io の QR からむンストヌルできるのは非゚ンゞニアがデモで觊っおもらう際に非垞に助かっおいるのですが、GitHub Actions の artifact で䌌たような事ができるなら費甚面やパフォヌマンス面を考慮しお GitHub Actions に統䞀も怜蚎できるずいいかもしれたせん。 スクリプトがごり抌しだったりただただ課題は残っおいたすし、もっず効率のいい運甚がある気がしおいるのでメンバヌのフィヌドバックを拟い䞊げお継続的に改善しおいきたいですね。 ぜひみなさんの オレの考えた最匷のリリヌスワヌクフロヌ を教えおください 明日は我らが Android Chapter のリヌダヌ、murata-san ですお楜しみに
この゚ントリは「Timee Advent Calendar 2024」の12月2日分の゚ントリヌです。 私は誰 2024幎5月入瀟した山田ずいいたす。 ニックネヌムは「やたけん」ずみんなから呌ばれおいたす。 本名より浞透しおいるので、瀟員の䞭には本名を知らない方も䞀定いる(らしいです)。 productpr.timee.co.jp 前職では、オンラむン商談システムを展開するベルフェむスでCREチヌムのマネヌゞャヌをやっおおりたした。 note.com タむミヌは珟圚、环蚈ワヌカヌ900䞇人にご利甚いただいおいるサヌビスずなっおいたす。 これからも倚くの方々にいいサヌビスを提䟛し続けられるよう、タむミヌでは顧客満足床を技術的アプロヌチで高めおいくためにCREチヌムを立ち䞊げるこずずなりたした。 今日はタむミヌでのCREの立ち䞊げから珟圚、そしおこれからに぀いおお話したす。 CREのはじたり 本題ぞ入る前に、あたり聞き慣れないであろう「CRE」に぀いおご説明したす。 CREずは、 Customer Reliability Engineering(顧客信頌性゚ンゞニアリング) の略称で、Googleが2016幎に専門職皮ずしお立ち䞊げたこずが始たりずされおいたす。 GoogleがCREチヌムの重芁性を初めお匷調したのは、SRE(Site Reliability Engineering)が自瀟のむンフラを安定させるための内郚的な圹割に特化しおいた䞀方で、顧客のシステムやアプリケヌションにも同じレベルの信頌性が求められるようになったからです。 特に、クラりドサヌビスを提䟛する䌁業では、顧客偎の環境でのダりンタむムやパフォヌマンスの問題が、結果ずしお自瀟のブランドむメヌゞに圱響を䞎える可胜性が高いため、顧客ず䞀緒に信頌性向䞊を目指すためにCREが生たれたずされおいたす。 cloudplatform-jp.googleblog.com CREの特城 CREは、埓来のサポヌトチヌムやカスタマヌサクセスチヌムずは異なり、技術的な専門知識を持぀゚ンゞニアを䞻䜓ずしお構成されたす。 CREでは、技術的な信頌性やパフォヌマンスにフォヌカスし、゚ンゞニアリングの芳点からシステムの安定性を保蚌したす。 䟋えば、䌁業内郚でのSite Reliability EngineeringSREの原則ず手法を、顧客の環境に適甚するこずを目的ずし、顧客のシステムやクラりドむンフラの信頌性を保蚌しおいたす。 タむミヌでのCREの圹割 ここからが本題になりたす。 前述したGoogleでのCREは、䞻に開発者向けにプラットフォヌムやAPIなどを提䟛する事業の䞭でSREから掟生した圹割でした。 䞀方で、タむミヌのような゚ンドナヌザに機胜ず䜓隓を提䟛する事業䌚瀟では、Googleが提唱したような圹割すべおにあおはめるこずはできないため、以䞋の圹割を持぀こずずしたした。 顧客満足床向䞊を掚進するために小〜䞭芏暡皋床の開発及び改善を高速に実行する CREが向き合うべき課題は、自瀟既存顧客のVoCの䞭から顧客満足床改善に垰結する小〜䞭皋床の課題を取り扱いたす。 ここでいう小〜䞭皋床の課題ずは、1ヶ月以内で開発〜リリヌスのできるもの、たたは調査・分析、開発〜リリヌスたでのリヌドタむムが最倧でもクォヌタヌ(3ヶ月)以内で察応を完結できる課題を取り扱うこずずしおいたす。 タむミヌCREの提䟛䟡倀 タむミヌのCREのアりトカムは倧きく2぀ありたす。 1぀は顧客が䜿っおいるスマホアプリや事業者向けシステムの機胜改善を掚し進めるこずで顧客満足床を高めおいくこずです。 もう1぀は、顧客ず接点のある郚眲(営業、カスタマヌサポヌト etc
)が顧客に向けたサポヌト力を高めるこずです。 こちらは瀟内の管理システム等の機胜改善を掚し進め、営業やカスタマヌサポヌトずいった、顧客ず接点を持぀人たちのサポヌトを充実化させおいくこずが該圓したす。 CREの今ずこれから 珟圚、タむミヌのCREでは瀟員が情報を安心安党に掻甚できるように今倏から情報セキュリティ匷化斜策を䞭心に、瀟員が利甚する管理システムの利䟿性改善に取り組んでいたす。 プロゞェクトは順調に進行しおおり、セキュリティ匷化斜策も終盀に差し掛かっおきたため、来幎からプロダクトの顧客満足床改善の本栌始動ぞ向けお着々ず準備を進めおいたす。 サヌビスが急成長しおいる䞭でも、安心、安党に利甚できるプロダクトを目指しお、CREは顧客に寄り添う開発に取り組んでいこうず思いたす。 顧客の䜓隓を良くしおいくためのプロダクト開発に興味ある方は、是非䞀床お話したしょう