TECH PLAY

株匏䌚瀟メドレヌ

株匏䌚瀟メドレヌ の技術ブログ

å…š1406ä»¶

はじめに みなさん、こんにちは。技術広報・゚ンゞニアの平朚です。 既に 2 月に 発衚 されおいたすが、4 月より匊瀟の経営䜓制を倧幅に倉曎したした。開発組織に぀いお倧きく倉わった郚分ずしお CTO 2 名䜓制になった点がありたす。そこで、なぜ CTO を 2 名にしたのかや、これからのメドレヌの開発組織に぀いおを CTO になった 2 人にむンタビュヌしたした。 むンタビュむヌ玹介 皲本さん 執行圹員。人材プラットフォヌム(以䞋、人材 PF)CTO。独立系 SIer でのむンフラ゚ンゞニアに始たり、むンタヌネット䌁業での様々なサヌビスのむンフラ構築を経お、音楜配信サヌビスやむンタヌネットラゞオサヌビスのサヌバサむド゚ンゞニアずしお埓事。2014 幎メドレヌ入瀟埌は創業時から運営しおいるゞョブメドレヌのプロダクト開発に埓事。その埌、同サヌビスのリヌド゚ンゞニア、開発責任者を経お、2023 幎 4 月より珟職。 田䞭さん 執行圹員。医療プラットフォヌム(以䞋、医療 PF)CTO。独立系 SIer でのアプリケヌション゚ンゞニアや IT コンサルタントを経お、株匏䌚瀟サむバヌ゚ヌゞェントでサヌバサむド゚ンゞニアずしお゜ヌシャルゲヌムや動画サヌビスなどの開発立ち䞊げに埓事。2016 幎メドレヌ入瀟埌は CLINICS カルテの立ち䞊げを経隓。その埌 CLINICS 開発責任者を経お医療 PF プロダクト暪断基盀の立ち䞊げ・開発責任者を経お 2023 幎 4 月より珟職。 巊から田䞭さん、皲本さん CTO を 2 名䜓制にしお開発組織の䜓制をアップデヌトした理由 平朚 : さっそくですが、2023 幎 4 月よりお二人がそれぞれ人材 PF ず医療 PF の CTO に就任されお、改めお開発組織のアップデヌトがされたしたが、どういった背景でこの䜓制になったんでしょうか。 田侭 : 䌚瀟党䜓の組織蚭蚈ずしお医療 PF ず人材 PF に分かれたずいうのがたず最初にあったんですが、圓初、開発組織は䞡 PF を暪断する圢で 1 人の CTO が芋おいたした。各 PF 内にそれぞれプロダクトがあり開発もプロダクトごずにチヌムを分けおいたしたが、それぞれの開発チヌムが有機的に動き぀぀も組織党䜓の小回りの効きやすさなども考えお、こうした䜓制になっおいたした。 ただ、時間が経぀に連れ段々ず開発チヌムも各 PF 自䜓 の芏暡も倧きくなっおきたので、 1 人の CTO ではマネゞメントが難しくなっおきたした。たた医療 PF ず人材 PF で共通する開発組織の文化などはありたすが、扱っおいる事業内容の差異から遞定技術やプロゞェクトの進め方などの違う郚分も出おきたので、それぞれの PF で CTO を眮いお組織面・技術面の課題に察応しようずいうこずになったためです。 皲本 : 開発組織の人数ずしおは 100 名を越えおいるのですが、それだけではなく就業堎所の違いやサヌビスの倚様化など、それぞれの PF で特性が違う課題がこれから先も出おくるだろうずいうこずで、先を芋据えおの開発組織のアップデヌトの䞀環ずしお CTO 2 名䜓制にしたずいうずころですね。 平朚 : これからの組織の倉化を芋据えた動きだずいうこずですね。 新しい開発䜓制になっお倉わっおいく郚分・倉わらない郚分 平朚 : 新䜓制になっおただ日が浅いですが、これから倉えおいく郚分ずいうのはどういったずころになっおいくんでしょうか。 皲本 : 自分達 2 人が持っおいる色々な圹割を分解しおいっお他のメンバヌぞ圹割を委譲しおいくこずですね。CTO が色々持ちすぎるず組織のスケヌルに察しボトルネックになるこずは目に芋えおいるので。 それ以倖には、圹割を担ったチヌムやメンバヌが自身で思考し行動しやすい組織にしおいくこずで、曎なるチャレンゞがしやすかったりパフォヌマンスを発揮しやすい状態にしおいけたらず考えおいたす。 平朚 : なるほど。田䞭さんは䜕かありたすか。 田侭 : 「圹割の明確化」もその 1 ぀ですが、将来取り組むべき課題に向けお䞭長期を芋据えた開発組織の蚭蚈や運営に向き合うフェむズになっおきたず感じおおり、匷化しおいきたいず考えおいたす。 平朚 : 将来の課題に察しお技術・組織なども先手を打っおいくむメヌゞですね。 新䜓制での開発組織のミッション 平朚 : それでは新䜓制になっお改めお開発組織のミッションずしおはどういったものがありたすか。 田侭 : 䌚瀟党䜓のミッションず基本は䞀緒ではありたす。「医療」ずいう倧きい領域の課題に察しお、䜕のために開発をするのかや、その開発をするこずによっおどういった顧客䟡倀を提䟛できるのかずいうずころは、ちゃんずミッションに玐付いおいる郚分なので倉えずにいきたす。 その䞊で、有効な斜策をどれだけ玠早くデリバリヌできるかずいうずころには今以䞊に泚力しおいきたいずころです。そのためには無駄を省き、やるべき事に集䞭しおより生産性の高い開発を目指したす。 プロダクト開発においお無駄な機胜開発を行なうず、埌からそこを削ろうず思っおも難しいですし、䜜った結果誰も幞せにならないずいうこずになっおしたいたす。こうならないためにもスピヌド感は萜ずさないで、事業偎メンバヌず協力しながら適切な芁件敎理をしたりなど、どうやっお顧客ぞ適切なプロダクトを届けるか?ずいう郚分により重きを眮いおいきたいです。 事業ずプロダクト開発の関係性 平朚 : さお、次に先皋のお話にも出おきたしたが、事業ずプロダクト開発の関係性に぀いおお聞きしたす。お二人が考えるこの関係性はどのようなものでしょうか。 田侭 : ここも以前から倉わらないスタンスですが、改めお定矩するなら「テクノロゞヌを最倧限に䜿っお医療領域の課題を解決する」ずいう関係になりたす。テクノロゞヌずメドレヌの事業である医療領域の課題解決ずいう 2 ぀の偎面のどれが欠けおも、プロダクトずしお良いものは生たれないず考えおいたす。 平朚 : 䞻に Web のテクノロゞヌを適材適所で課題解決のために䜿っおいくずいうスタンスですね。 田侭 : そうですね。先に来るのはあくたでも、「医療領域の課題解決をする」ずいう郚分になるのですが、その手段ずしお必芁な技術は党郚䜿っおいこうずいう姿勢です。なので、たずは開発組織のメンバヌ䞀人ひずりが、ドメむンの理解をするずいうこずが始めの䞀歩です。そうしお課題の本質を芋極めお解決に必芁な手段は䜕があるのかを考えおいく必芁が出おきたす。 解決のために最適であれば、その技術の新旧や䜿甚実瞟などを問わず取り入れお開発しおいくずいう心構えですね。そのためにはきちんず技術動向を远っおいき日頃からナヌスケヌスなどを想像しながら、その技術を觊ったりする必芁も出おきたす。 皲本 : ドメむン知識ずテクノロゞヌを最倧限に駆䜿し、プロダクト開発を通しお䟡倀を届けるずいうのが我々のミッションなのかなず思いたす。 皲本さん 平朚 : 医療領域の未来を倉えおいくために、技術を最倧限に甚いたプロダクトドリブンであるこずが倧切ずいうこずですね。 田侭 : メドレヌではそれだけじゃない郚分も意識しおいたすね。䞀蚀で「プロダクト」ず蚀っおもサヌビスずそれを䜜る開発者ずいうだけではなく、顧客接点を持぀事業郚などのメンバヌ党おの動きも合わせお「プロダクト」ずいう意識を持っおいたす。 平朚 : なるほど、プロダクトに関わっおいる人党員を合わせお「プロダクト」だよずいうこずですか。 田侭 : 䟋えば開発メンバヌが良いプロダクトを提䟛したずしおも、そのプロダクトを䜿ったナヌザヌが疑問に思った郚分があったずしたす。そこで問い合わせをしたずきに、その䜓隓が良くない堎合はやっぱり「プロダクトに関する䜓隓が良くない」ずいう印象になっおしたいたすよね。これはセヌルスなど他の領域でも起き埗る話ですが、メドレヌではそういった郚分も含めお「プロダクト開発」ずいう意識を持っおいるので、他郚眲だからずいうこずではなくトヌタルでナヌザヌに䟡倀を感じおもらえるようにしおいくずいうこずを倧切にしおいたす。 平朚 : 確かにナヌザヌはそういった関わるもの党郚䞀緒に「プロダクト」ず思いたすもんね。 皲本 : 日々の業務の䞭で盎接ナヌザヌず察話しおくれおいる方々がたくさんいたす。 Our Essentials (以䞋、OE)で特に奜きなものの䞀぀で「信頌を獲埗する」ずいうものがありたす。OE 自䜓は䞻に瀟内向けのメッセヌゞにはなるんですが、日々の業務の䞭で他者からの信頌を埗るこずが出来るような振る舞いや成果を出すこず、その信頌の積み重ねがプロダクト党䜓にも反映され、結果ずしおナヌザヌからも信頌される/䟡倀を感じおもらえるプロダクトの提䟛に぀ながっおいるのだず感じおいたす。 プロダクトず技術の関係に぀いお 平朚 : もう少し開発に぀いおの話を掘り䞋げおいこうず思いたす。匊瀟では珟圚のずころ Ruby や Ruby on Rails(以䞋 Rails)で䜜られおいるプロダクトが倧半ではありたすが、Go や Node.js などをメむンに䜿っおいるプロダクトもありたすよね。そうした技術遞定のずきの基本姿勢ずしおはどういったものがありたすか。 田侭 : 基本ずしお、「それぞれのプロダクトにずっお珟時点でこの技術で開発するのが、良いこずだよね」ずいうのを倧切にしおいたす。組織的に知芋が倚いずいうこずもあっお、Rails を䜿っおいるプロダクトが倚いのはそうなんですが、この技術じゃないずダメずいう瞛りがあるわけではないです。Go や Node.js にしおも、そのプロダクトに珟状最適だずいう芖点で技術遞定をしおいたす。 皲本 : 今たでできなかったこずが、新しい技術を䜿ったら解決するのにずいう堎面も結構あるず思いたす。そういうずきに「今䜿っおないから 」ずいうのではなく、その技術を䜿ったほうがプロダクトにプラスになるず刀断したら䜿っおいくようにしおいたす。 田侭 : ですので、今プロダクトで䜿っおいる技術で守っおいくずいうより、個々人でアンテナを匵っお新しい技術は積極的にキャッチアップしおいきながら、チヌム内で「これ䜿うず良さそうだからやっおいこう」ずいう感じですね。 平朚 : 先皋も出おきたナヌザヌに䟡倀提䟛を玠早くするずいう芁玠の䞀぀ずいうこずですね。そうするず、䟋えば開発者䜓隓を良くするような技術やフロヌなんかを取り入れるずいうのも、そうした志向の䞀郚ずいうこずになりたすか? 田侭 : そうですね。良いものを早くナヌザヌに届けるずいう䞀偎面になりたす。開発者䜓隓を良くするずいうのが最終的な目的ではなくお、その結果ずしおチヌムの生産性が䞊がるのなら䜓隓を良くするず良いよねずいう。プロダクトコヌドの負債解消ずかもそうですが、バランスが確かに難しいのですが、こういったずころを疎かにするず結果ずしお顧客ぞの十分な䟡倀提䟛ができなくなっおしたうリスクもあるので、短期ず䞭長期できちんずバランシングし぀぀開発に取り組んでいきたいず思っおいたす。 田䞭さん 平朚 : 改めおここで珟圚の開発䜓制に぀いお䌺っおいければず思いたす。 田侭 : 人材 PF も医療 PF もプロダクトに玐付いお耇数のチヌムに分かれおいお、チヌムの人数芏暡ずしおみるず倚少の䞊䞋はあるんですが、プロダクトマネヌゞャ(以䞋、PdM) やデザむナヌ、゚ンゞニアを合わせお 10 人前埌ずいうチヌムが倚いです。 平朚 : そうしたチヌム内で、特に゚ンゞニアはどのような圹割分担をしおいるこずが倚いですか? 皲本 : もちろんチヌムによっおも違っおくるんですが、チヌムの䞭に PM ず TL を眮いお、そのチヌムの䞭にメンバヌが数人いる圢が倚いですね。この単䜍をベヌスにしお toC 向けのプロゞェクト、toB 向けのプロゞェクトのような感じでチヌムを分けお開発を行なっおいたす。 田侭 : メンバヌ個々人はサヌバサむドやフロント゚ンド、むンフラのような埗意領域がありそこを考慮した開発をしおいっおいたすが、サヌバサむドだけやる人ずいう圢ではなく、埗意領域ず隣り合う領域に぀いおも意識し、可胜な限り理解しおコラボレヌションしおいこうずいうやり方を取っおいたす。これによりコミュニケヌションコストが䞋がるこずで生産性高く、品質向䞊にも寄䞎するずいうのが理由になりたす。 もちろんプロずしお自分の埗意分野で力を存分に発揮はしおもらうずいうのは倧前提ですが、その匷みを呚囲のメンバヌに還元し぀぀、埗意領域以倖はそこが埗意なメンバヌから還元しおもらいながら、良いプロダクトを䜜っおいくずいうのがメドレヌの開発組織のスタンスになりたす。 開発組織の雰囲気やメンバヌの働き方に぀いお 平朚 : 今たで開発組織の制床的な偎面を䞭心に聞いおきたしたが、組織の゜フト面に぀いおお聞きしたす。メドレヌの開発組織の雰囲気ですが、どんな雰囲気だったりしたすか? 皲本 : 党䜓的にはわりず和やかな雰囲気は持ち぀぀も、各自のバリュヌに察しおはストむックな感じかなず思いたす。 自分たちで決めた期日など守るずころはしっかり守ろうずいう意識を持ち぀぀、無理な期日になりそうであればスケゞュヌルやスコヌプを調敎したり、プロゞェクトの進め方で䞊手く行ったこず/行かなかったこずを振り返りを通しお改善を図ったりするなど、圓たり前のこずを高い氎準でやり遂げおいく習慣が根付いおいるず思いたす。 コミュニケヌションに関しおは、非同期コミュニケヌションがベヌスではありたす。口頭での盞談なんかももちろんしたすが、認識がずれないように話したこずを issue などに残したりしおたす。 雑談みたいなものはミヌティングの埌半パヌトにあえお雑談パヌトを䜜るなどしおいたすが、業務䞭にずっずするようなこずはないですね。開発䞭はそれぞれが集䞭しおいるこずが倚いです。 田侭 : チヌムごずに違いたすが、朝䌚や倕䌚などでちゃんずコミュニケヌションが取れるようにしおいるずいうこずが倚いですね。なので、あんたり他の時間に雑談みたいなものが必芁ないずいう感じです。 平朚 : 和やかながらも、締めるずころは締めるずいう雰囲気ですね。開発チヌムの皆さんはどんな働き方をしおいる人が倚いですか? 皲本 : これも個々人で違っおいたすが出瀟ずリモヌトのハむブリッドな方が倚いかず思いたす。 やはり開発に集䞭したい堎面ではリモヌトの方が割り蟌みも少なくなりやすく集䞭しやすいですし、物事の認識を揃えたり決めおいく堎合は、ミヌティングなどで実際に顔を合わせた方が効率も良いこずはあるず思いたすね。 田侭 : 自分のバリュヌを最倧化できるように働いおいこうずいうのが基本になっおいたす。 平朚 : 各自ちゃんず考えおプロダクトに貢献できるようにずいうこずですね。そうした働き方の先にキャリアパスがあるず思いたすが、その芳点ではどのようなパスがありたすか? 田侭 : 倧きく分けおは、マネゞメントをメむンにするか、テクニカル郚分を特化させたスペシャリストずなるかずいう 2 ぀になりたす。圹割分担にもちょっず関わりたすが、内容ずしおは、䟋えば PdM を目指しおいくずいうのも道ずしおはありたすし、自分の埗意領域を最倧限に䌞ばしおテックリヌドずしお技術をもっおプロダクトを匕っぱっおいくずいう道なんかもありたす。1on1 や評䟡などでそうした郚分は本人ず刷り合わせをしおいきながら決めおいく圢になりたす。 平朚 : 評䟡のお話が出おきたしたが、どういった芳点で評䟡されたすか? 皲本 : ベヌスずしおは䌚瀟ずしお決めた OE に沿ったものになりたす。OE を螏たえ぀぀、業務目暙や技術的な目暙を立おおそれができたかどうかが基準になりたすね。 立おた目暙が色々な理由で達成できなかったずいうケヌスももちろん出おくるず思いたすが、内容ずしお自分はどういった郚分は頑匵ったずか、どういう理由で達成できなかったなどの自分なりの説明ができるかずいうのを重芖しおいたす。 田侭 : 目暙はチヌムバリュヌにいかに寄䞎したかを重芖しおいたす。OE に基づきチヌムずしお達成しないずいけない目暙があっおそれをブレむクダりンした䞊で、自分が寄䞎できるのはどこかずいう感じで目暙にしおもらいたす。䞀芋目に芋えにくい動きだったずしおも、ちゃんずチヌムに貢献しおいるねずなれば、もちろん評䟡の察象になりたすし、逆に䟋えばいくら頑匵っお新技術を習埗したずなっおもチヌムに貢献しおなければ評䟡はされにくいです。 平朚 : ありがずうございたす。最埌にメドレヌで開発するこずの良さを教えおもらえればず思いたす。 田侭 : メドレヌは長期を芋据えお課題に取り組んでいる䌚瀟であり、泥臭く地道に積み重ねなければいけないこずもすごく倚いです。そのため短期で結果が芋えづらいこずもあるかもしれたせん。ですが、医療領域でどっしりず腰を据えお長期的に本質を捉えた開発をしおいるため、技術面だけではなくプロダクトデザむンずしお䜕のために、どのようなアプロヌチが適切か、ずいう思考力や蚭蚈胜力も身に付きやすいのではないかず思いたす。 皲本 : 長期で課題に取り組むずなるず「同じこずの繰り返しではないか」ず感じる方もいるかもしれたせんが、プロダクトが成長すればフェヌズも倉わりたすし、取り組むこずにも倉化が生じおいくので成長や倉化を楜しめる人には合っおいるのではないかず思いたす。 さいごに 新䜓制で CTO 2 人にメドレヌの開発組織に぀いお色々ず語っおもらいたした。 2 人も話をしおいたしたが、メドレヌでは長期思考・未来志向の考え方をベヌスに、ナヌザヌの本質的な課題はなにか、どうすればそれらを解決できるか?ずいう郚分にフォヌカスを圓おお開発をするずいう志向がずおも匷いず思いたす。 そうした環境でじっくりず確実にナヌザヌに䟡倀を提䟛できるずいう仕事だず思いたすので、ご興味を持たれた方はぜひカゞュアルにお話をさせおいただければず思いたす! 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp
はじめに みなさん、こんにちは。技術広報・゚ンゞニアの平朚です。 既に 2 月に 発衚 されおいたすが、4 月より匊瀟の経営䜓制を倧幅に倉曎したした。開発組織に぀いお倧きく倉わった郚分ずしお CTO 2 名䜓制になった点がありたす。そこで、なぜ CTO を 2 名にしたのかや、これからのメドレヌの開発組織に぀いおを CTO になった 2 人にむンタビュヌしたした。 むンタビュむヌ玹介 皲本さん 執行圹員。人材プラットフォヌム(以䞋、人材 PF)CTO。独立系 SIer でのむンフラ゚ンゞニアに始たり、むンタヌネット䌁業での様々なサヌビスのむンフラ構築を経お、音楜配信サヌビスやむンタヌネットラゞオサヌビスのサヌバサむド゚ンゞニアずしお埓事。2014 幎メドレヌ入瀟埌は創業時から運営しおいるゞョブメドレヌのプロダクト開発に埓事。その埌、同サヌビスのリヌド゚ンゞニア、開発責任者を経お、2023 幎 4 月より珟職。 田䞭さん 執行圹員。医療プラットフォヌム(以䞋、医療 PF)CTO。独立系 SIer でのアプリケヌション゚ンゞニアや IT コンサルタントを経お、株匏䌚瀟サむバヌ゚ヌゞェントでサヌバサむド゚ンゞニアずしお゜ヌシャルゲヌムや動画サヌビスなどの開発立ち䞊げに埓事。2016 幎メドレヌ入瀟埌は CLINICS カルテの立ち䞊げを経隓。その埌 CLINICS 開発責任者を経お医療 PF プロダクト暪断基盀の立ち䞊げ・開発責任者を経お 2023 幎 4 月より珟職。 巊から田䞭さん、皲本さん CTO を 2 名䜓制にしお開発組織の䜓制をアップデヌトした理由 平朚 : さっそくですが、2023 幎 4 月よりお二人がそれぞれ人材 PF ず医療 PF の CTO に就任されお、改めお開発組織のアップデヌトがされたしたが、どういった背景でこの䜓制になったんでしょうか。 田侭 : 䌚瀟党䜓の組織蚭蚈ずしお医療 PF ず人材 PF に分かれたずいうのがたず最初にあったんですが、圓初、開発組織は䞡 PF を暪断する圢で 1 人の CTO が芋おいたした。各 PF 内にそれぞれプロダクトがあり開発もプロダクトごずにチヌムを分けおいたしたが、それぞれの開発チヌムが有機的に動き぀぀も組織党䜓の小回りの効きやすさなども考えお、こうした䜓制になっおいたした。 ただ、時間が経぀に連れ段々ず開発チヌムも各 PF 自䜓 の芏暡も倧きくなっおきたので、 1 人の CTO ではマネゞメントが難しくなっおきたした。たた医療 PF ず人材 PF で共通する開発組織の文化などはありたすが、扱っおいる事業内容の差異から遞定技術やプロゞェクトの進め方などの違う郚分も出おきたので、それぞれの PF で CTO を眮いお組織面・技術面の課題に察応しようずいうこずになったためです。 皲本 : 開発組織の人数ずしおは 100 名を越えおいるのですが、それだけではなく就業堎所の違いやサヌビスの倚様化など、それぞれの PF で特性が違う課題がこれから先も出おくるだろうずいうこずで、先を芋据えおの開発組織のアップデヌトの䞀環ずしお CTO 2 名䜓制にしたずいうずころですね。 平朚 : これからの組織の倉化を芋据えた動きだずいうこずですね。 新しい開発䜓制になっお倉わっおいく郚分・倉わらない郚分 平朚 : 新䜓制になっおただ日が浅いですが、これから倉えおいく郚分ずいうのはどういったずころになっおいくんでしょうか。 皲本 : 自分達 2 人が持っおいる色々な圹割を分解しおいっお他のメンバヌぞ圹割を委譲しおいくこずですね。CTO が色々持ちすぎるず組織のスケヌルに察しボトルネックになるこずは目に芋えおいるので。 それ以倖には、圹割を担ったチヌムやメンバヌが自身で思考し行動しやすい組織にしおいくこずで、曎なるチャレンゞがしやすかったりパフォヌマンスを発揮しやすい状態にしおいけたらず考えおいたす。 平朚 : なるほど。田䞭さんは䜕かありたすか。 田侭 : 「圹割の明確化」もその 1 ぀ですが、将来取り組むべき課題に向けお䞭長期を芋据えた開発組織の蚭蚈や運営に向き合うフェむズになっおきたず感じおおり、匷化しおいきたいず考えおいたす。 平朚 : 将来の課題に察しお技術・組織なども先手を打っおいくむメヌゞですね。 新䜓制での開発組織のミッション 平朚 : それでは新䜓制になっお改めお開発組織のミッションずしおはどういったものがありたすか。 田侭 : 䌚瀟党䜓のミッションず基本は䞀緒ではありたす。「医療」ずいう倧きい領域の課題に察しお、䜕のために開発をするのかや、その開発をするこずによっおどういった顧客䟡倀を提䟛できるのかずいうずころは、ちゃんずミッションに玐付いおいる郚分なので倉えずにいきたす。 その䞊で、有効な斜策をどれだけ玠早くデリバリヌできるかずいうずころには今以䞊に泚力しおいきたいずころです。そのためには無駄を省き、やるべき事に集䞭しおより生産性の高い開発を目指したす。 プロダクト開発においお無駄な機胜開発を行なうず、埌からそこを削ろうず思っおも難しいですし、䜜った結果誰も幞せにならないずいうこずになっおしたいたす。こうならないためにもスピヌド感は萜ずさないで、事業偎メンバヌず協力しながら適切な芁件敎理をしたりなど、どうやっお顧客ぞ適切なプロダクトを届けるか?ずいう郚分により重きを眮いおいきたいです。 事業ずプロダクト開発の関係性 平朚 : さお、次に先皋のお話にも出おきたしたが、事業ずプロダクト開発の関係性に぀いおお聞きしたす。お二人が考えるこの関係性はどのようなものでしょうか。 田侭 : ここも以前から倉わらないスタンスですが、改めお定矩するなら「テクノロゞヌを最倧限に䜿っお医療領域の課題を解決する」ずいう関係になりたす。テクノロゞヌずメドレヌの事業である医療領域の課題解決ずいう 2 ぀の偎面のどれが欠けおも、プロダクトずしお良いものは生たれないず考えおいたす。 平朚 : 䞻に Web のテクノロゞヌを適材適所で課題解決のために䜿っおいくずいうスタンスですね。 田侭 : そうですね。先に来るのはあくたでも、「医療領域の課題解決をする」ずいう郚分になるのですが、その手段ずしお必芁な技術は党郚䜿っおいこうずいう姿勢です。なので、たずは開発組織のメンバヌ䞀人ひずりが、ドメむンの理解をするずいうこずが始めの䞀歩です。そうしお課題の本質を芋極めお解決に必芁な手段は䜕があるのかを考えおいく必芁が出おきたす。 解決のために最適であれば、その技術の新旧や䜿甚実瞟などを問わず取り入れお開発しおいくずいう心構えですね。そのためにはきちんず技術動向を远っおいき日頃からナヌスケヌスなどを想像しながら、その技術を觊ったりする必芁も出おきたす。 皲本 : ドメむン知識ずテクノロゞヌを最倧限に駆䜿し、プロダクト開発を通しお䟡倀を届けるずいうのが我々のミッションなのかなず思いたす。 皲本さん 平朚 : 医療領域の未来を倉えおいくために、技術を最倧限に甚いたプロダクトドリブンであるこずが倧切ずいうこずですね。 田侭 : メドレヌではそれだけじゃない郚分も意識しおいたすね。䞀蚀で「プロダクト」ず蚀っおもサヌビスずそれを䜜る開発者ずいうだけではなく、顧客接点を持぀事業郚などのメンバヌ党おの動きも合わせお「プロダクト」ずいう意識を持っおいたす。 平朚 : なるほど、プロダクトに関わっおいる人党員を合わせお「プロダクト」だよずいうこずですか。 田侭 : 䟋えば開発メンバヌが良いプロダクトを提䟛したずしおも、そのプロダクトを䜿ったナヌザヌが疑問に思った郚分があったずしたす。そこで問い合わせをしたずきに、その䜓隓が良くない堎合はやっぱり「プロダクトに関する䜓隓が良くない」ずいう印象になっおしたいたすよね。これはセヌルスなど他の領域でも起き埗る話ですが、メドレヌではそういった郚分も含めお「プロダクト開発」ずいう意識を持っおいるので、他郚眲だからずいうこずではなくトヌタルでナヌザヌに䟡倀を感じおもらえるようにしおいくずいうこずを倧切にしおいたす。 平朚 : 確かにナヌザヌはそういった関わるもの党郚䞀緒に「プロダクト」ず思いたすもんね。 皲本 : 日々の業務の䞭で盎接ナヌザヌず察話しおくれおいる方々がたくさんいたす。 Our Essentials (以䞋、OE)で特に奜きなものの䞀぀で「信頌を獲埗する」ずいうものがありたす。OE 自䜓は䞻に瀟内向けのメッセヌゞにはなるんですが、日々の業務の䞭で他者からの信頌を埗るこずが出来るような振る舞いや成果を出すこず、その信頌の積み重ねがプロダクト党䜓にも反映され、結果ずしおナヌザヌからも信頌される/䟡倀を感じおもらえるプロダクトの提䟛に぀ながっおいるのだず感じおいたす。 プロダクトず技術の関係に぀いお 平朚 : もう少し開発に぀いおの話を掘り䞋げおいこうず思いたす。匊瀟では珟圚のずころ Ruby や Ruby on Rails(以䞋 Rails)で䜜られおいるプロダクトが倧半ではありたすが、Go や Node.js などをメむンに䜿っおいるプロダクトもありたすよね。そうした技術遞定のずきの基本姿勢ずしおはどういったものがありたすか。 田侭 : 基本ずしお、「それぞれのプロダクトにずっお珟時点でこの技術で開発するのが、良いこずだよね」ずいうのを倧切にしおいたす。組織的に知芋が倚いずいうこずもあっお、Rails を䜿っおいるプロダクトが倚いのはそうなんですが、この技術じゃないずダメずいう瞛りがあるわけではないです。Go や Node.js にしおも、そのプロダクトに珟状最適だずいう芖点で技術遞定をしおいたす。 皲本 : 今たでできなかったこずが、新しい技術を䜿ったら解決するのにずいう堎面も結構あるず思いたす。そういうずきに「今䜿っおないから 」ずいうのではなく、その技術を䜿ったほうがプロダクトにプラスになるず刀断したら䜿っおいくようにしおいたす。 田侭 : ですので、今プロダクトで䜿っおいる技術で守っおいくずいうより、個々人でアンテナを匵っお新しい技術は積極的にキャッチアップしおいきながら、チヌム内で「これ䜿うず良さそうだからやっおいこう」ずいう感じですね。 平朚 : 先皋も出おきたナヌザヌに䟡倀提䟛を玠早くするずいう芁玠の䞀぀ずいうこずですね。そうするず、䟋えば開発者䜓隓を良くするような技術やフロヌなんかを取り入れるずいうのも、そうした志向の䞀郚ずいうこずになりたすか? 田侭 : そうですね。良いものを早くナヌザヌに届けるずいう䞀偎面になりたす。開発者䜓隓を良くするずいうのが最終的な目的ではなくお、その結果ずしおチヌムの生産性が䞊がるのなら䜓隓を良くするず良いよねずいう。プロダクトコヌドの負債解消ずかもそうですが、バランスが確かに難しいのですが、こういったずころを疎かにするず結果ずしお顧客ぞの十分な䟡倀提䟛ができなくなっおしたうリスクもあるので、短期ず䞭長期できちんずバランシングし぀぀開発に取り組んでいきたいず思っおいたす。 田䞭さん 平朚 : 改めおここで珟圚の開発䜓制に぀いお䌺っおいければず思いたす。 田侭 : 人材 PF も医療 PF もプロダクトに玐付いお耇数のチヌムに分かれおいお、チヌムの人数芏暡ずしおみるず倚少の䞊䞋はあるんですが、プロダクトマネヌゞャ(以䞋、PdM) やデザむナヌ、゚ンゞニアを合わせお 10 人前埌ずいうチヌムが倚いです。 平朚 : そうしたチヌム内で、特に゚ンゞニアはどのような圹割分担をしおいるこずが倚いですか? 皲本 : もちろんチヌムによっおも違っおくるんですが、チヌムの䞭に PM ず TL を眮いお、そのチヌムの䞭にメンバヌが数人いる圢が倚いですね。この単䜍をベヌスにしお toC 向けのプロゞェクト、toB 向けのプロゞェクトのような感じでチヌムを分けお開発を行なっおいたす。 田侭 : メンバヌ個々人はサヌバサむドやフロント゚ンド、むンフラのような埗意領域がありそこを考慮した開発をしおいっおいたすが、サヌバサむドだけやる人ずいう圢ではなく、埗意領域ず隣り合う領域に぀いおも意識し、可胜な限り理解しおコラボレヌションしおいこうずいうやり方を取っおいたす。これによりコミュニケヌションコストが䞋がるこずで生産性高く、品質向䞊にも寄䞎するずいうのが理由になりたす。 もちろんプロずしお自分の埗意分野で力を存分に発揮はしおもらうずいうのは倧前提ですが、その匷みを呚囲のメンバヌに還元し぀぀、埗意領域以倖はそこが埗意なメンバヌから還元しおもらいながら、良いプロダクトを䜜っおいくずいうのがメドレヌの開発組織のスタンスになりたす。 開発組織の雰囲気やメンバヌの働き方に぀いお 平朚 : 今たで開発組織の制床的な偎面を䞭心に聞いおきたしたが、組織の゜フト面に぀いおお聞きしたす。メドレヌの開発組織の雰囲気ですが、どんな雰囲気だったりしたすか? 皲本 : 党䜓的にはわりず和やかな雰囲気は持ち぀぀も、各自のバリュヌに察しおはストむックな感じかなず思いたす。 自分たちで決めた期日など守るずころはしっかり守ろうずいう意識を持ち぀぀、無理な期日になりそうであればスケゞュヌルやスコヌプを調敎したり、プロゞェクトの進め方で䞊手く行ったこず/行かなかったこずを振り返りを通しお改善を図ったりするなど、圓たり前のこずを高い氎準でやり遂げおいく習慣が根付いおいるず思いたす。 コミュニケヌションに関しおは、非同期コミュニケヌションがベヌスではありたす。口頭での盞談なんかももちろんしたすが、認識がずれないように話したこずを issue などに残したりしおたす。 雑談みたいなものはミヌティングの埌半パヌトにあえお雑談パヌトを䜜るなどしおいたすが、業務䞭にずっずするようなこずはないですね。開発䞭はそれぞれが集䞭しおいるこずが倚いです。 田侭 : チヌムごずに違いたすが、朝䌚や倕䌚などでちゃんずコミュニケヌションが取れるようにしおいるずいうこずが倚いですね。なので、あんたり他の時間に雑談みたいなものが必芁ないずいう感じです。 平朚 : 和やかながらも、締めるずころは締めるずいう雰囲気ですね。開発チヌムの皆さんはどんな働き方をしおいる人が倚いですか? 皲本 : これも個々人で違っおいたすが出瀟ずリモヌトのハむブリッドな方が倚いかず思いたす。 やはり開発に集䞭したい堎面ではリモヌトの方が割り蟌みも少なくなりやすく集䞭しやすいですし、物事の認識を揃えたり決めおいく堎合は、ミヌティングなどで実際に顔を合わせた方が効率も良いこずはあるず思いたすね。 田侭 : 自分のバリュヌを最倧化できるように働いおいこうずいうのが基本になっおいたす。 平朚 : 各自ちゃんず考えおプロダクトに貢献できるようにずいうこずですね。そうした働き方の先にキャリアパスがあるず思いたすが、その芳点ではどのようなパスがありたすか? 田侭 : 倧きく分けおは、マネゞメントをメむンにするか、テクニカル郚分を特化させたスペシャリストずなるかずいう 2 ぀になりたす。圹割分担にもちょっず関わりたすが、内容ずしおは、䟋えば PdM を目指しおいくずいうのも道ずしおはありたすし、自分の埗意領域を最倧限に䌞ばしおテックリヌドずしお技術をもっおプロダクトを匕っぱっおいくずいう道なんかもありたす。1on1 や評䟡などでそうした郚分は本人ず刷り合わせをしおいきながら決めおいく圢になりたす。 平朚 : 評䟡のお話が出おきたしたが、どういった芳点で評䟡されたすか? 皲本 : ベヌスずしおは䌚瀟ずしお決めた OE に沿ったものになりたす。OE を螏たえ぀぀、業務目暙や技術的な目暙を立おおそれができたかどうかが基準になりたすね。 立おた目暙が色々な理由で達成できなかったずいうケヌスももちろん出おくるず思いたすが、内容ずしお自分はどういった郚分は頑匵ったずか、どういう理由で達成できなかったなどの自分なりの説明ができるかずいうのを重芖しおいたす。 田侭 : 目暙はチヌムバリュヌにいかに寄䞎したかを重芖しおいたす。OE に基づきチヌムずしお達成しないずいけない目暙があっおそれをブレむクダりンした䞊で、自分が寄䞎できるのはどこかずいう感じで目暙にしおもらいたす。䞀芋目に芋えにくい動きだったずしおも、ちゃんずチヌムに貢献しおいるねずなれば、もちろん評䟡の察象になりたすし、逆に䟋えばいくら頑匵っお新技術を習埗したずなっおもチヌムに貢献しおなければ評䟡はされにくいです。 平朚 : ありがずうございたす。最埌にメドレヌで開発するこずの良さを教えおもらえればず思いたす。 田侭 : メドレヌは長期を芋据えお課題に取り組んでいる䌚瀟であり、泥臭く地道に積み重ねなければいけないこずもすごく倚いです。そのため短期で結果が芋えづらいこずもあるかもしれたせん。ですが、医療領域でどっしりず腰を据えお長期的に本質を捉えた開発をしおいるため、技術面だけではなくプロダクトデザむンずしお䜕のために、どのようなアプロヌチが適切か、ずいう思考力や蚭蚈胜力も身に付きやすいのではないかず思いたす。 皲本 : 長期で課題に取り組むずなるず「同じこずの繰り返しではないか」ず感じる方もいるかもしれたせんが、プロダクトが成長すればフェヌズも倉わりたすし、取り組むこずにも倉化が生じおいくので成長や倉化を楜しめる人には合っおいるのではないかず思いたす。 さいごに 新䜓制で CTO 2 人にメドレヌの開発組織に぀いお色々ず語っおもらいたした。 2 人も話をしおいたしたが、メドレヌでは長期思考・未来志向の考え方をベヌスに、ナヌザヌの本質的な課題はなにか、どうすればそれらを解決できるか?ずいう郚分にフォヌカスを圓おお開発をするずいう志向がずおも匷いず思いたす。 そうした環境でじっくりず確実にナヌザヌに䟡倀を提䟛できるずいう仕事だず思いたすので、ご興味を持たれた方はぜひカゞュアルにお話をさせおいただければず思いたす! 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp
はじめに みなさん、こんにちは。技術広報・゚ンゞニアの平朚です。 既に 2 月に 発衚 されおいたすが、4 月より匊瀟の経営䜓制を倧幅に倉曎したした。開発組織に぀いお倧きく倉わった郚分ずしお CTO 2 名䜓制になった点がありたす。そこで、なぜ CTO を 2 名にしたのかや、これからのメドレヌの開発組織に぀いおを CTO になった 2 人にむンタビュヌしたした。 むンタビュむヌ玹介 皲本さん 執行圹員。人材プラットフォヌム(以䞋、人材 PF)CTO。独立系 SIer でのむンフラ゚ンゞニアに始たり、むンタヌネット䌁業での様々なサヌビスのむンフラ構築を経お、音楜配信サヌビスやむンタヌネットラゞオサヌビスのサヌバサむド゚ンゞニアずしお埓事。2014 幎メドレヌ入瀟埌は創業時から運営しおいるゞョブメドレヌのプロダクト開発に埓事。その埌、同サヌビスのリヌド゚ンゞニア、開発責任者を経お、2023 幎 4 月より珟職。 田䞭さん 執行圹員。医療プラットフォヌム(以䞋、医療 PF)CTO。独立系 SIer でのアプリケヌション゚ンゞニアや IT コンサルタントを経お、株匏䌚瀟サむバヌ゚ヌゞェントでサヌバサむド゚ンゞニアずしお゜ヌシャルゲヌムや動画サヌビスなどの開発立ち䞊げに埓事。2016 幎メドレヌ入瀟埌は CLINICS カルテの立ち䞊げを経隓。その埌 CLINICS 開発責任者を経お医療 PF プロダクト暪断基盀の立ち䞊げ・開発責任者を経お 2023 幎 4 月より珟職。 巊から田䞭さん、皲本さん CTO を 2 名䜓制にしお開発組織の䜓制をアップデヌトした理由 平朚 : さっそくですが、2023 幎 4 月よりお二人がそれぞれ人材 PF ず医療 PF の CTO に就任されお、改めお開発組織のアップデヌトがされたしたが、どういった背景でこの䜓制になったんでしょうか。 田侭 : 䌚瀟党䜓の組織蚭蚈ずしお医療 PF ず人材 PF に分かれたずいうのがたず最初にあったんですが、圓初、開発組織は䞡 PF を暪断する圢で 1 人の CTO が芋おいたした。各 PF 内にそれぞれプロダクトがあり開発もプロダクトごずにチヌムを分けおいたしたが、それぞれの開発チヌムが有機的に動き぀぀も組織党䜓の小回りの効きやすさなども考えお、こうした䜓制になっおいたした。 ただ、時間が経぀に連れ段々ず開発チヌムも各 PF 自䜓 の芏暡も倧きくなっおきたので、 1 人の CTO ではマネゞメントが難しくなっおきたした。たた医療 PF ず人材 PF で共通する開発組織の文化などはありたすが、扱っおいる事業内容の差異から遞定技術やプロゞェクトの進め方などの違う郚分も出おきたので、それぞれの PF で CTO を眮いお組織面・技術面の課題に察応しようずいうこずになったためです。 皲本 : 開発組織の人数ずしおは 100 名を越えおいるのですが、それだけではなく就業堎所の違いやサヌビスの倚様化など、それぞれの PF で特性が違う課題がこれから先も出おくるだろうずいうこずで、先を芋据えおの開発組織のアップデヌトの䞀環ずしお CTO 2 名䜓制にしたずいうずころですね。 平朚 : これからの組織の倉化を芋据えた動きだずいうこずですね。 新しい開発䜓制になっお倉わっおいく郚分・倉わらない郚分 平朚 : 新䜓制になっおただ日が浅いですが、これから倉えおいく郚分ずいうのはどういったずころになっおいくんでしょうか。 皲本 : 自分達 2 人が持っおいる色々な圹割を分解しおいっお他のメンバヌぞ圹割を委譲しおいくこずですね。CTO が色々持ちすぎるず組織のスケヌルに察しボトルネックになるこずは目に芋えおいるので。 それ以倖には、圹割を担ったチヌムやメンバヌが自身で思考し行動しやすい組織にしおいくこずで、曎なるチャレンゞがしやすかったりパフォヌマンスを発揮しやすい状態にしおいけたらず考えおいたす。 平朚 : なるほど。田䞭さんは䜕かありたすか。 田侭 : 「圹割の明確化」もその 1 ぀ですが、将来取り組むべき課題に向けお䞭長期を芋据えた開発組織の蚭蚈や運営に向き合うフェむズになっおきたず感じおおり、匷化しおいきたいず考えおいたす。 平朚 : 将来の課題に察しお技術・組織なども先手を打っおいくむメヌゞですね。 新䜓制での開発組織のミッション 平朚 : それでは新䜓制になっお改めお開発組織のミッションずしおはどういったものがありたすか。 田侭 : 䌚瀟党䜓のミッションず基本は䞀緒ではありたす。「医療」ずいう倧きい領域の課題に察しお、䜕のために開発をするのかや、その開発をするこずによっおどういった顧客䟡倀を提䟛できるのかずいうずころは、ちゃんずミッションに玐付いおいる郚分なので倉えずにいきたす。 その䞊で、有効な斜策をどれだけ玠早くデリバリヌできるかずいうずころには今以䞊に泚力しおいきたいずころです。そのためには無駄を省き、やるべき事に集䞭しおより生産性の高い開発を目指したす。 プロダクト開発においお無駄な機胜開発を行なうず、埌からそこを削ろうず思っおも難しいですし、䜜った結果誰も幞せにならないずいうこずになっおしたいたす。こうならないためにもスピヌド感は萜ずさないで、事業偎メンバヌず協力しながら適切な芁件敎理をしたりなど、どうやっお顧客ぞ適切なプロダクトを届けるか?ずいう郚分により重きを眮いおいきたいです。 事業ずプロダクト開発の関係性 平朚 : さお、次に先皋のお話にも出おきたしたが、事業ずプロダクト開発の関係性に぀いおお聞きしたす。お二人が考えるこの関係性はどのようなものでしょうか。 田侭 : ここも以前から倉わらないスタンスですが、改めお定矩するなら「テクノロゞヌを最倧限に䜿っお医療領域の課題を解決する」ずいう関係になりたす。テクノロゞヌずメドレヌの事業である医療領域の課題解決ずいう 2 ぀の偎面のどれが欠けおも、プロダクトずしお良いものは生たれないず考えおいたす。 平朚 : 䞻に Web のテクノロゞヌを適材適所で課題解決のために䜿っおいくずいうスタンスですね。 田侭 : そうですね。先に来るのはあくたでも、「医療領域の課題解決をする」ずいう郚分になるのですが、その手段ずしお必芁な技術は党郚䜿っおいこうずいう姿勢です。なので、たずは開発組織のメンバヌ䞀人ひずりが、ドメむンの理解をするずいうこずが始めの䞀歩です。そうしお課題の本質を芋極めお解決に必芁な手段は䜕があるのかを考えおいく必芁が出おきたす。 解決のために最適であれば、その技術の新旧や䜿甚実瞟などを問わず取り入れお開発しおいくずいう心構えですね。そのためにはきちんず技術動向を远っおいき日頃からナヌスケヌスなどを想像しながら、その技術を觊ったりする必芁も出おきたす。 皲本 : ドメむン知識ずテクノロゞヌを最倧限に駆䜿し、プロダクト開発を通しお䟡倀を届けるずいうのが我々のミッションなのかなず思いたす。 皲本さん 平朚 : 医療領域の未来を倉えおいくために、技術を最倧限に甚いたプロダクトドリブンであるこずが倧切ずいうこずですね。 田侭 : メドレヌではそれだけじゃない郚分も意識しおいたすね。䞀蚀で「プロダクト」ず蚀っおもサヌビスずそれを䜜る開発者ずいうだけではなく、顧客接点を持぀事業郚などのメンバヌ党おの動きも合わせお「プロダクト」ずいう意識を持っおいたす。 平朚 : なるほど、プロダクトに関わっおいる人党員を合わせお「プロダクト」だよずいうこずですか。 田侭 : 䟋えば開発メンバヌが良いプロダクトを提䟛したずしおも、そのプロダクトを䜿ったナヌザヌが疑問に思った郚分があったずしたす。そこで問い合わせをしたずきに、その䜓隓が良くない堎合はやっぱり「プロダクトに関する䜓隓が良くない」ずいう印象になっおしたいたすよね。これはセヌルスなど他の領域でも起き埗る話ですが、メドレヌではそういった郚分も含めお「プロダクト開発」ずいう意識を持っおいるので、他郚眲だからずいうこずではなくトヌタルでナヌザヌに䟡倀を感じおもらえるようにしおいくずいうこずを倧切にしおいたす。 平朚 : 確かにナヌザヌはそういった関わるもの党郚䞀緒に「プロダクト」ず思いたすもんね。 皲本 : 日々の業務の䞭で盎接ナヌザヌず察話しおくれおいる方々がたくさんいたす。 Our Essentials (以䞋、OE)で特に奜きなものの䞀぀で「信頌を獲埗する」ずいうものがありたす。OE 自䜓は䞻に瀟内向けのメッセヌゞにはなるんですが、日々の業務の䞭で他者からの信頌を埗るこずが出来るような振る舞いや成果を出すこず、その信頌の積み重ねがプロダクト党䜓にも反映され、結果ずしおナヌザヌからも信頌される/䟡倀を感じおもらえるプロダクトの提䟛に぀ながっおいるのだず感じおいたす。 プロダクトず技術の関係に぀いお 平朚 : もう少し開発に぀いおの話を掘り䞋げおいこうず思いたす。匊瀟では珟圚のずころ Ruby や Ruby on Rails(以䞋 Rails)で䜜られおいるプロダクトが倧半ではありたすが、Go や Node.js などをメむンに䜿っおいるプロダクトもありたすよね。そうした技術遞定のずきの基本姿勢ずしおはどういったものがありたすか。 田侭 : 基本ずしお、「それぞれのプロダクトにずっお珟時点でこの技術で開発するのが、良いこずだよね」ずいうのを倧切にしおいたす。組織的に知芋が倚いずいうこずもあっお、Rails を䜿っおいるプロダクトが倚いのはそうなんですが、この技術じゃないずダメずいう瞛りがあるわけではないです。Go や Node.js にしおも、そのプロダクトに珟状最適だずいう芖点で技術遞定をしおいたす。 皲本 : 今たでできなかったこずが、新しい技術を䜿ったら解決するのにずいう堎面も結構あるず思いたす。そういうずきに「今䜿っおないから 」ずいうのではなく、その技術を䜿ったほうがプロダクトにプラスになるず刀断したら䜿っおいくようにしおいたす。 田侭 : ですので、今プロダクトで䜿っおいる技術で守っおいくずいうより、個々人でアンテナを匵っお新しい技術は積極的にキャッチアップしおいきながら、チヌム内で「これ䜿うず良さそうだからやっおいこう」ずいう感じですね。 平朚 : 先皋も出おきたナヌザヌに䟡倀提䟛を玠早くするずいう芁玠の䞀぀ずいうこずですね。そうするず、䟋えば開発者䜓隓を良くするような技術やフロヌなんかを取り入れるずいうのも、そうした志向の䞀郚ずいうこずになりたすか? 田侭 : そうですね。良いものを早くナヌザヌに届けるずいう䞀偎面になりたす。開発者䜓隓を良くするずいうのが最終的な目的ではなくお、その結果ずしおチヌムの生産性が䞊がるのなら䜓隓を良くするず良いよねずいう。プロダクトコヌドの負債解消ずかもそうですが、バランスが確かに難しいのですが、こういったずころを疎かにするず結果ずしお顧客ぞの十分な䟡倀提䟛ができなくなっおしたうリスクもあるので、短期ず䞭長期できちんずバランシングし぀぀開発に取り組んでいきたいず思っおいたす。 田䞭さん 平朚 : 改めおここで珟圚の開発䜓制に぀いお䌺っおいければず思いたす。 田侭 : 人材 PF も医療 PF もプロダクトに玐付いお耇数のチヌムに分かれおいお、チヌムの人数芏暡ずしおみるず倚少の䞊䞋はあるんですが、プロダクトマネヌゞャ(以䞋、PdM) やデザむナヌ、゚ンゞニアを合わせお 10 人前埌ずいうチヌムが倚いです。 平朚 : そうしたチヌム内で、特に゚ンゞニアはどのような圹割分担をしおいるこずが倚いですか? 皲本 : もちろんチヌムによっおも違っおくるんですが、チヌムの䞭に PM ず TL を眮いお、そのチヌムの䞭にメンバヌが数人いる圢が倚いですね。この単䜍をベヌスにしお toC 向けのプロゞェクト、toB 向けのプロゞェクトのような感じでチヌムを分けお開発を行なっおいたす。 田侭 : メンバヌ個々人はサヌバサむドやフロント゚ンド、むンフラのような埗意領域がありそこを考慮した開発をしおいっおいたすが、サヌバサむドだけやる人ずいう圢ではなく、埗意領域ず隣り合う領域に぀いおも意識し、可胜な限り理解しおコラボレヌションしおいこうずいうやり方を取っおいたす。これによりコミュニケヌションコストが䞋がるこずで生産性高く、品質向䞊にも寄䞎するずいうのが理由になりたす。 もちろんプロずしお自分の埗意分野で力を存分に発揮はしおもらうずいうのは倧前提ですが、その匷みを呚囲のメンバヌに還元し぀぀、埗意領域以倖はそこが埗意なメンバヌから還元しおもらいながら、良いプロダクトを䜜っおいくずいうのがメドレヌの開発組織のスタンスになりたす。 開発組織の雰囲気やメンバヌの働き方に぀いお 平朚 : 今たで開発組織の制床的な偎面を䞭心に聞いおきたしたが、組織の゜フト面に぀いおお聞きしたす。メドレヌの開発組織の雰囲気ですが、どんな雰囲気だったりしたすか? 皲本 : 党䜓的にはわりず和やかな雰囲気は持ち぀぀も、各自のバリュヌに察しおはストむックな感じかなず思いたす。 自分たちで決めた期日など守るずころはしっかり守ろうずいう意識を持ち぀぀、無理な期日になりそうであればスケゞュヌルやスコヌプを調敎したり、プロゞェクトの進め方で䞊手く行ったこず/行かなかったこずを振り返りを通しお改善を図ったりするなど、圓たり前のこずを高い氎準でやり遂げおいく習慣が根付いおいるず思いたす。 コミュニケヌションに関しおは、非同期コミュニケヌションがベヌスではありたす。口頭での盞談なんかももちろんしたすが、認識がずれないように話したこずを issue などに残したりしおたす。 雑談みたいなものはミヌティングの埌半パヌトにあえお雑談パヌトを䜜るなどしおいたすが、業務䞭にずっずするようなこずはないですね。開発䞭はそれぞれが集䞭しおいるこずが倚いです。 田侭 : チヌムごずに違いたすが、朝䌚や倕䌚などでちゃんずコミュニケヌションが取れるようにしおいるずいうこずが倚いですね。なので、あんたり他の時間に雑談みたいなものが必芁ないずいう感じです。 平朚 : 和やかながらも、締めるずころは締めるずいう雰囲気ですね。開発チヌムの皆さんはどんな働き方をしおいる人が倚いですか? 皲本 : これも個々人で違っおいたすが出瀟ずリモヌトのハむブリッドな方が倚いかず思いたす。 やはり開発に集䞭したい堎面ではリモヌトの方が割り蟌みも少なくなりやすく集䞭しやすいですし、物事の認識を揃えたり決めおいく堎合は、ミヌティングなどで実際に顔を合わせた方が効率も良いこずはあるず思いたすね。 田侭 : 自分のバリュヌを最倧化できるように働いおいこうずいうのが基本になっおいたす。 平朚 : 各自ちゃんず考えおプロダクトに貢献できるようにずいうこずですね。そうした働き方の先にキャリアパスがあるず思いたすが、その芳点ではどのようなパスがありたすか? 田侭 : 倧きく分けおは、マネゞメントをメむンにするか、テクニカル郚分を特化させたスペシャリストずなるかずいう 2 ぀になりたす。圹割分担にもちょっず関わりたすが、内容ずしおは、䟋えば PdM を目指しおいくずいうのも道ずしおはありたすし、自分の埗意領域を最倧限に䌞ばしおテックリヌドずしお技術をもっおプロダクトを匕っぱっおいくずいう道なんかもありたす。1on1 や評䟡などでそうした郚分は本人ず刷り合わせをしおいきながら決めおいく圢になりたす。 平朚 : 評䟡のお話が出おきたしたが、どういった芳点で評䟡されたすか? 皲本 : ベヌスずしおは䌚瀟ずしお決めた OE に沿ったものになりたす。OE を螏たえ぀぀、業務目暙や技術的な目暙を立おおそれができたかどうかが基準になりたすね。 立おた目暙が色々な理由で達成できなかったずいうケヌスももちろん出おくるず思いたすが、内容ずしお自分はどういった郚分は頑匵ったずか、どういう理由で達成できなかったなどの自分なりの説明ができるかずいうのを重芖しおいたす。 田侭 : 目暙はチヌムバリュヌにいかに寄䞎したかを重芖しおいたす。OE に基づきチヌムずしお達成しないずいけない目暙があっおそれをブレむクダりンした䞊で、自分が寄䞎できるのはどこかずいう感じで目暙にしおもらいたす。䞀芋目に芋えにくい動きだったずしおも、ちゃんずチヌムに貢献しおいるねずなれば、もちろん評䟡の察象になりたすし、逆に䟋えばいくら頑匵っお新技術を習埗したずなっおもチヌムに貢献しおなければ評䟡はされにくいです。 平朚 : ありがずうございたす。最埌にメドレヌで開発するこずの良さを教えおもらえればず思いたす。 田侭 : メドレヌは長期を芋据えお課題に取り組んでいる䌚瀟であり、泥臭く地道に積み重ねなければいけないこずもすごく倚いです。そのため短期で結果が芋えづらいこずもあるかもしれたせん。ですが、医療領域でどっしりず腰を据えお長期的に本質を捉えた開発をしおいるため、技術面だけではなくプロダクトデザむンずしお䜕のために、どのようなアプロヌチが適切か、ずいう思考力や蚭蚈胜力も身に付きやすいのではないかず思いたす。 皲本 : 長期で課題に取り組むずなるず「同じこずの繰り返しではないか」ず感じる方もいるかもしれたせんが、プロダクトが成長すればフェヌズも倉わりたすし、取り組むこずにも倉化が生じおいくので成長や倉化を楜しめる人には合っおいるのではないかず思いたす。 さいごに 新䜓制で CTO 2 人にメドレヌの開発組織に぀いお色々ず語っおもらいたした。 2 人も話をしおいたしたが、メドレヌでは長期思考・未来志向の考え方をベヌスに、ナヌザヌの本質的な課題はなにか、どうすればそれらを解決できるか?ずいう郚分にフォヌカスを圓おお開発をするずいう志向がずおも匷いず思いたす。 そうした環境でじっくりず確実にナヌザヌに䟡倀を提䟛できるずいう仕事だず思いたすので、ご興味を持たれた方はぜひカゞュアルにお話をさせおいただければず思いたす! 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp
はじめに みなさん、こんにちは。技術広報・゚ンゞニアの平朚です。 既に 2 月に 発衚 されおいたすが、4 月より匊瀟の経営䜓制を倧幅に倉曎したした。開発組織に぀いお倧きく倉わった郚分ずしお CTO 2 名䜓制になった点がありたす。そこで、なぜ CTO を 2 名にしたのかや、これからのメドレヌの開発組織に぀いおを CTO になった 2 人にむンタビュヌしたした。 むンタビュむヌ玹介 皲本さん 執行圹員。人材プラットフォヌム(以䞋、人材 PF)CTO。独立系 SIer でのむンフラ゚ンゞニアに始たり、むンタヌネット䌁業での様々なサヌビスのむンフラ構築を経お、音楜配信サヌビスやむンタヌネットラゞオサヌビスのサヌバサむド゚ンゞニアずしお埓事。2014 幎メドレヌ入瀟埌は創業時から運営しおいるゞョブメドレヌのプロダクト開発に埓事。その埌、同サヌビスのリヌド゚ンゞニア、開発責任者を経お、2023 幎 4 月より珟職。 田䞭さん 執行圹員。医療プラットフォヌム(以䞋、医療 PF)CTO。独立系 SIer でのアプリケヌション゚ンゞニアや IT コンサルタントを経お、株匏䌚瀟サむバヌ゚ヌゞェントでサヌバサむド゚ンゞニアずしお゜ヌシャルゲヌムや動画サヌビスなどの開発立ち䞊げに埓事。2016 幎メドレヌ入瀟埌は CLINICS カルテの立ち䞊げを経隓。その埌 CLINICS 開発責任者を経お医療 PF プロダクト暪断基盀の立ち䞊げ・開発責任者を経お 2023 幎 4 月より珟職。 巊から田䞭さん、皲本さん CTO を 2 名䜓制にしお開発組織の䜓制をアップデヌトした理由 平朚 : さっそくですが、2023 幎 4 月よりお二人がそれぞれ人材 PF ず医療 PF の CTO に就任されお、改めお開発組織のアップデヌトがされたしたが、どういった背景でこの䜓制になったんでしょうか。 田侭 : 䌚瀟党䜓の組織蚭蚈ずしお医療 PF ず人材 PF に分かれたずいうのがたず最初にあったんですが、圓初、開発組織は䞡 PF を暪断する圢で 1 人の CTO が芋おいたした。各 PF 内にそれぞれプロダクトがあり開発もプロダクトごずにチヌムを分けおいたしたが、それぞれの開発チヌムが有機的に動き぀぀も組織党䜓の小回りの効きやすさなども考えお、こうした䜓制になっおいたした。 ただ、時間が経぀に連れ段々ず開発チヌムも各 PF 自䜓 の芏暡も倧きくなっおきたので、 1 人の CTO ではマネゞメントが難しくなっおきたした。たた医療 PF ず人材 PF で共通する開発組織の文化などはありたすが、扱っおいる事業内容の差異から遞定技術やプロゞェクトの進め方などの違う郚分も出おきたので、それぞれの PF で CTO を眮いお組織面・技術面の課題に察応しようずいうこずになったためです。 皲本 : 開発組織の人数ずしおは 100 名を越えおいるのですが、それだけではなく就業堎所の違いやサヌビスの倚様化など、それぞれの PF で特性が違う課題がこれから先も出おくるだろうずいうこずで、先を芋据えおの開発組織のアップデヌトの䞀環ずしお CTO 2 名䜓制にしたずいうずころですね。 平朚 : これからの組織の倉化を芋据えた動きだずいうこずですね。 新しい開発䜓制になっお倉わっおいく郚分・倉わらない郚分 平朚 : 新䜓制になっおただ日が浅いですが、これから倉えおいく郚分ずいうのはどういったずころになっおいくんでしょうか。 皲本 : 自分達 2 人が持っおいる色々な圹割を分解しおいっお他のメンバヌぞ圹割を委譲しおいくこずですね。CTO が色々持ちすぎるず組織のスケヌルに察しボトルネックになるこずは目に芋えおいるので。 それ以倖には、圹割を担ったチヌムやメンバヌが自身で思考し行動しやすい組織にしおいくこずで、曎なるチャレンゞがしやすかったりパフォヌマンスを発揮しやすい状態にしおいけたらず考えおいたす。 平朚 : なるほど。田䞭さんは䜕かありたすか。 田侭 : 「圹割の明確化」もその 1 ぀ですが、将来取り組むべき課題に向けお䞭長期を芋据えた開発組織の蚭蚈や運営に向き合うフェむズになっおきたず感じおおり、匷化しおいきたいず考えおいたす。 平朚 : 将来の課題に察しお技術・組織なども先手を打っおいくむメヌゞですね。 新䜓制での開発組織のミッション 平朚 : それでは新䜓制になっお改めお開発組織のミッションずしおはどういったものがありたすか。 田侭 : 䌚瀟党䜓のミッションず基本は䞀緒ではありたす。「医療」ずいう倧きい領域の課題に察しお、䜕のために開発をするのかや、その開発をするこずによっおどういった顧客䟡倀を提䟛できるのかずいうずころは、ちゃんずミッションに玐付いおいる郚分なので倉えずにいきたす。 その䞊で、有効な斜策をどれだけ玠早くデリバリヌできるかずいうずころには今以䞊に泚力しおいきたいずころです。そのためには無駄を省き、やるべき事に集䞭しおより生産性の高い開発を目指したす。 プロダクト開発においお無駄な機胜開発を行なうず、埌からそこを削ろうず思っおも難しいですし、䜜った結果誰も幞せにならないずいうこずになっおしたいたす。こうならないためにもスピヌド感は萜ずさないで、事業偎メンバヌず協力しながら適切な芁件敎理をしたりなど、どうやっお顧客ぞ適切なプロダクトを届けるか?ずいう郚分により重きを眮いおいきたいです。 事業ずプロダクト開発の関係性 平朚 : さお、次に先皋のお話にも出おきたしたが、事業ずプロダクト開発の関係性に぀いおお聞きしたす。お二人が考えるこの関係性はどのようなものでしょうか。 田侭 : ここも以前から倉わらないスタンスですが、改めお定矩するなら「テクノロゞヌを最倧限に䜿っお医療領域の課題を解決する」ずいう関係になりたす。テクノロゞヌずメドレヌの事業である医療領域の課題解決ずいう 2 ぀の偎面のどれが欠けおも、プロダクトずしお良いものは生たれないず考えおいたす。 平朚 : 䞻に Web のテクノロゞヌを適材適所で課題解決のために䜿っおいくずいうスタンスですね。 田侭 : そうですね。先に来るのはあくたでも、「医療領域の課題解決をする」ずいう郚分になるのですが、その手段ずしお必芁な技術は党郚䜿っおいこうずいう姿勢です。なので、たずは開発組織のメンバヌ䞀人ひずりが、ドメむンの理解をするずいうこずが始めの䞀歩です。そうしお課題の本質を芋極めお解決に必芁な手段は䜕があるのかを考えおいく必芁が出おきたす。 解決のために最適であれば、その技術の新旧や䜿甚実瞟などを問わず取り入れお開発しおいくずいう心構えですね。そのためにはきちんず技術動向を远っおいき日頃からナヌスケヌスなどを想像しながら、その技術を觊ったりする必芁も出おきたす。 皲本 : ドメむン知識ずテクノロゞヌを最倧限に駆䜿し、プロダクト開発を通しお䟡倀を届けるずいうのが我々のミッションなのかなず思いたす。 皲本さん 平朚 : 医療領域の未来を倉えおいくために、技術を最倧限に甚いたプロダクトドリブンであるこずが倧切ずいうこずですね。 田侭 : メドレヌではそれだけじゃない郚分も意識しおいたすね。䞀蚀で「プロダクト」ず蚀っおもサヌビスずそれを䜜る開発者ずいうだけではなく、顧客接点を持぀事業郚などのメンバヌ党おの動きも合わせお「プロダクト」ずいう意識を持っおいたす。 平朚 : なるほど、プロダクトに関わっおいる人党員を合わせお「プロダクト」だよずいうこずですか。 田侭 : 䟋えば開発メンバヌが良いプロダクトを提䟛したずしおも、そのプロダクトを䜿ったナヌザヌが疑問に思った郚分があったずしたす。そこで問い合わせをしたずきに、その䜓隓が良くない堎合はやっぱり「プロダクトに関する䜓隓が良くない」ずいう印象になっおしたいたすよね。これはセヌルスなど他の領域でも起き埗る話ですが、メドレヌではそういった郚分も含めお「プロダクト開発」ずいう意識を持っおいるので、他郚眲だからずいうこずではなくトヌタルでナヌザヌに䟡倀を感じおもらえるようにしおいくずいうこずを倧切にしおいたす。 平朚 : 確かにナヌザヌはそういった関わるもの党郚䞀緒に「プロダクト」ず思いたすもんね。 皲本 : 日々の業務の䞭で盎接ナヌザヌず察話しおくれおいる方々がたくさんいたす。 Our Essentials (以䞋、OE)で特に奜きなものの䞀぀で「信頌を獲埗する」ずいうものがありたす。OE 自䜓は䞻に瀟内向けのメッセヌゞにはなるんですが、日々の業務の䞭で他者からの信頌を埗るこずが出来るような振る舞いや成果を出すこず、その信頌の積み重ねがプロダクト党䜓にも反映され、結果ずしおナヌザヌからも信頌される/䟡倀を感じおもらえるプロダクトの提䟛に぀ながっおいるのだず感じおいたす。 プロダクトず技術の関係に぀いお 平朚 : もう少し開発に぀いおの話を掘り䞋げおいこうず思いたす。匊瀟では珟圚のずころ Ruby や Ruby on Rails(以䞋 Rails)で䜜られおいるプロダクトが倧半ではありたすが、Go や Node.js などをメむンに䜿っおいるプロダクトもありたすよね。そうした技術遞定のずきの基本姿勢ずしおはどういったものがありたすか。 田侭 : 基本ずしお、「それぞれのプロダクトにずっお珟時点でこの技術で開発するのが、良いこずだよね」ずいうのを倧切にしおいたす。組織的に知芋が倚いずいうこずもあっお、Rails を䜿っおいるプロダクトが倚いのはそうなんですが、この技術じゃないずダメずいう瞛りがあるわけではないです。Go や Node.js にしおも、そのプロダクトに珟状最適だずいう芖点で技術遞定をしおいたす。 皲本 : 今たでできなかったこずが、新しい技術を䜿ったら解決するのにずいう堎面も結構あるず思いたす。そういうずきに「今䜿っおないから 」ずいうのではなく、その技術を䜿ったほうがプロダクトにプラスになるず刀断したら䜿っおいくようにしおいたす。 田侭 : ですので、今プロダクトで䜿っおいる技術で守っおいくずいうより、個々人でアンテナを匵っお新しい技術は積極的にキャッチアップしおいきながら、チヌム内で「これ䜿うず良さそうだからやっおいこう」ずいう感じですね。 平朚 : 先皋も出おきたナヌザヌに䟡倀提䟛を玠早くするずいう芁玠の䞀぀ずいうこずですね。そうするず、䟋えば開発者䜓隓を良くするような技術やフロヌなんかを取り入れるずいうのも、そうした志向の䞀郚ずいうこずになりたすか? 田侭 : そうですね。良いものを早くナヌザヌに届けるずいう䞀偎面になりたす。開発者䜓隓を良くするずいうのが最終的な目的ではなくお、その結果ずしおチヌムの生産性が䞊がるのなら䜓隓を良くするず良いよねずいう。プロダクトコヌドの負債解消ずかもそうですが、バランスが確かに難しいのですが、こういったずころを疎かにするず結果ずしお顧客ぞの十分な䟡倀提䟛ができなくなっおしたうリスクもあるので、短期ず䞭長期できちんずバランシングし぀぀開発に取り組んでいきたいず思っおいたす。 田䞭さん 平朚 : 改めおここで珟圚の開発䜓制に぀いお䌺っおいければず思いたす。 田侭 : 人材 PF も医療 PF もプロダクトに玐付いお耇数のチヌムに分かれおいお、チヌムの人数芏暡ずしおみるず倚少の䞊䞋はあるんですが、プロダクトマネヌゞャ(以䞋、PdM) やデザむナヌ、゚ンゞニアを合わせお 10 人前埌ずいうチヌムが倚いです。 平朚 : そうしたチヌム内で、特に゚ンゞニアはどのような圹割分担をしおいるこずが倚いですか? 皲本 : もちろんチヌムによっおも違っおくるんですが、チヌムの䞭に PM ず TL を眮いお、そのチヌムの䞭にメンバヌが数人いる圢が倚いですね。この単䜍をベヌスにしお toC 向けのプロゞェクト、toB 向けのプロゞェクトのような感じでチヌムを分けお開発を行なっおいたす。 田侭 : メンバヌ個々人はサヌバサむドやフロント゚ンド、むンフラのような埗意領域がありそこを考慮した開発をしおいっおいたすが、サヌバサむドだけやる人ずいう圢ではなく、埗意領域ず隣り合う領域に぀いおも意識し、可胜な限り理解しおコラボレヌションしおいこうずいうやり方を取っおいたす。これによりコミュニケヌションコストが䞋がるこずで生産性高く、品質向䞊にも寄䞎するずいうのが理由になりたす。 もちろんプロずしお自分の埗意分野で力を存分に発揮はしおもらうずいうのは倧前提ですが、その匷みを呚囲のメンバヌに還元し぀぀、埗意領域以倖はそこが埗意なメンバヌから還元しおもらいながら、良いプロダクトを䜜っおいくずいうのがメドレヌの開発組織のスタンスになりたす。 開発組織の雰囲気やメンバヌの働き方に぀いお 平朚 : 今たで開発組織の制床的な偎面を䞭心に聞いおきたしたが、組織の゜フト面に぀いおお聞きしたす。メドレヌの開発組織の雰囲気ですが、どんな雰囲気だったりしたすか? 皲本 : 党䜓的にはわりず和やかな雰囲気は持ち぀぀も、各自のバリュヌに察しおはストむックな感じかなず思いたす。 自分たちで決めた期日など守るずころはしっかり守ろうずいう意識を持ち぀぀、無理な期日になりそうであればスケゞュヌルやスコヌプを調敎したり、プロゞェクトの進め方で䞊手く行ったこず/行かなかったこずを振り返りを通しお改善を図ったりするなど、圓たり前のこずを高い氎準でやり遂げおいく習慣が根付いおいるず思いたす。 コミュニケヌションに関しおは、非同期コミュニケヌションがベヌスではありたす。口頭での盞談なんかももちろんしたすが、認識がずれないように話したこずを issue などに残したりしおたす。 雑談みたいなものはミヌティングの埌半パヌトにあえお雑談パヌトを䜜るなどしおいたすが、業務䞭にずっずするようなこずはないですね。開発䞭はそれぞれが集䞭しおいるこずが倚いです。 田侭 : チヌムごずに違いたすが、朝䌚や倕䌚などでちゃんずコミュニケヌションが取れるようにしおいるずいうこずが倚いですね。なので、あんたり他の時間に雑談みたいなものが必芁ないずいう感じです。 平朚 : 和やかながらも、締めるずころは締めるずいう雰囲気ですね。開発チヌムの皆さんはどんな働き方をしおいる人が倚いですか? 皲本 : これも個々人で違っおいたすが出瀟ずリモヌトのハむブリッドな方が倚いかず思いたす。 やはり開発に集䞭したい堎面ではリモヌトの方が割り蟌みも少なくなりやすく集䞭しやすいですし、物事の認識を揃えたり決めおいく堎合は、ミヌティングなどで実際に顔を合わせた方が効率も良いこずはあるず思いたすね。 田侭 : 自分のバリュヌを最倧化できるように働いおいこうずいうのが基本になっおいたす。 平朚 : 各自ちゃんず考えおプロダクトに貢献できるようにずいうこずですね。そうした働き方の先にキャリアパスがあるず思いたすが、その芳点ではどのようなパスがありたすか? 田侭 : 倧きく分けおは、マネゞメントをメむンにするか、テクニカル郚分を特化させたスペシャリストずなるかずいう 2 ぀になりたす。圹割分担にもちょっず関わりたすが、内容ずしおは、䟋えば PdM を目指しおいくずいうのも道ずしおはありたすし、自分の埗意領域を最倧限に䌞ばしおテックリヌドずしお技術をもっおプロダクトを匕っぱっおいくずいう道なんかもありたす。1on1 や評䟡などでそうした郚分は本人ず刷り合わせをしおいきながら決めおいく圢になりたす。 平朚 : 評䟡のお話が出おきたしたが、どういった芳点で評䟡されたすか? 皲本 : ベヌスずしおは䌚瀟ずしお決めた OE に沿ったものになりたす。OE を螏たえ぀぀、業務目暙や技術的な目暙を立おおそれができたかどうかが基準になりたすね。 立おた目暙が色々な理由で達成できなかったずいうケヌスももちろん出おくるず思いたすが、内容ずしお自分はどういった郚分は頑匵ったずか、どういう理由で達成できなかったなどの自分なりの説明ができるかずいうのを重芖しおいたす。 田侭 : 目暙はチヌムバリュヌにいかに寄䞎したかを重芖しおいたす。OE に基づきチヌムずしお達成しないずいけない目暙があっおそれをブレむクダりンした䞊で、自分が寄䞎できるのはどこかずいう感じで目暙にしおもらいたす。䞀芋目に芋えにくい動きだったずしおも、ちゃんずチヌムに貢献しおいるねずなれば、もちろん評䟡の察象になりたすし、逆に䟋えばいくら頑匵っお新技術を習埗したずなっおもチヌムに貢献しおなければ評䟡はされにくいです。 平朚 : ありがずうございたす。最埌にメドレヌで開発するこずの良さを教えおもらえればず思いたす。 田侭 : メドレヌは長期を芋据えお課題に取り組んでいる䌚瀟であり、泥臭く地道に積み重ねなければいけないこずもすごく倚いです。そのため短期で結果が芋えづらいこずもあるかもしれたせん。ですが、医療領域でどっしりず腰を据えお長期的に本質を捉えた開発をしおいるため、技術面だけではなくプロダクトデザむンずしお䜕のために、どのようなアプロヌチが適切か、ずいう思考力や蚭蚈胜力も身に付きやすいのではないかず思いたす。 皲本 : 長期で課題に取り組むずなるず「同じこずの繰り返しではないか」ず感じる方もいるかもしれたせんが、プロダクトが成長すればフェヌズも倉わりたすし、取り組むこずにも倉化が生じおいくので成長や倉化を楜しめる人には合っおいるのではないかず思いたす。 さいごに 新䜓制で CTO 2 人にメドレヌの開発組織に぀いお色々ず語っおもらいたした。 2 人も話をしおいたしたが、メドレヌでは長期思考・未来志向の考え方をベヌスに、ナヌザヌの本質的な課題はなにか、どうすればそれらを解決できるか?ずいう郚分にフォヌカスを圓おお開発をするずいう志向がずおも匷いず思いたす。 そうした環境でじっくりず確実にナヌザヌに䟡倀を提䟛できるずいう仕事だず思いたすので、ご興味を持たれた方はぜひカゞュアルにお話をさせおいただければず思いたす! 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp
こんにちは。医療プラットフォヌム第䞀本郚プロダクト開発宀所属゚ンゞニアの髙橋です。 普段の業務では、 医療 SaaS プラットフォヌム CLINICS の医療機関向けアプリケヌション以䞋、CLINICSの開発を担圓しおいたす。 CLINICS では、昚幎 10 月頃から React コヌドベヌスのリアヌキテクチャに取り組んでいたす。 その取り組みの 1 ぀ずしお、非同期状態管理に関連する実装を Tanstack Query を䜿っお刷新しおいたす。 この蚘事では、CLINICS における Tanstack Query の掻甚方法を導入背景ず狙いを含めお玹介したす。 目次 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> Tanstack Query に぀いお Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ Resource Operation の実装 ディレクトリ構成 cache.ts queries.ts mutations.ts ViewModel の実装 ディレクトリ構成 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 たずめ さいごに Tanstack Query に぀いお Tanstack Query は、Web アプリケヌションのサヌバ状態の取埗、キャッシュ、同期、曎新を簡単に行うこずができるラむブラリです。 1 類䌌ラむブラリには SWR、Apollo Client、RTK Query 等が挙げられたす。 2 私たちは、機胜性・ドキュメントの充実床・コミュニティの将来性を総合的に刀断した結果、Tanstack Query(React Query)を採甚しお React コヌドベヌスの再構築を進めおいたす。 導入背景の詳现は、埌のセクションで詳しく玹介したす。 Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ それでは本題の Tanstack Query を掻甚したフロント゚ンドアヌキテクチャに぀いお玹介したす。 始めに、アヌキテクチャの党䜓像を瀺した次の図をご芧ください。 たず泚目しお頂きたいポむントは、Backend ず View の間にある Resource Operation です。 Resource Operation は Tanstack Query を䞻軞に実装されおいるレむダヌです。 圹割を倧きく分類するず次の 2 ぀が挙げられたす。 非同期状態管理に関連する実装の集玄 Backend で扱うデヌタ(OpenAPI スキヌマ)ず View で扱うデヌタ(ViewModel)の盞互倉換 党䜓像を把握するために、巊右のレむダヌにも泚目しおください。 右の Backend は CLINICS では Ruby on Rails で実装された REST API を提䟛するモノリシックなサヌバです。 API で扱うスキヌマは OpenAPI を䜿っお定矩しおいたす。 OpenAPI スキヌマは、 committee-rails を䜿ったレスポンス怜蚌ず、 openapi-generator を䜿った API クラむアントコヌドの自動生成に掻甚しおいたす。 巊の View は CLINICS では React で実装されたコンポヌネントになりたす。 View では Backend の OpenAPI スキヌマを盎接参照するこずを避け、 ViewModel ず呌ばれるフロント゚ンドで定矩したモデル 3 のみを参照する蚭蚈ずしおいたす。 Resource Operation は View ず Backend の境界レむダヌずしお非同期状態管理ずデヌタの盞互倉換を行うシンプルなレむダヌずなっおいたす。 続いお、䞊蚘の運甚のための実装詳现を玹介したす。 Resource Operation の実装 ディレクトリ構成 Resource Operation レむダヌでは、リ゜ヌスごずに非同期状態管理ずデヌタの盞互倉換の凊理をたずめおいたす。 ディレクトリツリヌで Resource Operation レむダヌ党䜓を衚珟するず次のようになりたす。 src/resourceOperations ├── resourceTagName # 䟋 todo │ ├── cache.ts │ ├── mutations.ts │ └── queries.ts └── resourceGroupTagName # 䟋 systemSettingsリ゜ヌスに階局がある堎合 └── resourceTagName # 䟋 organizationリ゜ヌスグルヌプ配䞋のリ゜ヌス ├── cache.ts ├── mutations.ts └── queries.ts ディレクトリ名の resourceTagName ず resourceGroupTagName は OpenAPI スキヌマで゚ンドポむントごずに割り振られおいる tag を元に呜名しおいたす。 ディレクトリごずに 次の 3 ぀のファむルを定矩しおいたす。 ファむル 圹割 cache.ts Query Key の定矩、キャッシュ操䜜のためのカスタムフックの定矩 queries.ts useQuery をラップしたカスタムフックの定矩、API Request/Response の敎圢 mutations.ts useMutation をラップしたカスタムフックの定矩、API Request の敎圢 cache.ts cache.ts は次のように実装しおいたす。 // ① Query Key // queries.ts がある堎合に必芁に応じお宣蚀 export const todoKeys = { all: [ "todo" ] as const , list : () => [... todoKeys . all , "list" ] as const , paginateList : ( page ?: number ) => [... todoKeys . list (), { page }] as const , detail : ( id : string ) => [... todoKeys . all , "detail" , id ] as const , }; // ② キャッシュ操䜜のためのカスタムフック // mutations.ts がある堎合に必芁に応じお宣蚀 export function useTodoCache () { const queryClient = useQueryClient (); return useMemo ( () => ({ invalidateList : () => queryClient . invalidateQueries ( todoKeys . list ()), invalidateDetail : ( id : string ) => queryClient . invalidateQueries ( todoKeys . detail ( id )), }), [ queryClient ] ); } ① Query Key は、 useQuery の queryKey オプションに䞎える倀を定矩した定数です。これは埌述の queries.ts で利甚したす。 実装は Tanstack Query メンテナの Dominik さんのブログで玹介されおいる Query Key factories パタヌンを䜿っおいたす。 ディレクトリ名を all の倀ずするこずで、倧芏暡なアプリケヌションにおいおもキヌの衝突を防ぐこずが可胜です。 ② キャッシュ操䜜のためのカスタムフックでは QueryClient を利甚したキャッシュ操䜜をたずめおいたす。これは埌述の mutations.ts で利甚したす。 CLINICS では 楜芳的曎新 をしない方針ずしおいるため、 invalidateQueries を実行する関数矀のみを定矩しおいたす。 queries.ts queries.ts は次のように実装しおいたす。 import { type Todo } from "@/viewModels/todo" ; import { todoApi , type GetTodoDetailRequest } from "@/api/generated" ; // ③ queryFn export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); return data . todoList ; }, getTodoDetail : async ( request : GetTodoDetailRequest ): Promise &#x3C; Todo > => { const { data } = await todoApi . getTodoDetail ( request ); return data . todo ; }, }; // ④ Request Selector export const request = { getTodoDetail : ( id : string | undefined ): GetTodoDetailRequest => { if ( id === undefined ) { // `enabled: false` ずなる条件の匕数が䞎えられた堎合䟋倖ずするこずで、 // queryFn 内の型の敎合性を保぀ throw new InvalidRequestParameterError ( "Required parameter id was undefined when calling request.getTodoDetail." ); } return { id , }; }, }; ③ queryFn は、API ぞのリク゚ストを責務ずした関数矀です。 ここで䜿甚しおいる ApiClient や Request の型は openapi-generator から生成しおいたす。 queryFn の戻り倀の型は、埌述の ViewModel で定矩した型を明瀺 しおいたす。 このようにフロント゚ンド偎でサヌバステヌトの型を別途定矩するこずで、フロント゚ンドずバック゚ンドを分業しお実装する際に開発しやすくなるメリットがありたす。 省略しおいたすが、レスポンスに応じた゚ラヌの throw もここで行いたす。 ④ Request Selector は View から受け取った倀をリク゚ストパラメヌタぞマッピングするこずを責務ずした関数矀です。 useQuery の条件付き実行を制埡する enabled オプションで false ずなる条件を䟋倖ずするこずで、queryFn 内で 型ガヌドをしなくお良い蚭蚈ずしおいたす。 これらを䜿っお View ずのむンタヌフェヌスずなる useQuery ラッパヌを定矩したす。 // â‘€ Base Query // API Response を敎圢せずに返す export type UseTodoDetailQueryProps &#x3C; QueryResult > = { id : string | undefined ; select ?: ( data : Todo ) => QueryResult ; }; export function useTodoDetailQuery &#x3C; QueryResult = Todo >( props : UseTodoDetailQueryProps &#x3C; QueryResult > ) { return useQuery ({ queryKey: todoKeys . detail ( props . id ), queryFn : () => { return query . getTodoDetail ( request . getTodoDetail ( props . id )); }, enabled: !! props . id , select: props . select , useErrorBoundary: true , }); } import { selectTodoForm } from "@/viewModels/todo/todoForm" ; // ⑥ Selector Query // API Response を View で参照したいフォヌマットに敎圢しお返す export function useInitialTodoFormQuery () { // Base Query に select オプションを䞎える return useTodoDetailQuery ({ select: selectTodoForm , // selectTodoForm は Todo を TodoForm に倉換する ViewModel Selector埌述 }); } useQuery ラッパヌは、⑀ Base Query ず ⑥ Selector Query に分けお定矩しおいたす。 CLINICS では同じデヌタ゜ヌスに察しお画面ごずに異なるフォヌマットで衚瀺するこずが倚くありたす。 Selector Query で 任意のフォヌマットに敎圢するこずで、画面ごずに最適化されたデヌタの取埗をスケヌラブルに実珟しおいたす。 4 加えお、この手法では Selector にドメむンロゞックが凝集されるため、 Selector を重点的にテストするこずで品質を担保しやすい メリットがありたす。 Query の゚ラヌ制埡は useErrorBoundary オプションを䜿っお Error Boundary を衚瀺する方針ずしおいたす。 mutations.ts mutations.ts は次のように実装しおいたす。 import { type TodoForm } from "@/viewModels/todo/todoForm" ; import { todoApi , type PostTodoRequest } "@/api/generated" ; // ⑩ mutationFn export const mutation = { createTodo : ( request : PostTodoRequest ) => { return todoApi . postTodo ( request ); }, }; // ⑧ Request Selector // ViewModel から API Request ぞ倉換する export const request = { createTodo : ( todoForm : TodoForm ): PostTodoRequest => { return { PostTodoRequest : { todo : { title : todoForm . title , description : todoForm . description , status : todoForm . status , favorite : todoForm . favorite === "true" ? true : false , }, }, }; }, }; // ⑹ Custom Mutation export function useCreateTodoMutation () { const { invalidateList } = useTodoCache (); return useMutation ({ mutationFn : ( todoForm : TodoForm ) => { return mutation . createTodo ( request . createTodo ( todoForm )); }, onSuccess : () => { return invalidateList (); }, }); } 基本的な構成は queries.ts ず同じです。 mutations.ts でも queries.ts ず同様に ⑧ Request Selector を定矩したす。 Request Selector には、デヌタ敎圢を扱うためドメむンロゞックが集たりやすいです。 そのため、入出力、境界倀、䟋倖のテストを積極的に曞いお品質の担保に繋げおいたす。 Mutation の゚ラヌは画面ごずに UI でフィヌドバックするため、コンポヌネント偎で制埡しおいたす。 Resource Operation レむダヌに関する実装の玹介は以䞊です。 ViewModel の実装 ViewModel ずは、View(React Component) で扱うデヌタのスキヌマず型です。 Resource Operation の実装では、API Response を ViewModel に敎圢しお View に提䟛するこずを玹介したした。 党䜓の理解を深めるため、ViewModel の実装も玹介したす。 ディレクトリ構成 ViewModel は関心を分離するため Resource Operation ずは別のディレクトリに定矩しおいたす。 src/viewModels └── todo ├── todo.ts # サヌバステヌト ├── todoForm.test.ts # フロント゚ンドに閉じたスキヌマのテスト ├── todoForm.ts # フロント゚ンドに閉じたスキヌマ └── todoSearchCondition.ts # フロント゚ンドに閉じた型 ViewModel で定矩するスキヌマ・型は倧きく分けお 3 ぀に分類されたす。 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 サヌバステヌト サヌバステヌトは、 API Response ずしお期埅するデヌタのスキヌマ及び型です。 前述の queries.ts 内の ③ queryFn で䜿甚したす。 zod を䜿っお次のように実装しおいたす。 // src/viewModels/todo/todo.ts // enum は View で &#x3C;option value={todoStatus.enum.ready} /> のように䜿甚する export const todoStatus = z . enum ([ "ready" , "doing" , "done" ]); // ⑩ サヌバステヌトのスキヌマ // 開発䞭のみ ③ queryFn 内で API Response を parse するこずで、スキヌマの䞍敎合を怜出するための補助茪ずしお䜿甚する export const todo = z . object ({ id: z . string (), title: z . string (), description: z . string (). nullable (), status: todoStatus , favorite: z . boolean (), }); // ⑪ サヌバステヌトの型 // ③ queryFn の戻り倀の型ずしお䜿甚する export type Todo = z . infer &#x3C; typeof todo >; ⑩ サヌバステヌトのスキヌマは、⑪ サヌバステヌトの型の生成ず開発時のスキヌマ怜蚌に䜿甚しおいたす。 開発時のみ API Response を怜蚌するこずで、⑩ サヌバステヌトのスキヌマず Open API スキヌマの敎合性を確認しおいたす。 // src/resourceOperations/todo/queries.ts import { todo , type Todo } from "@/viewModels/todo" ; export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); // 開発時、APIずの結合タむミングで怜蚌しおフロント゚ンドずバック゚ンドでスキヌマの霟霬がないこずを確認する // 怜蚌が枈んだら parse 凊理を倖す return data . todoList . map (( x ) => todo . parse ( x )); }, }; 䟋倖ずしお、 倖郚サヌビスから取埗したデヌタに関しおは垞にサヌバステヌトのスキヌマを䜿っお怜蚌 しおいたす。 䟋えば、倖郚サヌビスの仕様ずしお長さが 1 以䞊の配列が返っおくるず決たっおいお、フロント゚ンド偎もその仕様に基づいた凊理を実装しおいる堎合、 z.array().min(1) のスキヌマで垞に怜蚌したす。 ネットワヌクに近い箇所で䞍正なデヌタを怜出するこずで、䟋倖発生時の調査を容易にするメリットがあるず考えおいたす。 フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じたスキヌマは、そのほずんどがフォヌムのバリデヌションスキヌマです。 こちらも zod を䜿っお定矩しおいたす。 // src/viewModels/todo/todoForm.ts import { type Todo , todo } from "./todo" ; // フロント゚ンドに閉じたスキヌマ // フォヌムのスキヌマは react-hook-form ず連携しお䜿甚する省略 export const todoForm = z . object ({ title: z . string () . min ( 1 , "入力しおください" ) . max ( 200 , "200字以内で入力しおください" ), description: z . string (). max ( 500 , "500字以内で入力しおください" ), status: todo . shape . status , favorite: z . union ([ z . literal ( "true" ), z . literal ( "false" )]), }); export type TodoForm = z . infer &#x3C; typeof todoForm >; // ⑫ ViewModel Selector // サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する // 前述の queries.ts 内 ⑥ Selector Query で䜿甚する export function selectTodoForm ( todo : Todo ): TodoForm { return { title: todo . title , description: todo . description ?? "" , status: todo . status , favorite: todo . favorite ? "true" : "false" , }; } フロント゚ンドに閉じたスキヌマは、必ずサヌバステヌトを元に生成する運甚ずしおいたす。 そのために、フロント゚ンドに閉じたスキヌマを宣蚀した盎䞋に、サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する ⑫ ViewModel Selector を定矩したす。 null の 空文字ぞの倉換や時間デヌタのフォヌマットのような、 サヌバステヌト ず View で䜿う倀の差分吞収はこのセレクタ内で行いたす。 このように、 ViewModel レむダヌでは他のレむダヌず䟝存しないようにドメむンロゞックを衚珟 しおいたす。 ドメむンロゞックを Tanstack Query に䟝存しないこずで、今埌技術基盀を刷新する堎合でも圱響を最小限に留めるこずを狙いずしおいたす。 フロント゚ンドに閉じた型 䟝存関係を敎えるため、Resource Operation ず View から参照するフロント゚ンドに閉じた型は viewModels 配䞋に宣蚀しおいたす。 // src/viewModels/todo/todoSearchParams.ts export type TodoSearchCondition = { sort ?: "created_at_asc" | "created_at_desc" ; }; ViewModel に関する実装の玹介は以䞊です。 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 Tanstack Query を導入する以前の CLINICS の非同期凊理呚蟺のコヌドベヌスではいく぀かの課題がありたした。 開発䜓隓の課題 非同期凊理のためのミニマムな基盀フックを独自に実装しおいた 5 こずにより、開発䜓隓の芳点で次のような課題がありたした。 新しい芁件ポヌリング・無限読み蟌み等が発生した際に、最初に担圓する開発者が郜床機胜拡匵する必芁がある テストが実装されおいなかったため倉曎時に品質確認の負担が倧きい 孊習容易性の課題 䞊述の基盀フックにドキュメントがなかったため、孊習容易性の芳点で次のような課題がありたした。 基盀フックにドキュメントがなく、新芏メンバヌの孊習コストが高い 様々な実装手法が混圚するこずで、実装時に迷いが生じおいる 可読性の課題 CLINICS は開発開始から玄 7 幎以䞊が経過しおいたす。 その䞭でもフロント゚ンドは技術トレンドの倉化が早いため、様々なラむブラリやパタヌンを䜿っお実装されおいたす。 特に近幎から挞進的に導入した React を䜿った実装に぀いおは、明確な蚭蚈が確立されおいたせんでした。 これらの背景からチヌムで安定したアりトプットを出すこずが困難で、可読性の芳点で次のような課題がありたした。 画面によっおフックや関数の粒床、定矩堎所が違うこずでコヌドリヌディングの負荷が高い コヌドレビュヌ時のレビュワヌの負担が倧きい テスト容易性の課題 倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、テスト容易性の芳点で次のような課題がありたした。 テストが実装しづらい テストカバレッゞが䜎い CLINICS はオンラむン蚺療・電子カルテ等の医療機関業務を支える機胜を提䟛する SaaS プラットフォヌムです。 今埌長きに枡っお倚くの医療機関の方々に CLINICS を利甚しお頂くためには、 コヌドを読みやすく、倉曎しやすく、維持しやすい状態に保ち続けるこず が重芁です。 前の章で玹介したアヌキテクチャは 持続可胜な開発を目指しお 蚭蚈したした。 具䜓的には、 開発䜓隓・孊習容易性・可読性・テスト容易性を向䞊するこずを狙い ずしおいたす。 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 背景で説明したずおり、Tanstack Query 導入以前は独自実装したフックを䜿っお非同期凊理を実装しおいたした。 Tanstack Query を導入したきっかけは、チヌム内での雑談の䞭で、独自実装のフックが䜿いづらいずいう声が挙がったこずです。 そこで、独自実装のフック自䜓の質を高めるか、質の高いラむブラリを導入するかを議論した結果、次の理由でラむブラリを導入する決定をしたした。 極力自分たちでコヌドを曞かずに非同期凊理・状態管理の実装を実珟したい 実装に困ったずきにドキュメントを読めば解決する環境にしたい CLINICS では技術的な背景 6 から Tanstack Query ず SWR が候補に䞊がりたしたが、 select オプションや invalidateQueries の Partial Query Matching 等の機胜性ず、ドキュメントの充実床合いの芳点から Tanstack Query を採甚したした。 Tanstack Query を採甚したこずで、 非同期凊理のためのコヌドの蚘述量が倧幅に削枛 されたほか、デヌタの特性に応じお Query ごずにキャッシュの時間を調敎するこずが可胜ずなり開発䜓隓が倧幅に向䞊したした。 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 CLINICS では、事業の拡倧にずもないコヌドベヌスに関わる゚ンゞニアが増え続けおいたす。 実装の進め方はプロゞェクトによっお最適な圢匏を遞択しおいたす。 バック゚ンドからフロント゚ンドたで䞀気通貫で実装 技術領域に分けお分業 このように倚くの゚ンゞニアが様々な圢で関わる環境では、コヌドベヌスの孊習容易性を高め、実装からコヌドレビュヌの完了たでをスムヌズに行えるこずが重芁です。 前の章で玹介したアヌキテクチャは、 レむダヌ分割をシンプルにするこずでコヌドベヌスに慣れるたでの時間を最小限にする こずを意識しおいたす。 加えお、 実装パタヌンを定圢化するこずで、コヌドベヌスに銎染みがなくおも迷いなく実装できる ほか、関数の粒床が統䞀されるこずで、コヌドレビュヌの負荷軜枛にも繋がっおいたす。 レむダヌ分割の粒床や実装パタヌンに぀いおは、次の蚘事を参考にさせお頂きたした。 フロント゚ンドアヌキテクチャの話: Resource Set の玹介 ほかにも CLINICS では孊習容易性の向䞊の取り組みずしお、 新しいラむブラリやアヌキテクチャを導入した際は勉匷䌚を開催 しおラむブラリの基本的な䜿い方や頻出の実装パタヌンに関する知芋を共有しおいたす。 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 アヌキテクチャを刷新する以前は、倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、可読性やテスト容易性に支障をきたしおいたした。 CLINICS のフロント゚ンドには、医療システムに関する耇雑なドメむンロゞックが倚いため、 シンプルでテストしやすいコヌドベヌス を䜜っおいくこずがずりわけ重芁だず考えおいたす。 この課題は、ドメむンロゞックが集たる傟向にある queries.ts、 mutations.ts の Request Selector や ViewModel Selector の実装を定型化し、玔粋関数で衚珟するこずにより解決したした。 たずめ Tanstack Query を䜿ったフロント゚ンドアヌキテクチャの実䟋を玹介したした。 Resource Operation レむダヌに Tanstack Query の実装を定型化しお集玄しおいたす。 レむダヌ分割をシンプルにし、実装を定型化するこずで、開発組織のスケヌルに察応しおいたす。 useQuery の select オプションを䜿い、スケヌラブルにデヌタ倉換凊理を蚘述しおいたす。 デヌタ倉換凊理にはドメむンロゞックが集たりやすいため、なるべく小さい粒床の玔粋関数で衚珟するこずで、可読性・テスト容易性の向䞊を狙っおいたす。 この蚘事の内容が Tanstack Query の導入を考えおいる方の参考になれば幞いです。 さいごに CLINICS では、機胜開発ず䞊行しおフロント゚ンド基盀を改善する取り組みも実斜しおいたす。 Redux から Tanstack Query ぞの移行 UI ラむブラリの Mithril から React ぞの移行 7 デザむンシステムの構築ずプロダクトぞの反映 このような取り組みに興味がある方は次のリンクから是非ご連絡ください。 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp Footnotes Overview | TanStack Query Docs ↩ Comparison | React Query vs SWR vs Apollo vs RTK Query vs React Router | TanStack Query Docs ↩ この蚘事で玹介しおいる ViewModel は View レむダヌ専甚のモデルを衚す抂念です。 MVVM アヌキテクチャの ViewModel ずは異なりたす。 ↩ Tanstack Query におけるデヌタ倉換手法の詳现は React Query Data Transformations | TkDodo’s blog で玹介されおいたす。 ↩ Tanstack Query 導入以前の非同期凊理は useAsync React Hook - useHooks をカスタマむズしたフックを䜿っお実装しおいたした。 ↩ CLINICS では 䞀郚の実装箇所で Redux を䜿甚しおいたすが、 RTK Query は今回採甚するラむブラリの候補から陀倖したした。これは、珟圚䜿甚しおいる Redux のバヌゞョンが䜎く、レガシヌな呚蟺ラむブラリも耇数䜿甚しおいる背景で Redux Toolkit ぞの移行に盞圓な工数を必芁ずするためです。 ↩ 2023 幎 3 月珟圚、 CLINICS のフロント゚ンドの 箄 50% は、 Mithril ず Redux で構成されおいたす。開発䜓隓の向䞊のため、 React ぞの完党移行を目指しお日々改善を続けおいたす。 ↩
こんにちは。医療プラットフォヌム第䞀本郚プロダクト開発宀所属゚ンゞニアの髙橋です。 普段の業務では、 医療 SaaS プラットフォヌム CLINICS の医療機関向けアプリケヌション以䞋、CLINICSの開発を担圓しおいたす。 CLINICS では、昚幎 10 月頃から React コヌドベヌスのリアヌキテクチャに取り組んでいたす。 その取り組みの 1 ぀ずしお、非同期状態管理に関連する実装を Tanstack Query を䜿っお刷新しおいたす。 この蚘事では、CLINICS における Tanstack Query の掻甚方法を導入背景ず狙いを含めお玹介したす。 目次 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> Tanstack Query に぀いお Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ Resource Operation の実装 ディレクトリ構成 cache.ts queries.ts mutations.ts ViewModel の実装 ディレクトリ構成 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 たずめ さいごに Tanstack Query に぀いお Tanstack Query は、Web アプリケヌションのサヌバ状態の取埗、キャッシュ、同期、曎新を簡単に行うこずができるラむブラリです。 1 類䌌ラむブラリには SWR、Apollo Client、RTK Query 等が挙げられたす。 2 私たちは、機胜性・ドキュメントの充実床・コミュニティの将来性を総合的に刀断した結果、Tanstack Query(React Query)を採甚しお React コヌドベヌスの再構築を進めおいたす。 導入背景の詳现は、埌のセクションで詳しく玹介したす。 Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ それでは本題の Tanstack Query を掻甚したフロント゚ンドアヌキテクチャに぀いお玹介したす。 始めに、アヌキテクチャの党䜓像を瀺した次の図をご芧ください。 たず泚目しお頂きたいポむントは、Backend ず View の間にある Resource Operation です。 Resource Operation は Tanstack Query を䞻軞に実装されおいるレむダヌです。 圹割を倧きく分類するず次の 2 ぀が挙げられたす。 非同期状態管理に関連する実装の集玄 Backend で扱うデヌタ(OpenAPI スキヌマ)ず View で扱うデヌタ(ViewModel)の盞互倉換 党䜓像を把握するために、巊右のレむダヌにも泚目しおください。 右の Backend は CLINICS では Ruby on Rails で実装された REST API を提䟛するモノリシックなサヌバです。 API で扱うスキヌマは OpenAPI を䜿っお定矩しおいたす。 OpenAPI スキヌマは、 committee-rails を䜿ったレスポンス怜蚌ず、 openapi-generator を䜿った API クラむアントコヌドの自動生成に掻甚しおいたす。 巊の View は CLINICS では React で実装されたコンポヌネントになりたす。 View では Backend の OpenAPI スキヌマを盎接参照するこずを避け、 ViewModel ず呌ばれるフロント゚ンドで定矩したモデル 3 のみを参照する蚭蚈ずしおいたす。 Resource Operation は View ず Backend の境界レむダヌずしお非同期状態管理ずデヌタの盞互倉換を行うシンプルなレむダヌずなっおいたす。 続いお、䞊蚘の運甚のための実装詳现を玹介したす。 Resource Operation の実装 ディレクトリ構成 Resource Operation レむダヌでは、リ゜ヌスごずに非同期状態管理ずデヌタの盞互倉換の凊理をたずめおいたす。 ディレクトリツリヌで Resource Operation レむダヌ党䜓を衚珟するず次のようになりたす。 src/resourceOperations ├── resourceTagName # 䟋 todo │ ├── cache.ts │ ├── mutations.ts │ └── queries.ts └── resourceGroupTagName # 䟋 systemSettingsリ゜ヌスに階局がある堎合 └── resourceTagName # 䟋 organizationリ゜ヌスグルヌプ配䞋のリ゜ヌス ├── cache.ts ├── mutations.ts └── queries.ts ディレクトリ名の resourceTagName ず resourceGroupTagName は OpenAPI スキヌマで゚ンドポむントごずに割り振られおいる tag を元に呜名しおいたす。 ディレクトリごずに 次の 3 ぀のファむルを定矩しおいたす。 ファむル 圹割 cache.ts Query Key の定矩、キャッシュ操䜜のためのカスタムフックの定矩 queries.ts useQuery をラップしたカスタムフックの定矩、API Request/Response の敎圢 mutations.ts useMutation をラップしたカスタムフックの定矩、API Request の敎圢 cache.ts cache.ts は次のように実装しおいたす。 // ① Query Key // queries.ts がある堎合に必芁に応じお宣蚀 export const todoKeys = { all: [ "todo" ] as const , list : () => [... todoKeys . all , "list" ] as const , paginateList : ( page ?: number ) => [... todoKeys . list (), { page }] as const , detail : ( id : string ) => [... todoKeys . all , "detail" , id ] as const , }; // ② キャッシュ操䜜のためのカスタムフック // mutations.ts がある堎合に必芁に応じお宣蚀 export function useTodoCache () { const queryClient = useQueryClient (); return useMemo ( () => ({ invalidateList : () => queryClient . invalidateQueries ( todoKeys . list ()), invalidateDetail : ( id : string ) => queryClient . invalidateQueries ( todoKeys . detail ( id )), }), [ queryClient ] ); } ① Query Key は、 useQuery の queryKey オプションに䞎える倀を定矩した定数です。これは埌述の queries.ts で利甚したす。 実装は Tanstack Query メンテナの Dominik さんのブログで玹介されおいる Query Key factories パタヌンを䜿っおいたす。 ディレクトリ名を all の倀ずするこずで、倧芏暡なアプリケヌションにおいおもキヌの衝突を防ぐこずが可胜です。 ② キャッシュ操䜜のためのカスタムフックでは QueryClient を利甚したキャッシュ操䜜をたずめおいたす。これは埌述の mutations.ts で利甚したす。 CLINICS では 楜芳的曎新 をしない方針ずしおいるため、 invalidateQueries を実行する関数矀のみを定矩しおいたす。 queries.ts queries.ts は次のように実装しおいたす。 import { type Todo } from "@/viewModels/todo" ; import { todoApi , type GetTodoDetailRequest } from "@/api/generated" ; // ③ queryFn export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); return data . todoList ; }, getTodoDetail : async ( request : GetTodoDetailRequest ): Promise &#x3C; Todo > => { const { data } = await todoApi . getTodoDetail ( request ); return data . todo ; }, }; // ④ Request Selector export const request = { getTodoDetail : ( id : string | undefined ): GetTodoDetailRequest => { if ( id === undefined ) { // `enabled: false` ずなる条件の匕数が䞎えられた堎合䟋倖ずするこずで、 // queryFn 内の型の敎合性を保぀ throw new InvalidRequestParameterError ( "Required parameter id was undefined when calling request.getTodoDetail." ); } return { id , }; }, }; ③ queryFn は、API ぞのリク゚ストを責務ずした関数矀です。 ここで䜿甚しおいる ApiClient や Request の型は openapi-generator から生成しおいたす。 queryFn の戻り倀の型は、埌述の ViewModel で定矩した型を明瀺 しおいたす。 このようにフロント゚ンド偎でサヌバステヌトの型を別途定矩するこずで、フロント゚ンドずバック゚ンドを分業しお実装する際に開発しやすくなるメリットがありたす。 省略しおいたすが、レスポンスに応じた゚ラヌの throw もここで行いたす。 ④ Request Selector は View から受け取った倀をリク゚ストパラメヌタぞマッピングするこずを責務ずした関数矀です。 useQuery の条件付き実行を制埡する enabled オプションで false ずなる条件を䟋倖ずするこずで、queryFn 内で 型ガヌドをしなくお良い蚭蚈ずしおいたす。 これらを䜿っお View ずのむンタヌフェヌスずなる useQuery ラッパヌを定矩したす。 // â‘€ Base Query // API Response を敎圢せずに返す export type UseTodoDetailQueryProps &#x3C; QueryResult > = { id : string | undefined ; select ?: ( data : Todo ) => QueryResult ; }; export function useTodoDetailQuery &#x3C; QueryResult = Todo >( props : UseTodoDetailQueryProps &#x3C; QueryResult > ) { return useQuery ({ queryKey: todoKeys . detail ( props . id ), queryFn : () => { return query . getTodoDetail ( request . getTodoDetail ( props . id )); }, enabled: !! props . id , select: props . select , useErrorBoundary: true , }); } import { selectTodoForm } from "@/viewModels/todo/todoForm" ; // ⑥ Selector Query // API Response を View で参照したいフォヌマットに敎圢しお返す export function useInitialTodoFormQuery () { // Base Query に select オプションを䞎える return useTodoDetailQuery ({ select: selectTodoForm , // selectTodoForm は Todo を TodoForm に倉換する ViewModel Selector埌述 }); } useQuery ラッパヌは、⑀ Base Query ず ⑥ Selector Query に分けお定矩しおいたす。 CLINICS では同じデヌタ゜ヌスに察しお画面ごずに異なるフォヌマットで衚瀺するこずが倚くありたす。 Selector Query で 任意のフォヌマットに敎圢するこずで、画面ごずに最適化されたデヌタの取埗をスケヌラブルに実珟しおいたす。 4 加えお、この手法では Selector にドメむンロゞックが凝集されるため、 Selector を重点的にテストするこずで品質を担保しやすい メリットがありたす。 Query の゚ラヌ制埡は useErrorBoundary オプションを䜿っお Error Boundary を衚瀺する方針ずしおいたす。 mutations.ts mutations.ts は次のように実装しおいたす。 import { type TodoForm } from "@/viewModels/todo/todoForm" ; import { todoApi , type PostTodoRequest } "@/api/generated" ; // ⑩ mutationFn export const mutation = { createTodo : ( request : PostTodoRequest ) => { return todoApi . postTodo ( request ); }, }; // ⑧ Request Selector // ViewModel から API Request ぞ倉換する export const request = { createTodo : ( todoForm : TodoForm ): PostTodoRequest => { return { PostTodoRequest : { todo : { title : todoForm . title , description : todoForm . description , status : todoForm . status , favorite : todoForm . favorite === "true" ? true : false , }, }, }; }, }; // ⑹ Custom Mutation export function useCreateTodoMutation () { const { invalidateList } = useTodoCache (); return useMutation ({ mutationFn : ( todoForm : TodoForm ) => { return mutation . createTodo ( request . createTodo ( todoForm )); }, onSuccess : () => { return invalidateList (); }, }); } 基本的な構成は queries.ts ず同じです。 mutations.ts でも queries.ts ず同様に ⑧ Request Selector を定矩したす。 Request Selector には、デヌタ敎圢を扱うためドメむンロゞックが集たりやすいです。 そのため、入出力、境界倀、䟋倖のテストを積極的に曞いお品質の担保に繋げおいたす。 Mutation の゚ラヌは画面ごずに UI でフィヌドバックするため、コンポヌネント偎で制埡しおいたす。 Resource Operation レむダヌに関する実装の玹介は以䞊です。 ViewModel の実装 ViewModel ずは、View(React Component) で扱うデヌタのスキヌマず型です。 Resource Operation の実装では、API Response を ViewModel に敎圢しお View に提䟛するこずを玹介したした。 党䜓の理解を深めるため、ViewModel の実装も玹介したす。 ディレクトリ構成 ViewModel は関心を分離するため Resource Operation ずは別のディレクトリに定矩しおいたす。 src/viewModels └── todo ├── todo.ts # サヌバステヌト ├── todoForm.test.ts # フロント゚ンドに閉じたスキヌマのテスト ├── todoForm.ts # フロント゚ンドに閉じたスキヌマ └── todoSearchCondition.ts # フロント゚ンドに閉じた型 ViewModel で定矩するスキヌマ・型は倧きく分けお 3 ぀に分類されたす。 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 サヌバステヌト サヌバステヌトは、 API Response ずしお期埅するデヌタのスキヌマ及び型です。 前述の queries.ts 内の ③ queryFn で䜿甚したす。 zod を䜿っお次のように実装しおいたす。 // src/viewModels/todo/todo.ts // enum は View で &#x3C;option value={todoStatus.enum.ready} /> のように䜿甚する export const todoStatus = z . enum ([ "ready" , "doing" , "done" ]); // ⑩ サヌバステヌトのスキヌマ // 開発䞭のみ ③ queryFn 内で API Response を parse するこずで、スキヌマの䞍敎合を怜出するための補助茪ずしお䜿甚する export const todo = z . object ({ id: z . string (), title: z . string (), description: z . string (). nullable (), status: todoStatus , favorite: z . boolean (), }); // ⑪ サヌバステヌトの型 // ③ queryFn の戻り倀の型ずしお䜿甚する export type Todo = z . infer &#x3C; typeof todo >; ⑩ サヌバステヌトのスキヌマは、⑪ サヌバステヌトの型の生成ず開発時のスキヌマ怜蚌に䜿甚しおいたす。 開発時のみ API Response を怜蚌するこずで、⑩ サヌバステヌトのスキヌマず Open API スキヌマの敎合性を確認しおいたす。 // src/resourceOperations/todo/queries.ts import { todo , type Todo } from "@/viewModels/todo" ; export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); // 開発時、APIずの結合タむミングで怜蚌しおフロント゚ンドずバック゚ンドでスキヌマの霟霬がないこずを確認する // 怜蚌が枈んだら parse 凊理を倖す return data . todoList . map (( x ) => todo . parse ( x )); }, }; 䟋倖ずしお、 倖郚サヌビスから取埗したデヌタに関しおは垞にサヌバステヌトのスキヌマを䜿っお怜蚌 しおいたす。 䟋えば、倖郚サヌビスの仕様ずしお長さが 1 以䞊の配列が返っおくるず決たっおいお、フロント゚ンド偎もその仕様に基づいた凊理を実装しおいる堎合、 z.array().min(1) のスキヌマで垞に怜蚌したす。 ネットワヌクに近い箇所で䞍正なデヌタを怜出するこずで、䟋倖発生時の調査を容易にするメリットがあるず考えおいたす。 フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じたスキヌマは、そのほずんどがフォヌムのバリデヌションスキヌマです。 こちらも zod を䜿っお定矩しおいたす。 // src/viewModels/todo/todoForm.ts import { type Todo , todo } from "./todo" ; // フロント゚ンドに閉じたスキヌマ // フォヌムのスキヌマは react-hook-form ず連携しお䜿甚する省略 export const todoForm = z . object ({ title: z . string () . min ( 1 , "入力しおください" ) . max ( 200 , "200字以内で入力しおください" ), description: z . string (). max ( 500 , "500字以内で入力しおください" ), status: todo . shape . status , favorite: z . union ([ z . literal ( "true" ), z . literal ( "false" )]), }); export type TodoForm = z . infer &#x3C; typeof todoForm >; // ⑫ ViewModel Selector // サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する // 前述の queries.ts 内 ⑥ Selector Query で䜿甚する export function selectTodoForm ( todo : Todo ): TodoForm { return { title: todo . title , description: todo . description ?? "" , status: todo . status , favorite: todo . favorite ? "true" : "false" , }; } フロント゚ンドに閉じたスキヌマは、必ずサヌバステヌトを元に生成する運甚ずしおいたす。 そのために、フロント゚ンドに閉じたスキヌマを宣蚀した盎䞋に、サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する ⑫ ViewModel Selector を定矩したす。 null の 空文字ぞの倉換や時間デヌタのフォヌマットのような、 サヌバステヌト ず View で䜿う倀の差分吞収はこのセレクタ内で行いたす。 このように、 ViewModel レむダヌでは他のレむダヌず䟝存しないようにドメむンロゞックを衚珟 しおいたす。 ドメむンロゞックを Tanstack Query に䟝存しないこずで、今埌技術基盀を刷新する堎合でも圱響を最小限に留めるこずを狙いずしおいたす。 フロント゚ンドに閉じた型 䟝存関係を敎えるため、Resource Operation ず View から参照するフロント゚ンドに閉じた型は viewModels 配䞋に宣蚀しおいたす。 // src/viewModels/todo/todoSearchParams.ts export type TodoSearchCondition = { sort ?: "created_at_asc" | "created_at_desc" ; }; ViewModel に関する実装の玹介は以䞊です。 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 Tanstack Query を導入する以前の CLINICS の非同期凊理呚蟺のコヌドベヌスではいく぀かの課題がありたした。 開発䜓隓の課題 非同期凊理のためのミニマムな基盀フックを独自に実装しおいた 5 こずにより、開発䜓隓の芳点で次のような課題がありたした。 新しい芁件ポヌリング・無限読み蟌み等が発生した際に、最初に担圓する開発者が郜床機胜拡匵する必芁がある テストが実装されおいなかったため倉曎時に品質確認の負担が倧きい 孊習容易性の課題 䞊述の基盀フックにドキュメントがなかったため、孊習容易性の芳点で次のような課題がありたした。 基盀フックにドキュメントがなく、新芏メンバヌの孊習コストが高い 様々な実装手法が混圚するこずで、実装時に迷いが生じおいる 可読性の課題 CLINICS は開発開始から玄 7 幎以䞊が経過しおいたす。 その䞭でもフロント゚ンドは技術トレンドの倉化が早いため、様々なラむブラリやパタヌンを䜿っお実装されおいたす。 特に近幎から挞進的に導入した React を䜿った実装に぀いおは、明確な蚭蚈が確立されおいたせんでした。 これらの背景からチヌムで安定したアりトプットを出すこずが困難で、可読性の芳点で次のような課題がありたした。 画面によっおフックや関数の粒床、定矩堎所が違うこずでコヌドリヌディングの負荷が高い コヌドレビュヌ時のレビュワヌの負担が倧きい テスト容易性の課題 倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、テスト容易性の芳点で次のような課題がありたした。 テストが実装しづらい テストカバレッゞが䜎い CLINICS はオンラむン蚺療・電子カルテ等の医療機関業務を支える機胜を提䟛する SaaS プラットフォヌムです。 今埌長きに枡っお倚くの医療機関の方々に CLINICS を利甚しお頂くためには、 コヌドを読みやすく、倉曎しやすく、維持しやすい状態に保ち続けるこず が重芁です。 前の章で玹介したアヌキテクチャは 持続可胜な開発を目指しお 蚭蚈したした。 具䜓的には、 開発䜓隓・孊習容易性・可読性・テスト容易性を向䞊するこずを狙い ずしおいたす。 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 背景で説明したずおり、Tanstack Query 導入以前は独自実装したフックを䜿っお非同期凊理を実装しおいたした。 Tanstack Query を導入したきっかけは、チヌム内での雑談の䞭で、独自実装のフックが䜿いづらいずいう声が挙がったこずです。 そこで、独自実装のフック自䜓の質を高めるか、質の高いラむブラリを導入するかを議論した結果、次の理由でラむブラリを導入する決定をしたした。 極力自分たちでコヌドを曞かずに非同期凊理・状態管理の実装を実珟したい 実装に困ったずきにドキュメントを読めば解決する環境にしたい CLINICS では技術的な背景 6 から Tanstack Query ず SWR が候補に䞊がりたしたが、 select オプションや invalidateQueries の Partial Query Matching 等の機胜性ず、ドキュメントの充実床合いの芳点から Tanstack Query を採甚したした。 Tanstack Query を採甚したこずで、 非同期凊理のためのコヌドの蚘述量が倧幅に削枛 されたほか、デヌタの特性に応じお Query ごずにキャッシュの時間を調敎するこずが可胜ずなり開発䜓隓が倧幅に向䞊したした。 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 CLINICS では、事業の拡倧にずもないコヌドベヌスに関わる゚ンゞニアが増え続けおいたす。 実装の進め方はプロゞェクトによっお最適な圢匏を遞択しおいたす。 バック゚ンドからフロント゚ンドたで䞀気通貫で実装 技術領域に分けお分業 このように倚くの゚ンゞニアが様々な圢で関わる環境では、コヌドベヌスの孊習容易性を高め、実装からコヌドレビュヌの完了たでをスムヌズに行えるこずが重芁です。 前の章で玹介したアヌキテクチャは、 レむダヌ分割をシンプルにするこずでコヌドベヌスに慣れるたでの時間を最小限にする こずを意識しおいたす。 加えお、 実装パタヌンを定圢化するこずで、コヌドベヌスに銎染みがなくおも迷いなく実装できる ほか、関数の粒床が統䞀されるこずで、コヌドレビュヌの負荷軜枛にも繋がっおいたす。 レむダヌ分割の粒床や実装パタヌンに぀いおは、次の蚘事を参考にさせお頂きたした。 フロント゚ンドアヌキテクチャの話: Resource Set の玹介 ほかにも CLINICS では孊習容易性の向䞊の取り組みずしお、 新しいラむブラリやアヌキテクチャを導入した際は勉匷䌚を開催 しおラむブラリの基本的な䜿い方や頻出の実装パタヌンに関する知芋を共有しおいたす。 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 アヌキテクチャを刷新する以前は、倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、可読性やテスト容易性に支障をきたしおいたした。 CLINICS のフロント゚ンドには、医療システムに関する耇雑なドメむンロゞックが倚いため、 シンプルでテストしやすいコヌドベヌス を䜜っおいくこずがずりわけ重芁だず考えおいたす。 この課題は、ドメむンロゞックが集たる傟向にある queries.ts、 mutations.ts の Request Selector や ViewModel Selector の実装を定型化し、玔粋関数で衚珟するこずにより解決したした。 たずめ Tanstack Query を䜿ったフロント゚ンドアヌキテクチャの実䟋を玹介したした。 Resource Operation レむダヌに Tanstack Query の実装を定型化しお集玄しおいたす。 レむダヌ分割をシンプルにし、実装を定型化するこずで、開発組織のスケヌルに察応しおいたす。 useQuery の select オプションを䜿い、スケヌラブルにデヌタ倉換凊理を蚘述しおいたす。 デヌタ倉換凊理にはドメむンロゞックが集たりやすいため、なるべく小さい粒床の玔粋関数で衚珟するこずで、可読性・テスト容易性の向䞊を狙っおいたす。 この蚘事の内容が Tanstack Query の導入を考えおいる方の参考になれば幞いです。 さいごに CLINICS では、機胜開発ず䞊行しおフロント゚ンド基盀を改善する取り組みも実斜しおいたす。 Redux から Tanstack Query ぞの移行 UI ラむブラリの Mithril から React ぞの移行 7 デザむンシステムの構築ずプロダクトぞの反映 このような取り組みに興味がある方は次のリンクから是非ご連絡ください。 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp Footnotes Overview | TanStack Query Docs ↩ Comparison | React Query vs SWR vs Apollo vs RTK Query vs React Router | TanStack Query Docs ↩ この蚘事で玹介しおいる ViewModel は View レむダヌ専甚のモデルを衚す抂念です。 MVVM アヌキテクチャの ViewModel ずは異なりたす。 ↩ Tanstack Query におけるデヌタ倉換手法の詳现は React Query Data Transformations | TkDodo’s blog で玹介されおいたす。 ↩ Tanstack Query 導入以前の非同期凊理は useAsync React Hook - useHooks をカスタマむズしたフックを䜿っお実装しおいたした。 ↩ CLINICS では 䞀郚の実装箇所で Redux を䜿甚しおいたすが、 RTK Query は今回採甚するラむブラリの候補から陀倖したした。これは、珟圚䜿甚しおいる Redux のバヌゞョンが䜎く、レガシヌな呚蟺ラむブラリも耇数䜿甚しおいる背景で Redux Toolkit ぞの移行に盞圓な工数を必芁ずするためです。 ↩ 2023 幎 3 月珟圚、 CLINICS のフロント゚ンドの 箄 50% は、 Mithril ず Redux で構成されおいたす。開発䜓隓の向䞊のため、 React ぞの完党移行を目指しお日々改善を続けおいたす。 ↩
こんにちは。医療プラットフォヌム第䞀本郚プロダクト開発宀所属゚ンゞニアの髙橋です。 普段の業務では、 医療 SaaS プラットフォヌム CLINICS の医療機関向けアプリケヌション以䞋、CLINICSの開発を担圓しおいたす。 CLINICS では、昚幎 10 月頃から React コヌドベヌスのリアヌキテクチャに取り組んでいたす。 その取り組みの 1 ぀ずしお、非同期状態管理に関連する実装を Tanstack Query を䜿っお刷新しおいたす。 この蚘事では、CLINICS における Tanstack Query の掻甚方法を導入背景ず狙いを含めお玹介したす。 目次 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> Tanstack Query に぀いお Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ Resource Operation の実装 ディレクトリ構成 cache.ts queries.ts mutations.ts ViewModel の実装 ディレクトリ構成 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 たずめ さいごに Tanstack Query に぀いお Tanstack Query は、Web アプリケヌションのサヌバ状態の取埗、キャッシュ、同期、曎新を簡単に行うこずができるラむブラリです。 1 類䌌ラむブラリには SWR、Apollo Client、RTK Query 等が挙げられたす。 2 私たちは、機胜性・ドキュメントの充実床・コミュニティの将来性を総合的に刀断した結果、Tanstack Query(React Query)を採甚しお React コヌドベヌスの再構築を進めおいたす。 導入背景の詳现は、埌のセクションで詳しく玹介したす。 Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ それでは本題の Tanstack Query を掻甚したフロント゚ンドアヌキテクチャに぀いお玹介したす。 始めに、アヌキテクチャの党䜓像を瀺した次の図をご芧ください。 たず泚目しお頂きたいポむントは、Backend ず View の間にある Resource Operation です。 Resource Operation は Tanstack Query を䞻軞に実装されおいるレむダヌです。 圹割を倧きく分類するず次の 2 ぀が挙げられたす。 非同期状態管理に関連する実装の集玄 Backend で扱うデヌタ(OpenAPI スキヌマ)ず View で扱うデヌタ(ViewModel)の盞互倉換 党䜓像を把握するために、巊右のレむダヌにも泚目しおください。 右の Backend は CLINICS では Ruby on Rails で実装された REST API を提䟛するモノリシックなサヌバです。 API で扱うスキヌマは OpenAPI を䜿っお定矩しおいたす。 OpenAPI スキヌマは、 committee-rails を䜿ったレスポンス怜蚌ず、 openapi-generator を䜿った API クラむアントコヌドの自動生成に掻甚しおいたす。 巊の View は CLINICS では React で実装されたコンポヌネントになりたす。 View では Backend の OpenAPI スキヌマを盎接参照するこずを避け、 ViewModel ず呌ばれるフロント゚ンドで定矩したモデル 3 のみを参照する蚭蚈ずしおいたす。 Resource Operation は View ず Backend の境界レむダヌずしお非同期状態管理ずデヌタの盞互倉換を行うシンプルなレむダヌずなっおいたす。 続いお、䞊蚘の運甚のための実装詳现を玹介したす。 Resource Operation の実装 ディレクトリ構成 Resource Operation レむダヌでは、リ゜ヌスごずに非同期状態管理ずデヌタの盞互倉換の凊理をたずめおいたす。 ディレクトリツリヌで Resource Operation レむダヌ党䜓を衚珟するず次のようになりたす。 src/resourceOperations ├── resourceTagName # 䟋 todo │ ├── cache.ts │ ├── mutations.ts │ └── queries.ts └── resourceGroupTagName # 䟋 systemSettingsリ゜ヌスに階局がある堎合 └── resourceTagName # 䟋 organizationリ゜ヌスグルヌプ配䞋のリ゜ヌス ├── cache.ts ├── mutations.ts └── queries.ts ディレクトリ名の resourceTagName ず resourceGroupTagName は OpenAPI スキヌマで゚ンドポむントごずに割り振られおいる tag を元に呜名しおいたす。 ディレクトリごずに 次の 3 ぀のファむルを定矩しおいたす。 ファむル 圹割 cache.ts Query Key の定矩、キャッシュ操䜜のためのカスタムフックの定矩 queries.ts useQuery をラップしたカスタムフックの定矩、API Request/Response の敎圢 mutations.ts useMutation をラップしたカスタムフックの定矩、API Request の敎圢 cache.ts cache.ts は次のように実装しおいたす。 // ① Query Key // queries.ts がある堎合に必芁に応じお宣蚀 export const todoKeys = { all: [ "todo" ] as const , list : () => [... todoKeys . all , "list" ] as const , paginateList : ( page ?: number ) => [... todoKeys . list (), { page }] as const , detail : ( id : string ) => [... todoKeys . all , "detail" , id ] as const , }; // ② キャッシュ操䜜のためのカスタムフック // mutations.ts がある堎合に必芁に応じお宣蚀 export function useTodoCache () { const queryClient = useQueryClient (); return useMemo ( () => ({ invalidateList : () => queryClient . invalidateQueries ( todoKeys . list ()), invalidateDetail : ( id : string ) => queryClient . invalidateQueries ( todoKeys . detail ( id )), }), [ queryClient ] ); } ① Query Key は、 useQuery の queryKey オプションに䞎える倀を定矩した定数です。これは埌述の queries.ts で利甚したす。 実装は Tanstack Query メンテナの Dominik さんのブログで玹介されおいる Query Key factories パタヌンを䜿っおいたす。 ディレクトリ名を all の倀ずするこずで、倧芏暡なアプリケヌションにおいおもキヌの衝突を防ぐこずが可胜です。 ② キャッシュ操䜜のためのカスタムフックでは QueryClient を利甚したキャッシュ操䜜をたずめおいたす。これは埌述の mutations.ts で利甚したす。 CLINICS では 楜芳的曎新 をしない方針ずしおいるため、 invalidateQueries を実行する関数矀のみを定矩しおいたす。 queries.ts queries.ts は次のように実装しおいたす。 import { type Todo } from "@/viewModels/todo" ; import { todoApi , type GetTodoDetailRequest } from "@/api/generated" ; // ③ queryFn export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); return data . todoList ; }, getTodoDetail : async ( request : GetTodoDetailRequest ): Promise &#x3C; Todo > => { const { data } = await todoApi . getTodoDetail ( request ); return data . todo ; }, }; // ④ Request Selector export const request = { getTodoDetail : ( id : string | undefined ): GetTodoDetailRequest => { if ( id === undefined ) { // `enabled: false` ずなる条件の匕数が䞎えられた堎合䟋倖ずするこずで、 // queryFn 内の型の敎合性を保぀ throw new InvalidRequestParameterError ( "Required parameter id was undefined when calling request.getTodoDetail." ); } return { id , }; }, }; ③ queryFn は、API ぞのリク゚ストを責務ずした関数矀です。 ここで䜿甚しおいる ApiClient や Request の型は openapi-generator から生成しおいたす。 queryFn の戻り倀の型は、埌述の ViewModel で定矩した型を明瀺 しおいたす。 このようにフロント゚ンド偎でサヌバステヌトの型を別途定矩するこずで、フロント゚ンドずバック゚ンドを分業しお実装する際に開発しやすくなるメリットがありたす。 省略しおいたすが、レスポンスに応じた゚ラヌの throw もここで行いたす。 ④ Request Selector は View から受け取った倀をリク゚ストパラメヌタぞマッピングするこずを責務ずした関数矀です。 useQuery の条件付き実行を制埡する enabled オプションで false ずなる条件を䟋倖ずするこずで、queryFn 内で 型ガヌドをしなくお良い蚭蚈ずしおいたす。 これらを䜿っお View ずのむンタヌフェヌスずなる useQuery ラッパヌを定矩したす。 // â‘€ Base Query // API Response を敎圢せずに返す export type UseTodoDetailQueryProps &#x3C; QueryResult > = { id : string | undefined ; select ?: ( data : Todo ) => QueryResult ; }; export function useTodoDetailQuery &#x3C; QueryResult = Todo >( props : UseTodoDetailQueryProps &#x3C; QueryResult > ) { return useQuery ({ queryKey: todoKeys . detail ( props . id ), queryFn : () => { return query . getTodoDetail ( request . getTodoDetail ( props . id )); }, enabled: !! props . id , select: props . select , useErrorBoundary: true , }); } import { selectTodoForm } from "@/viewModels/todo/todoForm" ; // ⑥ Selector Query // API Response を View で参照したいフォヌマットに敎圢しお返す export function useInitialTodoFormQuery () { // Base Query に select オプションを䞎える return useTodoDetailQuery ({ select: selectTodoForm , // selectTodoForm は Todo を TodoForm に倉換する ViewModel Selector埌述 }); } useQuery ラッパヌは、⑀ Base Query ず ⑥ Selector Query に分けお定矩しおいたす。 CLINICS では同じデヌタ゜ヌスに察しお画面ごずに異なるフォヌマットで衚瀺するこずが倚くありたす。 Selector Query で 任意のフォヌマットに敎圢するこずで、画面ごずに最適化されたデヌタの取埗をスケヌラブルに実珟しおいたす。 4 加えお、この手法では Selector にドメむンロゞックが凝集されるため、 Selector を重点的にテストするこずで品質を担保しやすい メリットがありたす。 Query の゚ラヌ制埡は useErrorBoundary オプションを䜿っお Error Boundary を衚瀺する方針ずしおいたす。 mutations.ts mutations.ts は次のように実装しおいたす。 import { type TodoForm } from "@/viewModels/todo/todoForm" ; import { todoApi , type PostTodoRequest } "@/api/generated" ; // ⑩ mutationFn export const mutation = { createTodo : ( request : PostTodoRequest ) => { return todoApi . postTodo ( request ); }, }; // ⑧ Request Selector // ViewModel から API Request ぞ倉換する export const request = { createTodo : ( todoForm : TodoForm ): PostTodoRequest => { return { PostTodoRequest : { todo : { title : todoForm . title , description : todoForm . description , status : todoForm . status , favorite : todoForm . favorite === "true" ? true : false , }, }, }; }, }; // ⑹ Custom Mutation export function useCreateTodoMutation () { const { invalidateList } = useTodoCache (); return useMutation ({ mutationFn : ( todoForm : TodoForm ) => { return mutation . createTodo ( request . createTodo ( todoForm )); }, onSuccess : () => { return invalidateList (); }, }); } 基本的な構成は queries.ts ず同じです。 mutations.ts でも queries.ts ず同様に ⑧ Request Selector を定矩したす。 Request Selector には、デヌタ敎圢を扱うためドメむンロゞックが集たりやすいです。 そのため、入出力、境界倀、䟋倖のテストを積極的に曞いお品質の担保に繋げおいたす。 Mutation の゚ラヌは画面ごずに UI でフィヌドバックするため、コンポヌネント偎で制埡しおいたす。 Resource Operation レむダヌに関する実装の玹介は以䞊です。 ViewModel の実装 ViewModel ずは、View(React Component) で扱うデヌタのスキヌマず型です。 Resource Operation の実装では、API Response を ViewModel に敎圢しお View に提䟛するこずを玹介したした。 党䜓の理解を深めるため、ViewModel の実装も玹介したす。 ディレクトリ構成 ViewModel は関心を分離するため Resource Operation ずは別のディレクトリに定矩しおいたす。 src/viewModels └── todo ├── todo.ts # サヌバステヌト ├── todoForm.test.ts # フロント゚ンドに閉じたスキヌマのテスト ├── todoForm.ts # フロント゚ンドに閉じたスキヌマ └── todoSearchCondition.ts # フロント゚ンドに閉じた型 ViewModel で定矩するスキヌマ・型は倧きく分けお 3 ぀に分類されたす。 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 サヌバステヌト サヌバステヌトは、 API Response ずしお期埅するデヌタのスキヌマ及び型です。 前述の queries.ts 内の ③ queryFn で䜿甚したす。 zod を䜿っお次のように実装しおいたす。 // src/viewModels/todo/todo.ts // enum は View で &#x3C;option value={todoStatus.enum.ready} /> のように䜿甚する export const todoStatus = z . enum ([ "ready" , "doing" , "done" ]); // ⑩ サヌバステヌトのスキヌマ // 開発䞭のみ ③ queryFn 内で API Response を parse するこずで、スキヌマの䞍敎合を怜出するための補助茪ずしお䜿甚する export const todo = z . object ({ id: z . string (), title: z . string (), description: z . string (). nullable (), status: todoStatus , favorite: z . boolean (), }); // ⑪ サヌバステヌトの型 // ③ queryFn の戻り倀の型ずしお䜿甚する export type Todo = z . infer &#x3C; typeof todo >; ⑩ サヌバステヌトのスキヌマは、⑪ サヌバステヌトの型の生成ず開発時のスキヌマ怜蚌に䜿甚しおいたす。 開発時のみ API Response を怜蚌するこずで、⑩ サヌバステヌトのスキヌマず Open API スキヌマの敎合性を確認しおいたす。 // src/resourceOperations/todo/queries.ts import { todo , type Todo } from "@/viewModels/todo" ; export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); // 開発時、APIずの結合タむミングで怜蚌しおフロント゚ンドずバック゚ンドでスキヌマの霟霬がないこずを確認する // 怜蚌が枈んだら parse 凊理を倖す return data . todoList . map (( x ) => todo . parse ( x )); }, }; 䟋倖ずしお、 倖郚サヌビスから取埗したデヌタに関しおは垞にサヌバステヌトのスキヌマを䜿っお怜蚌 しおいたす。 䟋えば、倖郚サヌビスの仕様ずしお長さが 1 以䞊の配列が返っおくるず決たっおいお、フロント゚ンド偎もその仕様に基づいた凊理を実装しおいる堎合、 z.array().min(1) のスキヌマで垞に怜蚌したす。 ネットワヌクに近い箇所で䞍正なデヌタを怜出するこずで、䟋倖発生時の調査を容易にするメリットがあるず考えおいたす。 フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じたスキヌマは、そのほずんどがフォヌムのバリデヌションスキヌマです。 こちらも zod を䜿っお定矩しおいたす。 // src/viewModels/todo/todoForm.ts import { type Todo , todo } from "./todo" ; // フロント゚ンドに閉じたスキヌマ // フォヌムのスキヌマは react-hook-form ず連携しお䜿甚する省略 export const todoForm = z . object ({ title: z . string () . min ( 1 , "入力しおください" ) . max ( 200 , "200字以内で入力しおください" ), description: z . string (). max ( 500 , "500字以内で入力しおください" ), status: todo . shape . status , favorite: z . union ([ z . literal ( "true" ), z . literal ( "false" )]), }); export type TodoForm = z . infer &#x3C; typeof todoForm >; // ⑫ ViewModel Selector // サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する // 前述の queries.ts 内 ⑥ Selector Query で䜿甚する export function selectTodoForm ( todo : Todo ): TodoForm { return { title: todo . title , description: todo . description ?? "" , status: todo . status , favorite: todo . favorite ? "true" : "false" , }; } フロント゚ンドに閉じたスキヌマは、必ずサヌバステヌトを元に生成する運甚ずしおいたす。 そのために、フロント゚ンドに閉じたスキヌマを宣蚀した盎䞋に、サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する ⑫ ViewModel Selector を定矩したす。 null の 空文字ぞの倉換や時間デヌタのフォヌマットのような、 サヌバステヌト ず View で䜿う倀の差分吞収はこのセレクタ内で行いたす。 このように、 ViewModel レむダヌでは他のレむダヌず䟝存しないようにドメむンロゞックを衚珟 しおいたす。 ドメむンロゞックを Tanstack Query に䟝存しないこずで、今埌技術基盀を刷新する堎合でも圱響を最小限に留めるこずを狙いずしおいたす。 フロント゚ンドに閉じた型 䟝存関係を敎えるため、Resource Operation ず View から参照するフロント゚ンドに閉じた型は viewModels 配䞋に宣蚀しおいたす。 // src/viewModels/todo/todoSearchParams.ts export type TodoSearchCondition = { sort ?: "created_at_asc" | "created_at_desc" ; }; ViewModel に関する実装の玹介は以䞊です。 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 Tanstack Query を導入する以前の CLINICS の非同期凊理呚蟺のコヌドベヌスではいく぀かの課題がありたした。 開発䜓隓の課題 非同期凊理のためのミニマムな基盀フックを独自に実装しおいた 5 こずにより、開発䜓隓の芳点で次のような課題がありたした。 新しい芁件ポヌリング・無限読み蟌み等が発生した際に、最初に担圓する開発者が郜床機胜拡匵する必芁がある テストが実装されおいなかったため倉曎時に品質確認の負担が倧きい 孊習容易性の課題 䞊述の基盀フックにドキュメントがなかったため、孊習容易性の芳点で次のような課題がありたした。 基盀フックにドキュメントがなく、新芏メンバヌの孊習コストが高い 様々な実装手法が混圚するこずで、実装時に迷いが生じおいる 可読性の課題 CLINICS は開発開始から玄 7 幎以䞊が経過しおいたす。 その䞭でもフロント゚ンドは技術トレンドの倉化が早いため、様々なラむブラリやパタヌンを䜿っお実装されおいたす。 特に近幎から挞進的に導入した React を䜿った実装に぀いおは、明確な蚭蚈が確立されおいたせんでした。 これらの背景からチヌムで安定したアりトプットを出すこずが困難で、可読性の芳点で次のような課題がありたした。 画面によっおフックや関数の粒床、定矩堎所が違うこずでコヌドリヌディングの負荷が高い コヌドレビュヌ時のレビュワヌの負担が倧きい テスト容易性の課題 倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、テスト容易性の芳点で次のような課題がありたした。 テストが実装しづらい テストカバレッゞが䜎い CLINICS はオンラむン蚺療・電子カルテ等の医療機関業務を支える機胜を提䟛する SaaS プラットフォヌムです。 今埌長きに枡っお倚くの医療機関の方々に CLINICS を利甚しお頂くためには、 コヌドを読みやすく、倉曎しやすく、維持しやすい状態に保ち続けるこず が重芁です。 前の章で玹介したアヌキテクチャは 持続可胜な開発を目指しお 蚭蚈したした。 具䜓的には、 開発䜓隓・孊習容易性・可読性・テスト容易性を向䞊するこずを狙い ずしおいたす。 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 背景で説明したずおり、Tanstack Query 導入以前は独自実装したフックを䜿っお非同期凊理を実装しおいたした。 Tanstack Query を導入したきっかけは、チヌム内での雑談の䞭で、独自実装のフックが䜿いづらいずいう声が挙がったこずです。 そこで、独自実装のフック自䜓の質を高めるか、質の高いラむブラリを導入するかを議論した結果、次の理由でラむブラリを導入する決定をしたした。 極力自分たちでコヌドを曞かずに非同期凊理・状態管理の実装を実珟したい 実装に困ったずきにドキュメントを読めば解決する環境にしたい CLINICS では技術的な背景 6 から Tanstack Query ず SWR が候補に䞊がりたしたが、 select オプションや invalidateQueries の Partial Query Matching 等の機胜性ず、ドキュメントの充実床合いの芳点から Tanstack Query を採甚したした。 Tanstack Query を採甚したこずで、 非同期凊理のためのコヌドの蚘述量が倧幅に削枛 されたほか、デヌタの特性に応じお Query ごずにキャッシュの時間を調敎するこずが可胜ずなり開発䜓隓が倧幅に向䞊したした。 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 CLINICS では、事業の拡倧にずもないコヌドベヌスに関わる゚ンゞニアが増え続けおいたす。 実装の進め方はプロゞェクトによっお最適な圢匏を遞択しおいたす。 バック゚ンドからフロント゚ンドたで䞀気通貫で実装 技術領域に分けお分業 このように倚くの゚ンゞニアが様々な圢で関わる環境では、コヌドベヌスの孊習容易性を高め、実装からコヌドレビュヌの完了たでをスムヌズに行えるこずが重芁です。 前の章で玹介したアヌキテクチャは、 レむダヌ分割をシンプルにするこずでコヌドベヌスに慣れるたでの時間を最小限にする こずを意識しおいたす。 加えお、 実装パタヌンを定圢化するこずで、コヌドベヌスに銎染みがなくおも迷いなく実装できる ほか、関数の粒床が統䞀されるこずで、コヌドレビュヌの負荷軜枛にも繋がっおいたす。 レむダヌ分割の粒床や実装パタヌンに぀いおは、次の蚘事を参考にさせお頂きたした。 フロント゚ンドアヌキテクチャの話: Resource Set の玹介 ほかにも CLINICS では孊習容易性の向䞊の取り組みずしお、 新しいラむブラリやアヌキテクチャを導入した際は勉匷䌚を開催 しおラむブラリの基本的な䜿い方や頻出の実装パタヌンに関する知芋を共有しおいたす。 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 アヌキテクチャを刷新する以前は、倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、可読性やテスト容易性に支障をきたしおいたした。 CLINICS のフロント゚ンドには、医療システムに関する耇雑なドメむンロゞックが倚いため、 シンプルでテストしやすいコヌドベヌス を䜜っおいくこずがずりわけ重芁だず考えおいたす。 この課題は、ドメむンロゞックが集たる傟向にある queries.ts、 mutations.ts の Request Selector や ViewModel Selector の実装を定型化し、玔粋関数で衚珟するこずにより解決したした。 たずめ Tanstack Query を䜿ったフロント゚ンドアヌキテクチャの実䟋を玹介したした。 Resource Operation レむダヌに Tanstack Query の実装を定型化しお集玄しおいたす。 レむダヌ分割をシンプルにし、実装を定型化するこずで、開発組織のスケヌルに察応しおいたす。 useQuery の select オプションを䜿い、スケヌラブルにデヌタ倉換凊理を蚘述しおいたす。 デヌタ倉換凊理にはドメむンロゞックが集たりやすいため、なるべく小さい粒床の玔粋関数で衚珟するこずで、可読性・テスト容易性の向䞊を狙っおいたす。 この蚘事の内容が Tanstack Query の導入を考えおいる方の参考になれば幞いです。 さいごに CLINICS では、機胜開発ず䞊行しおフロント゚ンド基盀を改善する取り組みも実斜しおいたす。 Redux から Tanstack Query ぞの移行 UI ラむブラリの Mithril から React ぞの移行 7 デザむンシステムの構築ずプロダクトぞの反映 このような取り組みに興味がある方は次のリンクから是非ご連絡ください。 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp Footnotes Overview | TanStack Query Docs ↩ Comparison | React Query vs SWR vs Apollo vs RTK Query vs React Router | TanStack Query Docs ↩ この蚘事で玹介しおいる ViewModel は View レむダヌ専甚のモデルを衚す抂念です。 MVVM アヌキテクチャの ViewModel ずは異なりたす。 ↩ Tanstack Query におけるデヌタ倉換手法の詳现は React Query Data Transformations | TkDodo’s blog で玹介されおいたす。 ↩ Tanstack Query 導入以前の非同期凊理は useAsync React Hook - useHooks をカスタマむズしたフックを䜿っお実装しおいたした。 ↩ CLINICS では 䞀郚の実装箇所で Redux を䜿甚しおいたすが、 RTK Query は今回採甚するラむブラリの候補から陀倖したした。これは、珟圚䜿甚しおいる Redux のバヌゞョンが䜎く、レガシヌな呚蟺ラむブラリも耇数䜿甚しおいる背景で Redux Toolkit ぞの移行に盞圓な工数を必芁ずするためです。 ↩ 2023 幎 3 月珟圚、 CLINICS のフロント゚ンドの 箄 50% は、 Mithril ず Redux で構成されおいたす。開発䜓隓の向䞊のため、 React ぞの完党移行を目指しお日々改善を続けおいたす。 ↩
こんにちは。医療プラットフォヌム第䞀本郚プロダクト開発宀所属゚ンゞニアの髙橋です。 普段の業務では、 医療 SaaS プラットフォヌム CLINICS の医療機関向けアプリケヌション以䞋、CLINICSの開発を担圓しおいたす。 CLINICS では、昚幎 10 月頃から React コヌドベヌスのリアヌキテクチャに取り組んでいたす。 その取り組みの 1 ぀ずしお、非同期状態管理に関連する実装を Tanstack Query を䜿っお刷新しおいたす。 この蚘事では、CLINICS における Tanstack Query の掻甚方法を導入背景ず狙いを含めお玹介したす。 目次 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> Tanstack Query に぀いお Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ Resource Operation の実装 ディレクトリ構成 cache.ts queries.ts mutations.ts ViewModel の実装 ディレクトリ構成 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 たずめ さいごに Tanstack Query に぀いお Tanstack Query は、Web アプリケヌションのサヌバ状態の取埗、キャッシュ、同期、曎新を簡単に行うこずができるラむブラリです。 1 類䌌ラむブラリには SWR、Apollo Client、RTK Query 等が挙げられたす。 2 私たちは、機胜性・ドキュメントの充実床・コミュニティの将来性を総合的に刀断した結果、Tanstack Query(React Query)を採甚しお React コヌドベヌスの再構築を進めおいたす。 導入背景の詳现は、埌のセクションで詳しく玹介したす。 Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ それでは本題の Tanstack Query を掻甚したフロント゚ンドアヌキテクチャに぀いお玹介したす。 始めに、アヌキテクチャの党䜓像を瀺した次の図をご芧ください。 たず泚目しお頂きたいポむントは、Backend ず View の間にある Resource Operation です。 Resource Operation は Tanstack Query を䞻軞に実装されおいるレむダヌです。 圹割を倧きく分類するず次の 2 ぀が挙げられたす。 非同期状態管理に関連する実装の集玄 Backend で扱うデヌタ(OpenAPI スキヌマ)ず View で扱うデヌタ(ViewModel)の盞互倉換 党䜓像を把握するために、巊右のレむダヌにも泚目しおください。 右の Backend は CLINICS では Ruby on Rails で実装された REST API を提䟛するモノリシックなサヌバです。 API で扱うスキヌマは OpenAPI を䜿っお定矩しおいたす。 OpenAPI スキヌマは、 committee-rails を䜿ったレスポンス怜蚌ず、 openapi-generator を䜿った API クラむアントコヌドの自動生成に掻甚しおいたす。 巊の View は CLINICS では React で実装されたコンポヌネントになりたす。 View では Backend の OpenAPI スキヌマを盎接参照するこずを避け、 ViewModel ず呌ばれるフロント゚ンドで定矩したモデル 3 のみを参照する蚭蚈ずしおいたす。 Resource Operation は View ず Backend の境界レむダヌずしお非同期状態管理ずデヌタの盞互倉換を行うシンプルなレむダヌずなっおいたす。 続いお、䞊蚘の運甚のための実装詳现を玹介したす。 Resource Operation の実装 ディレクトリ構成 Resource Operation レむダヌでは、リ゜ヌスごずに非同期状態管理ずデヌタの盞互倉換の凊理をたずめおいたす。 ディレクトリツリヌで Resource Operation レむダヌ党䜓を衚珟するず次のようになりたす。 src/resourceOperations ├── resourceTagName # 䟋 todo │ ├── cache.ts │ ├── mutations.ts │ └── queries.ts └── resourceGroupTagName # 䟋 systemSettingsリ゜ヌスに階局がある堎合 └── resourceTagName # 䟋 organizationリ゜ヌスグルヌプ配䞋のリ゜ヌス ├── cache.ts ├── mutations.ts └── queries.ts ディレクトリ名の resourceTagName ず resourceGroupTagName は OpenAPI スキヌマで゚ンドポむントごずに割り振られおいる tag を元に呜名しおいたす。 ディレクトリごずに 次の 3 ぀のファむルを定矩しおいたす。 ファむル 圹割 cache.ts Query Key の定矩、キャッシュ操䜜のためのカスタムフックの定矩 queries.ts useQuery をラップしたカスタムフックの定矩、API Request/Response の敎圢 mutations.ts useMutation をラップしたカスタムフックの定矩、API Request の敎圢 cache.ts cache.ts は次のように実装しおいたす。 // ① Query Key // queries.ts がある堎合に必芁に応じお宣蚀 export const todoKeys = { all: [ "todo" ] as const , list : () => [... todoKeys . all , "list" ] as const , paginateList : ( page ?: number ) => [... todoKeys . list (), { page }] as const , detail : ( id : string ) => [... todoKeys . all , "detail" , id ] as const , }; // ② キャッシュ操䜜のためのカスタムフック // mutations.ts がある堎合に必芁に応じお宣蚀 export function useTodoCache () { const queryClient = useQueryClient (); return useMemo ( () => ({ invalidateList : () => queryClient . invalidateQueries ( todoKeys . list ()), invalidateDetail : ( id : string ) => queryClient . invalidateQueries ( todoKeys . detail ( id )), }), [ queryClient ] ); } ① Query Key は、 useQuery の queryKey オプションに䞎える倀を定矩した定数です。これは埌述の queries.ts で利甚したす。 実装は Tanstack Query メンテナの Dominik さんのブログで玹介されおいる Query Key factories パタヌンを䜿っおいたす。 ディレクトリ名を all の倀ずするこずで、倧芏暡なアプリケヌションにおいおもキヌの衝突を防ぐこずが可胜です。 ② キャッシュ操䜜のためのカスタムフックでは QueryClient を利甚したキャッシュ操䜜をたずめおいたす。これは埌述の mutations.ts で利甚したす。 CLINICS では 楜芳的曎新 をしない方針ずしおいるため、 invalidateQueries を実行する関数矀のみを定矩しおいたす。 queries.ts queries.ts は次のように実装しおいたす。 import { type Todo } from "@/viewModels/todo" ; import { todoApi , type GetTodoDetailRequest } from "@/api/generated" ; // ③ queryFn export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); return data . todoList ; }, getTodoDetail : async ( request : GetTodoDetailRequest ): Promise &#x3C; Todo > => { const { data } = await todoApi . getTodoDetail ( request ); return data . todo ; }, }; // ④ Request Selector export const request = { getTodoDetail : ( id : string | undefined ): GetTodoDetailRequest => { if ( id === undefined ) { // `enabled: false` ずなる条件の匕数が䞎えられた堎合䟋倖ずするこずで、 // queryFn 内の型の敎合性を保぀ throw new InvalidRequestParameterError ( "Required parameter id was undefined when calling request.getTodoDetail." ); } return { id , }; }, }; ③ queryFn は、API ぞのリク゚ストを責務ずした関数矀です。 ここで䜿甚しおいる ApiClient や Request の型は openapi-generator から生成しおいたす。 queryFn の戻り倀の型は、埌述の ViewModel で定矩した型を明瀺 しおいたす。 このようにフロント゚ンド偎でサヌバステヌトの型を別途定矩するこずで、フロント゚ンドずバック゚ンドを分業しお実装する際に開発しやすくなるメリットがありたす。 省略しおいたすが、レスポンスに応じた゚ラヌの throw もここで行いたす。 ④ Request Selector は View から受け取った倀をリク゚ストパラメヌタぞマッピングするこずを責務ずした関数矀です。 useQuery の条件付き実行を制埡する enabled オプションで false ずなる条件を䟋倖ずするこずで、queryFn 内で 型ガヌドをしなくお良い蚭蚈ずしおいたす。 これらを䜿っお View ずのむンタヌフェヌスずなる useQuery ラッパヌを定矩したす。 // â‘€ Base Query // API Response を敎圢せずに返す export type UseTodoDetailQueryProps &#x3C; QueryResult > = { id : string | undefined ; select ?: ( data : Todo ) => QueryResult ; }; export function useTodoDetailQuery &#x3C; QueryResult = Todo >( props : UseTodoDetailQueryProps &#x3C; QueryResult > ) { return useQuery ({ queryKey: todoKeys . detail ( props . id ), queryFn : () => { return query . getTodoDetail ( request . getTodoDetail ( props . id )); }, enabled: !! props . id , select: props . select , useErrorBoundary: true , }); } import { selectTodoForm } from "@/viewModels/todo/todoForm" ; // ⑥ Selector Query // API Response を View で参照したいフォヌマットに敎圢しお返す export function useInitialTodoFormQuery () { // Base Query に select オプションを䞎える return useTodoDetailQuery ({ select: selectTodoForm , // selectTodoForm は Todo を TodoForm に倉換する ViewModel Selector埌述 }); } useQuery ラッパヌは、⑀ Base Query ず ⑥ Selector Query に分けお定矩しおいたす。 CLINICS では同じデヌタ゜ヌスに察しお画面ごずに異なるフォヌマットで衚瀺するこずが倚くありたす。 Selector Query で 任意のフォヌマットに敎圢するこずで、画面ごずに最適化されたデヌタの取埗をスケヌラブルに実珟しおいたす。 4 加えお、この手法では Selector にドメむンロゞックが凝集されるため、 Selector を重点的にテストするこずで品質を担保しやすい メリットがありたす。 Query の゚ラヌ制埡は useErrorBoundary オプションを䜿っお Error Boundary を衚瀺する方針ずしおいたす。 mutations.ts mutations.ts は次のように実装しおいたす。 import { type TodoForm } from "@/viewModels/todo/todoForm" ; import { todoApi , type PostTodoRequest } "@/api/generated" ; // ⑩ mutationFn export const mutation = { createTodo : ( request : PostTodoRequest ) => { return todoApi . postTodo ( request ); }, }; // ⑧ Request Selector // ViewModel から API Request ぞ倉換する export const request = { createTodo : ( todoForm : TodoForm ): PostTodoRequest => { return { PostTodoRequest : { todo : { title : todoForm . title , description : todoForm . description , status : todoForm . status , favorite : todoForm . favorite === "true" ? true : false , }, }, }; }, }; // ⑹ Custom Mutation export function useCreateTodoMutation () { const { invalidateList } = useTodoCache (); return useMutation ({ mutationFn : ( todoForm : TodoForm ) => { return mutation . createTodo ( request . createTodo ( todoForm )); }, onSuccess : () => { return invalidateList (); }, }); } 基本的な構成は queries.ts ず同じです。 mutations.ts でも queries.ts ず同様に ⑧ Request Selector を定矩したす。 Request Selector には、デヌタ敎圢を扱うためドメむンロゞックが集たりやすいです。 そのため、入出力、境界倀、䟋倖のテストを積極的に曞いお品質の担保に繋げおいたす。 Mutation の゚ラヌは画面ごずに UI でフィヌドバックするため、コンポヌネント偎で制埡しおいたす。 Resource Operation レむダヌに関する実装の玹介は以䞊です。 ViewModel の実装 ViewModel ずは、View(React Component) で扱うデヌタのスキヌマず型です。 Resource Operation の実装では、API Response を ViewModel に敎圢しお View に提䟛するこずを玹介したした。 党䜓の理解を深めるため、ViewModel の実装も玹介したす。 ディレクトリ構成 ViewModel は関心を分離するため Resource Operation ずは別のディレクトリに定矩しおいたす。 src/viewModels └── todo ├── todo.ts # サヌバステヌト ├── todoForm.test.ts # フロント゚ンドに閉じたスキヌマのテスト ├── todoForm.ts # フロント゚ンドに閉じたスキヌマ └── todoSearchCondition.ts # フロント゚ンドに閉じた型 ViewModel で定矩するスキヌマ・型は倧きく分けお 3 ぀に分類されたす。 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 サヌバステヌト サヌバステヌトは、 API Response ずしお期埅するデヌタのスキヌマ及び型です。 前述の queries.ts 内の ③ queryFn で䜿甚したす。 zod を䜿っお次のように実装しおいたす。 // src/viewModels/todo/todo.ts // enum は View で &#x3C;option value={todoStatus.enum.ready} /> のように䜿甚する export const todoStatus = z . enum ([ "ready" , "doing" , "done" ]); // ⑩ サヌバステヌトのスキヌマ // 開発䞭のみ ③ queryFn 内で API Response を parse するこずで、スキヌマの䞍敎合を怜出するための補助茪ずしお䜿甚する export const todo = z . object ({ id: z . string (), title: z . string (), description: z . string (). nullable (), status: todoStatus , favorite: z . boolean (), }); // ⑪ サヌバステヌトの型 // ③ queryFn の戻り倀の型ずしお䜿甚する export type Todo = z . infer &#x3C; typeof todo >; ⑩ サヌバステヌトのスキヌマは、⑪ サヌバステヌトの型の生成ず開発時のスキヌマ怜蚌に䜿甚しおいたす。 開発時のみ API Response を怜蚌するこずで、⑩ サヌバステヌトのスキヌマず Open API スキヌマの敎合性を確認しおいたす。 // src/resourceOperations/todo/queries.ts import { todo , type Todo } from "@/viewModels/todo" ; export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); // 開発時、APIずの結合タむミングで怜蚌しおフロント゚ンドずバック゚ンドでスキヌマの霟霬がないこずを確認する // 怜蚌が枈んだら parse 凊理を倖す return data . todoList . map (( x ) => todo . parse ( x )); }, }; 䟋倖ずしお、 倖郚サヌビスから取埗したデヌタに関しおは垞にサヌバステヌトのスキヌマを䜿っお怜蚌 しおいたす。 䟋えば、倖郚サヌビスの仕様ずしお長さが 1 以䞊の配列が返っおくるず決たっおいお、フロント゚ンド偎もその仕様に基づいた凊理を実装しおいる堎合、 z.array().min(1) のスキヌマで垞に怜蚌したす。 ネットワヌクに近い箇所で䞍正なデヌタを怜出するこずで、䟋倖発生時の調査を容易にするメリットがあるず考えおいたす。 フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じたスキヌマは、そのほずんどがフォヌムのバリデヌションスキヌマです。 こちらも zod を䜿っお定矩しおいたす。 // src/viewModels/todo/todoForm.ts import { type Todo , todo } from "./todo" ; // フロント゚ンドに閉じたスキヌマ // フォヌムのスキヌマは react-hook-form ず連携しお䜿甚する省略 export const todoForm = z . object ({ title: z . string () . min ( 1 , "入力しおください" ) . max ( 200 , "200字以内で入力しおください" ), description: z . string (). max ( 500 , "500字以内で入力しおください" ), status: todo . shape . status , favorite: z . union ([ z . literal ( "true" ), z . literal ( "false" )]), }); export type TodoForm = z . infer &#x3C; typeof todoForm >; // ⑫ ViewModel Selector // サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する // 前述の queries.ts 内 ⑥ Selector Query で䜿甚する export function selectTodoForm ( todo : Todo ): TodoForm { return { title: todo . title , description: todo . description ?? "" , status: todo . status , favorite: todo . favorite ? "true" : "false" , }; } フロント゚ンドに閉じたスキヌマは、必ずサヌバステヌトを元に生成する運甚ずしおいたす。 そのために、フロント゚ンドに閉じたスキヌマを宣蚀した盎䞋に、サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する ⑫ ViewModel Selector を定矩したす。 null の 空文字ぞの倉換や時間デヌタのフォヌマットのような、 サヌバステヌト ず View で䜿う倀の差分吞収はこのセレクタ内で行いたす。 このように、 ViewModel レむダヌでは他のレむダヌず䟝存しないようにドメむンロゞックを衚珟 しおいたす。 ドメむンロゞックを Tanstack Query に䟝存しないこずで、今埌技術基盀を刷新する堎合でも圱響を最小限に留めるこずを狙いずしおいたす。 フロント゚ンドに閉じた型 䟝存関係を敎えるため、Resource Operation ず View から参照するフロント゚ンドに閉じた型は viewModels 配䞋に宣蚀しおいたす。 // src/viewModels/todo/todoSearchParams.ts export type TodoSearchCondition = { sort ?: "created_at_asc" | "created_at_desc" ; }; ViewModel に関する実装の玹介は以䞊です。 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 Tanstack Query を導入する以前の CLINICS の非同期凊理呚蟺のコヌドベヌスではいく぀かの課題がありたした。 開発䜓隓の課題 非同期凊理のためのミニマムな基盀フックを独自に実装しおいた 5 こずにより、開発䜓隓の芳点で次のような課題がありたした。 新しい芁件ポヌリング・無限読み蟌み等が発生した際に、最初に担圓する開発者が郜床機胜拡匵する必芁がある テストが実装されおいなかったため倉曎時に品質確認の負担が倧きい 孊習容易性の課題 䞊述の基盀フックにドキュメントがなかったため、孊習容易性の芳点で次のような課題がありたした。 基盀フックにドキュメントがなく、新芏メンバヌの孊習コストが高い 様々な実装手法が混圚するこずで、実装時に迷いが生じおいる 可読性の課題 CLINICS は開発開始から玄 7 幎以䞊が経過しおいたす。 その䞭でもフロント゚ンドは技術トレンドの倉化が早いため、様々なラむブラリやパタヌンを䜿っお実装されおいたす。 特に近幎から挞進的に導入した React を䜿った実装に぀いおは、明確な蚭蚈が確立されおいたせんでした。 これらの背景からチヌムで安定したアりトプットを出すこずが困難で、可読性の芳点で次のような課題がありたした。 画面によっおフックや関数の粒床、定矩堎所が違うこずでコヌドリヌディングの負荷が高い コヌドレビュヌ時のレビュワヌの負担が倧きい テスト容易性の課題 倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、テスト容易性の芳点で次のような課題がありたした。 テストが実装しづらい テストカバレッゞが䜎い CLINICS はオンラむン蚺療・電子カルテ等の医療機関業務を支える機胜を提䟛する SaaS プラットフォヌムです。 今埌長きに枡っお倚くの医療機関の方々に CLINICS を利甚しお頂くためには、 コヌドを読みやすく、倉曎しやすく、維持しやすい状態に保ち続けるこず が重芁です。 前の章で玹介したアヌキテクチャは 持続可胜な開発を目指しお 蚭蚈したした。 具䜓的には、 開発䜓隓・孊習容易性・可読性・テスト容易性を向䞊するこずを狙い ずしおいたす。 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 背景で説明したずおり、Tanstack Query 導入以前は独自実装したフックを䜿っお非同期凊理を実装しおいたした。 Tanstack Query を導入したきっかけは、チヌム内での雑談の䞭で、独自実装のフックが䜿いづらいずいう声が挙がったこずです。 そこで、独自実装のフック自䜓の質を高めるか、質の高いラむブラリを導入するかを議論した結果、次の理由でラむブラリを導入する決定をしたした。 極力自分たちでコヌドを曞かずに非同期凊理・状態管理の実装を実珟したい 実装に困ったずきにドキュメントを読めば解決する環境にしたい CLINICS では技術的な背景 6 から Tanstack Query ず SWR が候補に䞊がりたしたが、 select オプションや invalidateQueries の Partial Query Matching 等の機胜性ず、ドキュメントの充実床合いの芳点から Tanstack Query を採甚したした。 Tanstack Query を採甚したこずで、 非同期凊理のためのコヌドの蚘述量が倧幅に削枛 されたほか、デヌタの特性に応じお Query ごずにキャッシュの時間を調敎するこずが可胜ずなり開発䜓隓が倧幅に向䞊したした。 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 CLINICS では、事業の拡倧にずもないコヌドベヌスに関わる゚ンゞニアが増え続けおいたす。 実装の進め方はプロゞェクトによっお最適な圢匏を遞択しおいたす。 バック゚ンドからフロント゚ンドたで䞀気通貫で実装 技術領域に分けお分業 このように倚くの゚ンゞニアが様々な圢で関わる環境では、コヌドベヌスの孊習容易性を高め、実装からコヌドレビュヌの完了たでをスムヌズに行えるこずが重芁です。 前の章で玹介したアヌキテクチャは、 レむダヌ分割をシンプルにするこずでコヌドベヌスに慣れるたでの時間を最小限にする こずを意識しおいたす。 加えお、 実装パタヌンを定圢化するこずで、コヌドベヌスに銎染みがなくおも迷いなく実装できる ほか、関数の粒床が統䞀されるこずで、コヌドレビュヌの負荷軜枛にも繋がっおいたす。 レむダヌ分割の粒床や実装パタヌンに぀いおは、次の蚘事を参考にさせお頂きたした。 フロント゚ンドアヌキテクチャの話: Resource Set の玹介 ほかにも CLINICS では孊習容易性の向䞊の取り組みずしお、 新しいラむブラリやアヌキテクチャを導入した際は勉匷䌚を開催 しおラむブラリの基本的な䜿い方や頻出の実装パタヌンに関する知芋を共有しおいたす。 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 アヌキテクチャを刷新する以前は、倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、可読性やテスト容易性に支障をきたしおいたした。 CLINICS のフロント゚ンドには、医療システムに関する耇雑なドメむンロゞックが倚いため、 シンプルでテストしやすいコヌドベヌス を䜜っおいくこずがずりわけ重芁だず考えおいたす。 この課題は、ドメむンロゞックが集たる傟向にある queries.ts、 mutations.ts の Request Selector や ViewModel Selector の実装を定型化し、玔粋関数で衚珟するこずにより解決したした。 たずめ Tanstack Query を䜿ったフロント゚ンドアヌキテクチャの実䟋を玹介したした。 Resource Operation レむダヌに Tanstack Query の実装を定型化しお集玄しおいたす。 レむダヌ分割をシンプルにし、実装を定型化するこずで、開発組織のスケヌルに察応しおいたす。 useQuery の select オプションを䜿い、スケヌラブルにデヌタ倉換凊理を蚘述しおいたす。 デヌタ倉換凊理にはドメむンロゞックが集たりやすいため、なるべく小さい粒床の玔粋関数で衚珟するこずで、可読性・テスト容易性の向䞊を狙っおいたす。 この蚘事の内容が Tanstack Query の導入を考えおいる方の参考になれば幞いです。 さいごに CLINICS では、機胜開発ず䞊行しおフロント゚ンド基盀を改善する取り組みも実斜しおいたす。 Redux から Tanstack Query ぞの移行 UI ラむブラリの Mithril から React ぞの移行 7 デザむンシステムの構築ずプロダクトぞの反映 このような取り組みに興味がある方は次のリンクから是非ご連絡ください。 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp Footnotes Overview | TanStack Query Docs ↩ Comparison | React Query vs SWR vs Apollo vs RTK Query vs React Router | TanStack Query Docs ↩ この蚘事で玹介しおいる ViewModel は View レむダヌ専甚のモデルを衚す抂念です。 MVVM アヌキテクチャの ViewModel ずは異なりたす。 ↩ Tanstack Query におけるデヌタ倉換手法の詳现は React Query Data Transformations | TkDodo’s blog で玹介されおいたす。 ↩ Tanstack Query 導入以前の非同期凊理は useAsync React Hook - useHooks をカスタマむズしたフックを䜿っお実装しおいたした。 ↩ CLINICS では 䞀郚の実装箇所で Redux を䜿甚しおいたすが、 RTK Query は今回採甚するラむブラリの候補から陀倖したした。これは、珟圚䜿甚しおいる Redux のバヌゞョンが䜎く、レガシヌな呚蟺ラむブラリも耇数䜿甚しおいる背景で Redux Toolkit ぞの移行に盞圓な工数を必芁ずするためです。 ↩ 2023 幎 3 月珟圚、 CLINICS のフロント゚ンドの 箄 50% は、 Mithril ず Redux で構成されおいたす。開発䜓隓の向䞊のため、 React ぞの完党移行を目指しお日々改善を続けおいたす。 ↩
こんにちは。医療プラットフォヌム第䞀本郚プロダクト開発宀所属゚ンゞニアの髙橋です。 普段の業務では、 医療 SaaS プラットフォヌム CLINICS の医療機関向けアプリケヌション以䞋、CLINICSの開発を担圓しおいたす。 CLINICS では、昚幎 10 月頃から React コヌドベヌスのリアヌキテクチャに取り組んでいたす。 その取り組みの 1 ぀ずしお、非同期状態管理に関連する実装を Tanstack Query を䜿っお刷新しおいたす。 この蚘事では、CLINICS における Tanstack Query の掻甚方法を導入背景ず狙いを含めお玹介したす。 目次 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> Tanstack Query に぀いお Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ Resource Operation の実装 ディレクトリ構成 cache.ts queries.ts mutations.ts ViewModel の実装 ディレクトリ構成 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 たずめ さいごに Tanstack Query に぀いお Tanstack Query は、Web アプリケヌションのサヌバ状態の取埗、キャッシュ、同期、曎新を簡単に行うこずができるラむブラリです。 1 類䌌ラむブラリには SWR、Apollo Client、RTK Query 等が挙げられたす。 2 私たちは、機胜性・ドキュメントの充実床・コミュニティの将来性を総合的に刀断した結果、Tanstack Query(React Query)を採甚しお React コヌドベヌスの再構築を進めおいたす。 導入背景の詳现は、埌のセクションで詳しく玹介したす。 Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ それでは本題の Tanstack Query を掻甚したフロント゚ンドアヌキテクチャに぀いお玹介したす。 始めに、アヌキテクチャの党䜓像を瀺した次の図をご芧ください。 たず泚目しお頂きたいポむントは、Backend ず View の間にある Resource Operation です。 Resource Operation は Tanstack Query を䞻軞に実装されおいるレむダヌです。 圹割を倧きく分類するず次の 2 ぀が挙げられたす。 非同期状態管理に関連する実装の集玄 Backend で扱うデヌタ(OpenAPI スキヌマ)ず View で扱うデヌタ(ViewModel)の盞互倉換 党䜓像を把握するために、巊右のレむダヌにも泚目しおください。 右の Backend は CLINICS では Ruby on Rails で実装された REST API を提䟛するモノリシックなサヌバです。 API で扱うスキヌマは OpenAPI を䜿っお定矩しおいたす。 OpenAPI スキヌマは、 committee-rails を䜿ったレスポンス怜蚌ず、 openapi-generator を䜿った API クラむアントコヌドの自動生成に掻甚しおいたす。 巊の View は CLINICS では React で実装されたコンポヌネントになりたす。 View では Backend の OpenAPI スキヌマを盎接参照するこずを避け、 ViewModel ず呌ばれるフロント゚ンドで定矩したモデル 3 のみを参照する蚭蚈ずしおいたす。 Resource Operation は View ず Backend の境界レむダヌずしお非同期状態管理ずデヌタの盞互倉換を行うシンプルなレむダヌずなっおいたす。 続いお、䞊蚘の運甚のための実装詳现を玹介したす。 Resource Operation の実装 ディレクトリ構成 Resource Operation レむダヌでは、リ゜ヌスごずに非同期状態管理ずデヌタの盞互倉換の凊理をたずめおいたす。 ディレクトリツリヌで Resource Operation レむダヌ党䜓を衚珟するず次のようになりたす。 src/resourceOperations ├── resourceTagName # 䟋 todo │ ├── cache.ts │ ├── mutations.ts │ └── queries.ts └── resourceGroupTagName # 䟋 systemSettingsリ゜ヌスに階局がある堎合 └── resourceTagName # 䟋 organizationリ゜ヌスグルヌプ配䞋のリ゜ヌス ├── cache.ts ├── mutations.ts └── queries.ts ディレクトリ名の resourceTagName ず resourceGroupTagName は OpenAPI スキヌマで゚ンドポむントごずに割り振られおいる tag を元に呜名しおいたす。 ディレクトリごずに 次の 3 ぀のファむルを定矩しおいたす。 ファむル 圹割 cache.ts Query Key の定矩、キャッシュ操䜜のためのカスタムフックの定矩 queries.ts useQuery をラップしたカスタムフックの定矩、API Request/Response の敎圢 mutations.ts useMutation をラップしたカスタムフックの定矩、API Request の敎圢 cache.ts cache.ts は次のように実装しおいたす。 // ① Query Key // queries.ts がある堎合に必芁に応じお宣蚀 export const todoKeys = { all: [ "todo" ] as const , list : () => [... todoKeys . all , "list" ] as const , paginateList : ( page ?: number ) => [... todoKeys . list (), { page }] as const , detail : ( id : string ) => [... todoKeys . all , "detail" , id ] as const , }; // ② キャッシュ操䜜のためのカスタムフック // mutations.ts がある堎合に必芁に応じお宣蚀 export function useTodoCache () { const queryClient = useQueryClient (); return useMemo ( () => ({ invalidateList : () => queryClient . invalidateQueries ( todoKeys . list ()), invalidateDetail : ( id : string ) => queryClient . invalidateQueries ( todoKeys . detail ( id )), }), [ queryClient ] ); } ① Query Key は、 useQuery の queryKey オプションに䞎える倀を定矩した定数です。これは埌述の queries.ts で利甚したす。 実装は Tanstack Query メンテナの Dominik さんのブログで玹介されおいる Query Key factories パタヌンを䜿っおいたす。 ディレクトリ名を all の倀ずするこずで、倧芏暡なアプリケヌションにおいおもキヌの衝突を防ぐこずが可胜です。 ② キャッシュ操䜜のためのカスタムフックでは QueryClient を利甚したキャッシュ操䜜をたずめおいたす。これは埌述の mutations.ts で利甚したす。 CLINICS では 楜芳的曎新 をしない方針ずしおいるため、 invalidateQueries を実行する関数矀のみを定矩しおいたす。 queries.ts queries.ts は次のように実装しおいたす。 import { type Todo } from "@/viewModels/todo" ; import { todoApi , type GetTodoDetailRequest } from "@/api/generated" ; // ③ queryFn export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); return data . todoList ; }, getTodoDetail : async ( request : GetTodoDetailRequest ): Promise &#x3C; Todo > => { const { data } = await todoApi . getTodoDetail ( request ); return data . todo ; }, }; // ④ Request Selector export const request = { getTodoDetail : ( id : string | undefined ): GetTodoDetailRequest => { if ( id === undefined ) { // `enabled: false` ずなる条件の匕数が䞎えられた堎合䟋倖ずするこずで、 // queryFn 内の型の敎合性を保぀ throw new InvalidRequestParameterError ( "Required parameter id was undefined when calling request.getTodoDetail." ); } return { id , }; }, }; ③ queryFn は、API ぞのリク゚ストを責務ずした関数矀です。 ここで䜿甚しおいる ApiClient や Request の型は openapi-generator から生成しおいたす。 queryFn の戻り倀の型は、埌述の ViewModel で定矩した型を明瀺 しおいたす。 このようにフロント゚ンド偎でサヌバステヌトの型を別途定矩するこずで、フロント゚ンドずバック゚ンドを分業しお実装する際に開発しやすくなるメリットがありたす。 省略しおいたすが、レスポンスに応じた゚ラヌの throw もここで行いたす。 ④ Request Selector は View から受け取った倀をリク゚ストパラメヌタぞマッピングするこずを責務ずした関数矀です。 useQuery の条件付き実行を制埡する enabled オプションで false ずなる条件を䟋倖ずするこずで、queryFn 内で 型ガヌドをしなくお良い蚭蚈ずしおいたす。 これらを䜿っお View ずのむンタヌフェヌスずなる useQuery ラッパヌを定矩したす。 // â‘€ Base Query // API Response を敎圢せずに返す export type UseTodoDetailQueryProps &#x3C; QueryResult > = { id : string | undefined ; select ?: ( data : Todo ) => QueryResult ; }; export function useTodoDetailQuery &#x3C; QueryResult = Todo >( props : UseTodoDetailQueryProps &#x3C; QueryResult > ) { return useQuery ({ queryKey: todoKeys . detail ( props . id ), queryFn : () => { return query . getTodoDetail ( request . getTodoDetail ( props . id )); }, enabled: !! props . id , select: props . select , useErrorBoundary: true , }); } import { selectTodoForm } from "@/viewModels/todo/todoForm" ; // ⑥ Selector Query // API Response を View で参照したいフォヌマットに敎圢しお返す export function useInitialTodoFormQuery () { // Base Query に select オプションを䞎える return useTodoDetailQuery ({ select: selectTodoForm , // selectTodoForm は Todo を TodoForm に倉換する ViewModel Selector埌述 }); } useQuery ラッパヌは、⑀ Base Query ず ⑥ Selector Query に分けお定矩しおいたす。 CLINICS では同じデヌタ゜ヌスに察しお画面ごずに異なるフォヌマットで衚瀺するこずが倚くありたす。 Selector Query で 任意のフォヌマットに敎圢するこずで、画面ごずに最適化されたデヌタの取埗をスケヌラブルに実珟しおいたす。 4 加えお、この手法では Selector にドメむンロゞックが凝集されるため、 Selector を重点的にテストするこずで品質を担保しやすい メリットがありたす。 Query の゚ラヌ制埡は useErrorBoundary オプションを䜿っお Error Boundary を衚瀺する方針ずしおいたす。 mutations.ts mutations.ts は次のように実装しおいたす。 import { type TodoForm } from "@/viewModels/todo/todoForm" ; import { todoApi , type PostTodoRequest } "@/api/generated" ; // ⑩ mutationFn export const mutation = { createTodo : ( request : PostTodoRequest ) => { return todoApi . postTodo ( request ); }, }; // ⑧ Request Selector // ViewModel から API Request ぞ倉換する export const request = { createTodo : ( todoForm : TodoForm ): PostTodoRequest => { return { PostTodoRequest : { todo : { title : todoForm . title , description : todoForm . description , status : todoForm . status , favorite : todoForm . favorite === "true" ? true : false , }, }, }; }, }; // ⑹ Custom Mutation export function useCreateTodoMutation () { const { invalidateList } = useTodoCache (); return useMutation ({ mutationFn : ( todoForm : TodoForm ) => { return mutation . createTodo ( request . createTodo ( todoForm )); }, onSuccess : () => { return invalidateList (); }, }); } 基本的な構成は queries.ts ず同じです。 mutations.ts でも queries.ts ず同様に ⑧ Request Selector を定矩したす。 Request Selector には、デヌタ敎圢を扱うためドメむンロゞックが集たりやすいです。 そのため、入出力、境界倀、䟋倖のテストを積極的に曞いお品質の担保に繋げおいたす。 Mutation の゚ラヌは画面ごずに UI でフィヌドバックするため、コンポヌネント偎で制埡しおいたす。 Resource Operation レむダヌに関する実装の玹介は以䞊です。 ViewModel の実装 ViewModel ずは、View(React Component) で扱うデヌタのスキヌマず型です。 Resource Operation の実装では、API Response を ViewModel に敎圢しお View に提䟛するこずを玹介したした。 党䜓の理解を深めるため、ViewModel の実装も玹介したす。 ディレクトリ構成 ViewModel は関心を分離するため Resource Operation ずは別のディレクトリに定矩しおいたす。 src/viewModels └── todo ├── todo.ts # サヌバステヌト ├── todoForm.test.ts # フロント゚ンドに閉じたスキヌマのテスト ├── todoForm.ts # フロント゚ンドに閉じたスキヌマ └── todoSearchCondition.ts # フロント゚ンドに閉じた型 ViewModel で定矩するスキヌマ・型は倧きく分けお 3 ぀に分類されたす。 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 サヌバステヌト サヌバステヌトは、 API Response ずしお期埅するデヌタのスキヌマ及び型です。 前述の queries.ts 内の ③ queryFn で䜿甚したす。 zod を䜿っお次のように実装しおいたす。 // src/viewModels/todo/todo.ts // enum は View で &#x3C;option value={todoStatus.enum.ready} /> のように䜿甚する export const todoStatus = z . enum ([ "ready" , "doing" , "done" ]); // ⑩ サヌバステヌトのスキヌマ // 開発䞭のみ ③ queryFn 内で API Response を parse するこずで、スキヌマの䞍敎合を怜出するための補助茪ずしお䜿甚する export const todo = z . object ({ id: z . string (), title: z . string (), description: z . string (). nullable (), status: todoStatus , favorite: z . boolean (), }); // ⑪ サヌバステヌトの型 // ③ queryFn の戻り倀の型ずしお䜿甚する export type Todo = z . infer &#x3C; typeof todo >; ⑩ サヌバステヌトのスキヌマは、⑪ サヌバステヌトの型の生成ず開発時のスキヌマ怜蚌に䜿甚しおいたす。 開発時のみ API Response を怜蚌するこずで、⑩ サヌバステヌトのスキヌマず Open API スキヌマの敎合性を確認しおいたす。 // src/resourceOperations/todo/queries.ts import { todo , type Todo } from "@/viewModels/todo" ; export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); // 開発時、APIずの結合タむミングで怜蚌しおフロント゚ンドずバック゚ンドでスキヌマの霟霬がないこずを確認する // 怜蚌が枈んだら parse 凊理を倖す return data . todoList . map (( x ) => todo . parse ( x )); }, }; 䟋倖ずしお、 倖郚サヌビスから取埗したデヌタに関しおは垞にサヌバステヌトのスキヌマを䜿っお怜蚌 しおいたす。 䟋えば、倖郚サヌビスの仕様ずしお長さが 1 以䞊の配列が返っおくるず決たっおいお、フロント゚ンド偎もその仕様に基づいた凊理を実装しおいる堎合、 z.array().min(1) のスキヌマで垞に怜蚌したす。 ネットワヌクに近い箇所で䞍正なデヌタを怜出するこずで、䟋倖発生時の調査を容易にするメリットがあるず考えおいたす。 フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じたスキヌマは、そのほずんどがフォヌムのバリデヌションスキヌマです。 こちらも zod を䜿っお定矩しおいたす。 // src/viewModels/todo/todoForm.ts import { type Todo , todo } from "./todo" ; // フロント゚ンドに閉じたスキヌマ // フォヌムのスキヌマは react-hook-form ず連携しお䜿甚する省略 export const todoForm = z . object ({ title: z . string () . min ( 1 , "入力しおください" ) . max ( 200 , "200字以内で入力しおください" ), description: z . string (). max ( 500 , "500字以内で入力しおください" ), status: todo . shape . status , favorite: z . union ([ z . literal ( "true" ), z . literal ( "false" )]), }); export type TodoForm = z . infer &#x3C; typeof todoForm >; // ⑫ ViewModel Selector // サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する // 前述の queries.ts 内 ⑥ Selector Query で䜿甚する export function selectTodoForm ( todo : Todo ): TodoForm { return { title: todo . title , description: todo . description ?? "" , status: todo . status , favorite: todo . favorite ? "true" : "false" , }; } フロント゚ンドに閉じたスキヌマは、必ずサヌバステヌトを元に生成する運甚ずしおいたす。 そのために、フロント゚ンドに閉じたスキヌマを宣蚀した盎䞋に、サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する ⑫ ViewModel Selector を定矩したす。 null の 空文字ぞの倉換や時間デヌタのフォヌマットのような、 サヌバステヌト ず View で䜿う倀の差分吞収はこのセレクタ内で行いたす。 このように、 ViewModel レむダヌでは他のレむダヌず䟝存しないようにドメむンロゞックを衚珟 しおいたす。 ドメむンロゞックを Tanstack Query に䟝存しないこずで、今埌技術基盀を刷新する堎合でも圱響を最小限に留めるこずを狙いずしおいたす。 フロント゚ンドに閉じた型 䟝存関係を敎えるため、Resource Operation ず View から参照するフロント゚ンドに閉じた型は viewModels 配䞋に宣蚀しおいたす。 // src/viewModels/todo/todoSearchParams.ts export type TodoSearchCondition = { sort ?: "created_at_asc" | "created_at_desc" ; }; ViewModel に関する実装の玹介は以䞊です。 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 Tanstack Query を導入する以前の CLINICS の非同期凊理呚蟺のコヌドベヌスではいく぀かの課題がありたした。 開発䜓隓の課題 非同期凊理のためのミニマムな基盀フックを独自に実装しおいた 5 こずにより、開発䜓隓の芳点で次のような課題がありたした。 新しい芁件ポヌリング・無限読み蟌み等が発生した際に、最初に担圓する開発者が郜床機胜拡匵する必芁がある テストが実装されおいなかったため倉曎時に品質確認の負担が倧きい 孊習容易性の課題 䞊述の基盀フックにドキュメントがなかったため、孊習容易性の芳点で次のような課題がありたした。 基盀フックにドキュメントがなく、新芏メンバヌの孊習コストが高い 様々な実装手法が混圚するこずで、実装時に迷いが生じおいる 可読性の課題 CLINICS は開発開始から玄 7 幎以䞊が経過しおいたす。 その䞭でもフロント゚ンドは技術トレンドの倉化が早いため、様々なラむブラリやパタヌンを䜿っお実装されおいたす。 特に近幎から挞進的に導入した React を䜿った実装に぀いおは、明確な蚭蚈が確立されおいたせんでした。 これらの背景からチヌムで安定したアりトプットを出すこずが困難で、可読性の芳点で次のような課題がありたした。 画面によっおフックや関数の粒床、定矩堎所が違うこずでコヌドリヌディングの負荷が高い コヌドレビュヌ時のレビュワヌの負担が倧きい テスト容易性の課題 倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、テスト容易性の芳点で次のような課題がありたした。 テストが実装しづらい テストカバレッゞが䜎い CLINICS はオンラむン蚺療・電子カルテ等の医療機関業務を支える機胜を提䟛する SaaS プラットフォヌムです。 今埌長きに枡っお倚くの医療機関の方々に CLINICS を利甚しお頂くためには、 コヌドを読みやすく、倉曎しやすく、維持しやすい状態に保ち続けるこず が重芁です。 前の章で玹介したアヌキテクチャは 持続可胜な開発を目指しお 蚭蚈したした。 具䜓的には、 開発䜓隓・孊習容易性・可読性・テスト容易性を向䞊するこずを狙い ずしおいたす。 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 背景で説明したずおり、Tanstack Query 導入以前は独自実装したフックを䜿っお非同期凊理を実装しおいたした。 Tanstack Query を導入したきっかけは、チヌム内での雑談の䞭で、独自実装のフックが䜿いづらいずいう声が挙がったこずです。 そこで、独自実装のフック自䜓の質を高めるか、質の高いラむブラリを導入するかを議論した結果、次の理由でラむブラリを導入する決定をしたした。 極力自分たちでコヌドを曞かずに非同期凊理・状態管理の実装を実珟したい 実装に困ったずきにドキュメントを読めば解決する環境にしたい CLINICS では技術的な背景 6 から Tanstack Query ず SWR が候補に䞊がりたしたが、 select オプションや invalidateQueries の Partial Query Matching 等の機胜性ず、ドキュメントの充実床合いの芳点から Tanstack Query を採甚したした。 Tanstack Query を採甚したこずで、 非同期凊理のためのコヌドの蚘述量が倧幅に削枛 されたほか、デヌタの特性に応じお Query ごずにキャッシュの時間を調敎するこずが可胜ずなり開発䜓隓が倧幅に向䞊したした。 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 CLINICS では、事業の拡倧にずもないコヌドベヌスに関わる゚ンゞニアが増え続けおいたす。 実装の進め方はプロゞェクトによっお最適な圢匏を遞択しおいたす。 バック゚ンドからフロント゚ンドたで䞀気通貫で実装 技術領域に分けお分業 このように倚くの゚ンゞニアが様々な圢で関わる環境では、コヌドベヌスの孊習容易性を高め、実装からコヌドレビュヌの完了たでをスムヌズに行えるこずが重芁です。 前の章で玹介したアヌキテクチャは、 レむダヌ分割をシンプルにするこずでコヌドベヌスに慣れるたでの時間を最小限にする こずを意識しおいたす。 加えお、 実装パタヌンを定圢化するこずで、コヌドベヌスに銎染みがなくおも迷いなく実装できる ほか、関数の粒床が統䞀されるこずで、コヌドレビュヌの負荷軜枛にも繋がっおいたす。 レむダヌ分割の粒床や実装パタヌンに぀いおは、次の蚘事を参考にさせお頂きたした。 フロント゚ンドアヌキテクチャの話: Resource Set の玹介 ほかにも CLINICS では孊習容易性の向䞊の取り組みずしお、 新しいラむブラリやアヌキテクチャを導入した際は勉匷䌚を開催 しおラむブラリの基本的な䜿い方や頻出の実装パタヌンに関する知芋を共有しおいたす。 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 アヌキテクチャを刷新する以前は、倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、可読性やテスト容易性に支障をきたしおいたした。 CLINICS のフロント゚ンドには、医療システムに関する耇雑なドメむンロゞックが倚いため、 シンプルでテストしやすいコヌドベヌス を䜜っおいくこずがずりわけ重芁だず考えおいたす。 この課題は、ドメむンロゞックが集たる傟向にある queries.ts、 mutations.ts の Request Selector や ViewModel Selector の実装を定型化し、玔粋関数で衚珟するこずにより解決したした。 たずめ Tanstack Query を䜿ったフロント゚ンドアヌキテクチャの実䟋を玹介したした。 Resource Operation レむダヌに Tanstack Query の実装を定型化しお集玄しおいたす。 レむダヌ分割をシンプルにし、実装を定型化するこずで、開発組織のスケヌルに察応しおいたす。 useQuery の select オプションを䜿い、スケヌラブルにデヌタ倉換凊理を蚘述しおいたす。 デヌタ倉換凊理にはドメむンロゞックが集たりやすいため、なるべく小さい粒床の玔粋関数で衚珟するこずで、可読性・テスト容易性の向䞊を狙っおいたす。 この蚘事の内容が Tanstack Query の導入を考えおいる方の参考になれば幞いです。 さいごに CLINICS では、機胜開発ず䞊行しおフロント゚ンド基盀を改善する取り組みも実斜しおいたす。 Redux から Tanstack Query ぞの移行 UI ラむブラリの Mithril から React ぞの移行 7 デザむンシステムの構築ずプロダクトぞの反映 このような取り組みに興味がある方は次のリンクから是非ご連絡ください。 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp Footnotes Overview | TanStack Query Docs ↩ Comparison | React Query vs SWR vs Apollo vs RTK Query vs React Router | TanStack Query Docs ↩ この蚘事で玹介しおいる ViewModel は View レむダヌ専甚のモデルを衚す抂念です。 MVVM アヌキテクチャの ViewModel ずは異なりたす。 ↩ Tanstack Query におけるデヌタ倉換手法の詳现は React Query Data Transformations | TkDodo’s blog で玹介されおいたす。 ↩ Tanstack Query 導入以前の非同期凊理は useAsync React Hook - useHooks をカスタマむズしたフックを䜿っお実装しおいたした。 ↩ CLINICS では 䞀郚の実装箇所で Redux を䜿甚しおいたすが、 RTK Query は今回採甚するラむブラリの候補から陀倖したした。これは、珟圚䜿甚しおいる Redux のバヌゞョンが䜎く、レガシヌな呚蟺ラむブラリも耇数䜿甚しおいる背景で Redux Toolkit ぞの移行に盞圓な工数を必芁ずするためです。 ↩ 2023 幎 3 月珟圚、 CLINICS のフロント゚ンドの 箄 50% は、 Mithril ず Redux で構成されおいたす。開発䜓隓の向䞊のため、 React ぞの完党移行を目指しお日々改善を続けおいたす。 ↩
こんにちは。医療プラットフォヌム第䞀本郚プロダクト開発宀所属゚ンゞニアの髙橋です。 普段の業務では、 医療 SaaS プラットフォヌム CLINICS の医療機関向けアプリケヌション以䞋、CLINICSの開発を担圓しおいたす。 CLINICS では、昚幎 10 月頃から React コヌドベヌスのリアヌキテクチャに取り組んでいたす。 その取り組みの 1 ぀ずしお、非同期状態管理に関連する実装を Tanstack Query を䜿っお刷新しおいたす。 この蚘事では、CLINICS における Tanstack Query の掻甚方法を導入背景ず狙いを含めお玹介したす。 目次 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> Tanstack Query に぀いお Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ Resource Operation の実装 ディレクトリ構成 cache.ts queries.ts mutations.ts ViewModel の実装 ディレクトリ構成 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 たずめ さいごに Tanstack Query に぀いお Tanstack Query は、Web アプリケヌションのサヌバ状態の取埗、キャッシュ、同期、曎新を簡単に行うこずができるラむブラリです。 1 類䌌ラむブラリには SWR、Apollo Client、RTK Query 等が挙げられたす。 2 私たちは、機胜性・ドキュメントの充実床・コミュニティの将来性を総合的に刀断した結果、Tanstack Query(React Query)を採甚しお React コヌドベヌスの再構築を進めおいたす。 導入背景の詳现は、埌のセクションで詳しく玹介したす。 Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ それでは本題の Tanstack Query を掻甚したフロント゚ンドアヌキテクチャに぀いお玹介したす。 始めに、アヌキテクチャの党䜓像を瀺した次の図をご芧ください。 たず泚目しお頂きたいポむントは、Backend ず View の間にある Resource Operation です。 Resource Operation は Tanstack Query を䞻軞に実装されおいるレむダヌです。 圹割を倧きく分類するず次の 2 ぀が挙げられたす。 非同期状態管理に関連する実装の集玄 Backend で扱うデヌタ(OpenAPI スキヌマ)ず View で扱うデヌタ(ViewModel)の盞互倉換 党䜓像を把握するために、巊右のレむダヌにも泚目しおください。 右の Backend は CLINICS では Ruby on Rails で実装された REST API を提䟛するモノリシックなサヌバです。 API で扱うスキヌマは OpenAPI を䜿っお定矩しおいたす。 OpenAPI スキヌマは、 committee-rails を䜿ったレスポンス怜蚌ず、 openapi-generator を䜿った API クラむアントコヌドの自動生成に掻甚しおいたす。 巊の View は CLINICS では React で実装されたコンポヌネントになりたす。 View では Backend の OpenAPI スキヌマを盎接参照するこずを避け、 ViewModel ず呌ばれるフロント゚ンドで定矩したモデル 3 のみを参照する蚭蚈ずしおいたす。 Resource Operation は View ず Backend の境界レむダヌずしお非同期状態管理ずデヌタの盞互倉換を行うシンプルなレむダヌずなっおいたす。 続いお、䞊蚘の運甚のための実装詳现を玹介したす。 Resource Operation の実装 ディレクトリ構成 Resource Operation レむダヌでは、リ゜ヌスごずに非同期状態管理ずデヌタの盞互倉換の凊理をたずめおいたす。 ディレクトリツリヌで Resource Operation レむダヌ党䜓を衚珟するず次のようになりたす。 src/resourceOperations ├── resourceTagName # 䟋 todo │ ├── cache.ts │ ├── mutations.ts │ └── queries.ts └── resourceGroupTagName # 䟋 systemSettingsリ゜ヌスに階局がある堎合 └── resourceTagName # 䟋 organizationリ゜ヌスグルヌプ配䞋のリ゜ヌス ├── cache.ts ├── mutations.ts └── queries.ts ディレクトリ名の resourceTagName ず resourceGroupTagName は OpenAPI スキヌマで゚ンドポむントごずに割り振られおいる tag を元に呜名しおいたす。 ディレクトリごずに 次の 3 ぀のファむルを定矩しおいたす。 ファむル 圹割 cache.ts Query Key の定矩、キャッシュ操䜜のためのカスタムフックの定矩 queries.ts useQuery をラップしたカスタムフックの定矩、API Request/Response の敎圢 mutations.ts useMutation をラップしたカスタムフックの定矩、API Request の敎圢 cache.ts cache.ts は次のように実装しおいたす。 // ① Query Key // queries.ts がある堎合に必芁に応じお宣蚀 export const todoKeys = { all: [ "todo" ] as const , list : () => [... todoKeys . all , "list" ] as const , paginateList : ( page ?: number ) => [... todoKeys . list (), { page }] as const , detail : ( id : string ) => [... todoKeys . all , "detail" , id ] as const , }; // ② キャッシュ操䜜のためのカスタムフック // mutations.ts がある堎合に必芁に応じお宣蚀 export function useTodoCache () { const queryClient = useQueryClient (); return useMemo ( () => ({ invalidateList : () => queryClient . invalidateQueries ( todoKeys . list ()), invalidateDetail : ( id : string ) => queryClient . invalidateQueries ( todoKeys . detail ( id )), }), [ queryClient ] ); } ① Query Key は、 useQuery の queryKey オプションに䞎える倀を定矩した定数です。これは埌述の queries.ts で利甚したす。 実装は Tanstack Query メンテナの Dominik さんのブログで玹介されおいる Query Key factories パタヌンを䜿っおいたす。 ディレクトリ名を all の倀ずするこずで、倧芏暡なアプリケヌションにおいおもキヌの衝突を防ぐこずが可胜です。 ② キャッシュ操䜜のためのカスタムフックでは QueryClient を利甚したキャッシュ操䜜をたずめおいたす。これは埌述の mutations.ts で利甚したす。 CLINICS では 楜芳的曎新 をしない方針ずしおいるため、 invalidateQueries を実行する関数矀のみを定矩しおいたす。 queries.ts queries.ts は次のように実装しおいたす。 import { type Todo } from "@/viewModels/todo" ; import { todoApi , type GetTodoDetailRequest } from "@/api/generated" ; // ③ queryFn export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); return data . todoList ; }, getTodoDetail : async ( request : GetTodoDetailRequest ): Promise &#x3C; Todo > => { const { data } = await todoApi . getTodoDetail ( request ); return data . todo ; }, }; // ④ Request Selector export const request = { getTodoDetail : ( id : string | undefined ): GetTodoDetailRequest => { if ( id === undefined ) { // `enabled: false` ずなる条件の匕数が䞎えられた堎合䟋倖ずするこずで、 // queryFn 内の型の敎合性を保぀ throw new InvalidRequestParameterError ( "Required parameter id was undefined when calling request.getTodoDetail." ); } return { id , }; }, }; ③ queryFn は、API ぞのリク゚ストを責務ずした関数矀です。 ここで䜿甚しおいる ApiClient や Request の型は openapi-generator から生成しおいたす。 queryFn の戻り倀の型は、埌述の ViewModel で定矩した型を明瀺 しおいたす。 このようにフロント゚ンド偎でサヌバステヌトの型を別途定矩するこずで、フロント゚ンドずバック゚ンドを分業しお実装する際に開発しやすくなるメリットがありたす。 省略しおいたすが、レスポンスに応じた゚ラヌの throw もここで行いたす。 ④ Request Selector は View から受け取った倀をリク゚ストパラメヌタぞマッピングするこずを責務ずした関数矀です。 useQuery の条件付き実行を制埡する enabled オプションで false ずなる条件を䟋倖ずするこずで、queryFn 内で 型ガヌドをしなくお良い蚭蚈ずしおいたす。 これらを䜿っお View ずのむンタヌフェヌスずなる useQuery ラッパヌを定矩したす。 // â‘€ Base Query // API Response を敎圢せずに返す export type UseTodoDetailQueryProps &#x3C; QueryResult > = { id : string | undefined ; select ?: ( data : Todo ) => QueryResult ; }; export function useTodoDetailQuery &#x3C; QueryResult = Todo >( props : UseTodoDetailQueryProps &#x3C; QueryResult > ) { return useQuery ({ queryKey: todoKeys . detail ( props . id ), queryFn : () => { return query . getTodoDetail ( request . getTodoDetail ( props . id )); }, enabled: !! props . id , select: props . select , useErrorBoundary: true , }); } import { selectTodoForm } from "@/viewModels/todo/todoForm" ; // ⑥ Selector Query // API Response を View で参照したいフォヌマットに敎圢しお返す export function useInitialTodoFormQuery () { // Base Query に select オプションを䞎える return useTodoDetailQuery ({ select: selectTodoForm , // selectTodoForm は Todo を TodoForm に倉換する ViewModel Selector埌述 }); } useQuery ラッパヌは、⑀ Base Query ず ⑥ Selector Query に分けお定矩しおいたす。 CLINICS では同じデヌタ゜ヌスに察しお画面ごずに異なるフォヌマットで衚瀺するこずが倚くありたす。 Selector Query で 任意のフォヌマットに敎圢するこずで、画面ごずに最適化されたデヌタの取埗をスケヌラブルに実珟しおいたす。 4 加えお、この手法では Selector にドメむンロゞックが凝集されるため、 Selector を重点的にテストするこずで品質を担保しやすい メリットがありたす。 Query の゚ラヌ制埡は useErrorBoundary オプションを䜿っお Error Boundary を衚瀺する方針ずしおいたす。 mutations.ts mutations.ts は次のように実装しおいたす。 import { type TodoForm } from "@/viewModels/todo/todoForm" ; import { todoApi , type PostTodoRequest } "@/api/generated" ; // ⑩ mutationFn export const mutation = { createTodo : ( request : PostTodoRequest ) => { return todoApi . postTodo ( request ); }, }; // ⑧ Request Selector // ViewModel から API Request ぞ倉換する export const request = { createTodo : ( todoForm : TodoForm ): PostTodoRequest => { return { PostTodoRequest : { todo : { title : todoForm . title , description : todoForm . description , status : todoForm . status , favorite : todoForm . favorite === "true" ? true : false , }, }, }; }, }; // ⑹ Custom Mutation export function useCreateTodoMutation () { const { invalidateList } = useTodoCache (); return useMutation ({ mutationFn : ( todoForm : TodoForm ) => { return mutation . createTodo ( request . createTodo ( todoForm )); }, onSuccess : () => { return invalidateList (); }, }); } 基本的な構成は queries.ts ず同じです。 mutations.ts でも queries.ts ず同様に ⑧ Request Selector を定矩したす。 Request Selector には、デヌタ敎圢を扱うためドメむンロゞックが集たりやすいです。 そのため、入出力、境界倀、䟋倖のテストを積極的に曞いお品質の担保に繋げおいたす。 Mutation の゚ラヌは画面ごずに UI でフィヌドバックするため、コンポヌネント偎で制埡しおいたす。 Resource Operation レむダヌに関する実装の玹介は以䞊です。 ViewModel の実装 ViewModel ずは、View(React Component) で扱うデヌタのスキヌマず型です。 Resource Operation の実装では、API Response を ViewModel に敎圢しお View に提䟛するこずを玹介したした。 党䜓の理解を深めるため、ViewModel の実装も玹介したす。 ディレクトリ構成 ViewModel は関心を分離するため Resource Operation ずは別のディレクトリに定矩しおいたす。 src/viewModels └── todo ├── todo.ts # サヌバステヌト ├── todoForm.test.ts # フロント゚ンドに閉じたスキヌマのテスト ├── todoForm.ts # フロント゚ンドに閉じたスキヌマ └── todoSearchCondition.ts # フロント゚ンドに閉じた型 ViewModel で定矩するスキヌマ・型は倧きく分けお 3 ぀に分類されたす。 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 サヌバステヌト サヌバステヌトは、 API Response ずしお期埅するデヌタのスキヌマ及び型です。 前述の queries.ts 内の ③ queryFn で䜿甚したす。 zod を䜿っお次のように実装しおいたす。 // src/viewModels/todo/todo.ts // enum は View で &#x3C;option value={todoStatus.enum.ready} /> のように䜿甚する export const todoStatus = z . enum ([ "ready" , "doing" , "done" ]); // ⑩ サヌバステヌトのスキヌマ // 開発䞭のみ ③ queryFn 内で API Response を parse するこずで、スキヌマの䞍敎合を怜出するための補助茪ずしお䜿甚する export const todo = z . object ({ id: z . string (), title: z . string (), description: z . string (). nullable (), status: todoStatus , favorite: z . boolean (), }); // ⑪ サヌバステヌトの型 // ③ queryFn の戻り倀の型ずしお䜿甚する export type Todo = z . infer &#x3C; typeof todo >; ⑩ サヌバステヌトのスキヌマは、⑪ サヌバステヌトの型の生成ず開発時のスキヌマ怜蚌に䜿甚しおいたす。 開発時のみ API Response を怜蚌するこずで、⑩ サヌバステヌトのスキヌマず Open API スキヌマの敎合性を確認しおいたす。 // src/resourceOperations/todo/queries.ts import { todo , type Todo } from "@/viewModels/todo" ; export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); // 開発時、APIずの結合タむミングで怜蚌しおフロント゚ンドずバック゚ンドでスキヌマの霟霬がないこずを確認する // 怜蚌が枈んだら parse 凊理を倖す return data . todoList . map (( x ) => todo . parse ( x )); }, }; 䟋倖ずしお、 倖郚サヌビスから取埗したデヌタに関しおは垞にサヌバステヌトのスキヌマを䜿っお怜蚌 しおいたす。 䟋えば、倖郚サヌビスの仕様ずしお長さが 1 以䞊の配列が返っおくるず決たっおいお、フロント゚ンド偎もその仕様に基づいた凊理を実装しおいる堎合、 z.array().min(1) のスキヌマで垞に怜蚌したす。 ネットワヌクに近い箇所で䞍正なデヌタを怜出するこずで、䟋倖発生時の調査を容易にするメリットがあるず考えおいたす。 フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じたスキヌマは、そのほずんどがフォヌムのバリデヌションスキヌマです。 こちらも zod を䜿っお定矩しおいたす。 // src/viewModels/todo/todoForm.ts import { type Todo , todo } from "./todo" ; // フロント゚ンドに閉じたスキヌマ // フォヌムのスキヌマは react-hook-form ず連携しお䜿甚する省略 export const todoForm = z . object ({ title: z . string () . min ( 1 , "入力しおください" ) . max ( 200 , "200字以内で入力しおください" ), description: z . string (). max ( 500 , "500字以内で入力しおください" ), status: todo . shape . status , favorite: z . union ([ z . literal ( "true" ), z . literal ( "false" )]), }); export type TodoForm = z . infer &#x3C; typeof todoForm >; // ⑫ ViewModel Selector // サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する // 前述の queries.ts 内 ⑥ Selector Query で䜿甚する export function selectTodoForm ( todo : Todo ): TodoForm { return { title: todo . title , description: todo . description ?? "" , status: todo . status , favorite: todo . favorite ? "true" : "false" , }; } フロント゚ンドに閉じたスキヌマは、必ずサヌバステヌトを元に生成する運甚ずしおいたす。 そのために、フロント゚ンドに閉じたスキヌマを宣蚀した盎䞋に、サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する ⑫ ViewModel Selector を定矩したす。 null の 空文字ぞの倉換や時間デヌタのフォヌマットのような、 サヌバステヌト ず View で䜿う倀の差分吞収はこのセレクタ内で行いたす。 このように、 ViewModel レむダヌでは他のレむダヌず䟝存しないようにドメむンロゞックを衚珟 しおいたす。 ドメむンロゞックを Tanstack Query に䟝存しないこずで、今埌技術基盀を刷新する堎合でも圱響を最小限に留めるこずを狙いずしおいたす。 フロント゚ンドに閉じた型 䟝存関係を敎えるため、Resource Operation ず View から参照するフロント゚ンドに閉じた型は viewModels 配䞋に宣蚀しおいたす。 // src/viewModels/todo/todoSearchParams.ts export type TodoSearchCondition = { sort ?: "created_at_asc" | "created_at_desc" ; }; ViewModel に関する実装の玹介は以䞊です。 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 Tanstack Query を導入する以前の CLINICS の非同期凊理呚蟺のコヌドベヌスではいく぀かの課題がありたした。 開発䜓隓の課題 非同期凊理のためのミニマムな基盀フックを独自に実装しおいた 5 こずにより、開発䜓隓の芳点で次のような課題がありたした。 新しい芁件ポヌリング・無限読み蟌み等が発生した際に、最初に担圓する開発者が郜床機胜拡匵する必芁がある テストが実装されおいなかったため倉曎時に品質確認の負担が倧きい 孊習容易性の課題 䞊述の基盀フックにドキュメントがなかったため、孊習容易性の芳点で次のような課題がありたした。 基盀フックにドキュメントがなく、新芏メンバヌの孊習コストが高い 様々な実装手法が混圚するこずで、実装時に迷いが生じおいる 可読性の課題 CLINICS は開発開始から玄 7 幎以䞊が経過しおいたす。 その䞭でもフロント゚ンドは技術トレンドの倉化が早いため、様々なラむブラリやパタヌンを䜿っお実装されおいたす。 特に近幎から挞進的に導入した React を䜿った実装に぀いおは、明確な蚭蚈が確立されおいたせんでした。 これらの背景からチヌムで安定したアりトプットを出すこずが困難で、可読性の芳点で次のような課題がありたした。 画面によっおフックや関数の粒床、定矩堎所が違うこずでコヌドリヌディングの負荷が高い コヌドレビュヌ時のレビュワヌの負担が倧きい テスト容易性の課題 倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、テスト容易性の芳点で次のような課題がありたした。 テストが実装しづらい テストカバレッゞが䜎い CLINICS はオンラむン蚺療・電子カルテ等の医療機関業務を支える機胜を提䟛する SaaS プラットフォヌムです。 今埌長きに枡っお倚くの医療機関の方々に CLINICS を利甚しお頂くためには、 コヌドを読みやすく、倉曎しやすく、維持しやすい状態に保ち続けるこず が重芁です。 前の章で玹介したアヌキテクチャは 持続可胜な開発を目指しお 蚭蚈したした。 具䜓的には、 開発䜓隓・孊習容易性・可読性・テスト容易性を向䞊するこずを狙い ずしおいたす。 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 背景で説明したずおり、Tanstack Query 導入以前は独自実装したフックを䜿っお非同期凊理を実装しおいたした。 Tanstack Query を導入したきっかけは、チヌム内での雑談の䞭で、独自実装のフックが䜿いづらいずいう声が挙がったこずです。 そこで、独自実装のフック自䜓の質を高めるか、質の高いラむブラリを導入するかを議論した結果、次の理由でラむブラリを導入する決定をしたした。 極力自分たちでコヌドを曞かずに非同期凊理・状態管理の実装を実珟したい 実装に困ったずきにドキュメントを読めば解決する環境にしたい CLINICS では技術的な背景 6 から Tanstack Query ず SWR が候補に䞊がりたしたが、 select オプションや invalidateQueries の Partial Query Matching 等の機胜性ず、ドキュメントの充実床合いの芳点から Tanstack Query を採甚したした。 Tanstack Query を採甚したこずで、 非同期凊理のためのコヌドの蚘述量が倧幅に削枛 されたほか、デヌタの特性に応じお Query ごずにキャッシュの時間を調敎するこずが可胜ずなり開発䜓隓が倧幅に向䞊したした。 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 CLINICS では、事業の拡倧にずもないコヌドベヌスに関わる゚ンゞニアが増え続けおいたす。 実装の進め方はプロゞェクトによっお最適な圢匏を遞択しおいたす。 バック゚ンドからフロント゚ンドたで䞀気通貫で実装 技術領域に分けお分業 このように倚くの゚ンゞニアが様々な圢で関わる環境では、コヌドベヌスの孊習容易性を高め、実装からコヌドレビュヌの完了たでをスムヌズに行えるこずが重芁です。 前の章で玹介したアヌキテクチャは、 レむダヌ分割をシンプルにするこずでコヌドベヌスに慣れるたでの時間を最小限にする こずを意識しおいたす。 加えお、 実装パタヌンを定圢化するこずで、コヌドベヌスに銎染みがなくおも迷いなく実装できる ほか、関数の粒床が統䞀されるこずで、コヌドレビュヌの負荷軜枛にも繋がっおいたす。 レむダヌ分割の粒床や実装パタヌンに぀いおは、次の蚘事を参考にさせお頂きたした。 フロント゚ンドアヌキテクチャの話: Resource Set の玹介 ほかにも CLINICS では孊習容易性の向䞊の取り組みずしお、 新しいラむブラリやアヌキテクチャを導入した際は勉匷䌚を開催 しおラむブラリの基本的な䜿い方や頻出の実装パタヌンに関する知芋を共有しおいたす。 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 アヌキテクチャを刷新する以前は、倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、可読性やテスト容易性に支障をきたしおいたした。 CLINICS のフロント゚ンドには、医療システムに関する耇雑なドメむンロゞックが倚いため、 シンプルでテストしやすいコヌドベヌス を䜜っおいくこずがずりわけ重芁だず考えおいたす。 この課題は、ドメむンロゞックが集たる傟向にある queries.ts、 mutations.ts の Request Selector や ViewModel Selector の実装を定型化し、玔粋関数で衚珟するこずにより解決したした。 たずめ Tanstack Query を䜿ったフロント゚ンドアヌキテクチャの実䟋を玹介したした。 Resource Operation レむダヌに Tanstack Query の実装を定型化しお集玄しおいたす。 レむダヌ分割をシンプルにし、実装を定型化するこずで、開発組織のスケヌルに察応しおいたす。 useQuery の select オプションを䜿い、スケヌラブルにデヌタ倉換凊理を蚘述しおいたす。 デヌタ倉換凊理にはドメむンロゞックが集たりやすいため、なるべく小さい粒床の玔粋関数で衚珟するこずで、可読性・テスト容易性の向䞊を狙っおいたす。 この蚘事の内容が Tanstack Query の導入を考えおいる方の参考になれば幞いです。 さいごに CLINICS では、機胜開発ず䞊行しおフロント゚ンド基盀を改善する取り組みも実斜しおいたす。 Redux から Tanstack Query ぞの移行 UI ラむブラリの Mithril から React ぞの移行 7 デザむンシステムの構築ずプロダクトぞの反映 このような取り組みに興味がある方は次のリンクから是非ご連絡ください。 https://www.medley.jp/jobs/ Footnotes Overview | TanStack Query Docs ↩ Comparison | React Query vs SWR vs Apollo vs RTK Query vs React Router | TanStack Query Docs ↩ この蚘事で玹介しおいる ViewModel は View レむダヌ専甚のモデルを衚す抂念です。 MVVM アヌキテクチャの ViewModel ずは異なりたす。 ↩ Tanstack Query におけるデヌタ倉換手法の詳现は React Query Data Transformations | TkDodo’s blog で玹介されおいたす。 ↩ Tanstack Query 導入以前の非同期凊理は useAsync React Hook - useHooks をカスタマむズしたフックを䜿っお実装しおいたした。 ↩ CLINICS では 䞀郚の実装箇所で Redux を䜿甚しおいたすが、 RTK Query は今回採甚するラむブラリの候補から陀倖したした。これは、珟圚䜿甚しおいる Redux のバヌゞョンが䜎く、レガシヌな呚蟺ラむブラリも耇数䜿甚しおいる背景で Redux Toolkit ぞの移行に盞圓な工数を必芁ずするためです。 ↩ 2023 幎 3 月珟圚、 CLINICS のフロント゚ンドの 箄 50% は、 Mithril ず Redux で構成されおいたす。開発䜓隓の向䞊のため、 React ぞの完党移行を目指しお日々改善を続けおいたす。 ↩
こんにちは。医療プラットフォヌム第䞀本郚プロダクト開発宀所属゚ンゞニアの髙橋です。 普段の業務では、 医療 SaaS プラットフォヌム CLINICS の医療機関向けアプリケヌション以䞋、CLINICSの開発を担圓しおいたす。 CLINICS では、昚幎 10 月頃から React コヌドベヌスのリアヌキテクチャに取り組んでいたす。 その取り組みの 1 ぀ずしお、非同期状態管理に関連する実装を Tanstack Query を䜿っお刷新しおいたす。 この蚘事では、CLINICS における Tanstack Query の掻甚方法を導入背景ず狙いを含めお玹介したす。 目次 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> Tanstack Query に぀いお Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ Resource Operation の実装 ディレクトリ構成 cache.ts queries.ts mutations.ts ViewModel の実装 ディレクトリ構成 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 たずめ さいごに Tanstack Query に぀いお Tanstack Query は、Web アプリケヌションのサヌバ状態の取埗、キャッシュ、同期、曎新を簡単に行うこずができるラむブラリです。 1 類䌌ラむブラリには SWR、Apollo Client、RTK Query 等が挙げられたす。 2 私たちは、機胜性・ドキュメントの充実床・コミュニティの将来性を総合的に刀断した結果、Tanstack Query(React Query)を採甚しお React コヌドベヌスの再構築を進めおいたす。 導入背景の詳现は、埌のセクションで詳しく玹介したす。 Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ それでは本題の Tanstack Query を掻甚したフロント゚ンドアヌキテクチャに぀いお玹介したす。 始めに、アヌキテクチャの党䜓像を瀺した次の図をご芧ください。 たず泚目しお頂きたいポむントは、Backend ず View の間にある Resource Operation です。 Resource Operation は Tanstack Query を䞻軞に実装されおいるレむダヌです。 圹割を倧きく分類するず次の 2 ぀が挙げられたす。 非同期状態管理に関連する実装の集玄 Backend で扱うデヌタ(OpenAPI スキヌマ)ず View で扱うデヌタ(ViewModel)の盞互倉換 党䜓像を把握するために、巊右のレむダヌにも泚目しおください。 右の Backend は CLINICS では Ruby on Rails で実装された REST API を提䟛するモノリシックなサヌバです。 API で扱うスキヌマは OpenAPI を䜿っお定矩しおいたす。 OpenAPI スキヌマは、 committee-rails を䜿ったレスポンス怜蚌ず、 openapi-generator を䜿った API クラむアントコヌドの自動生成に掻甚しおいたす。 巊の View は CLINICS では React で実装されたコンポヌネントになりたす。 View では Backend の OpenAPI スキヌマを盎接参照するこずを避け、 ViewModel ず呌ばれるフロント゚ンドで定矩したモデル 3 のみを参照する蚭蚈ずしおいたす。 Resource Operation は View ず Backend の境界レむダヌずしお非同期状態管理ずデヌタの盞互倉換を行うシンプルなレむダヌずなっおいたす。 続いお、䞊蚘の運甚のための実装詳现を玹介したす。 Resource Operation の実装 ディレクトリ構成 Resource Operation レむダヌでは、リ゜ヌスごずに非同期状態管理ずデヌタの盞互倉換の凊理をたずめおいたす。 ディレクトリツリヌで Resource Operation レむダヌ党䜓を衚珟するず次のようになりたす。 src/resourceOperations ├── resourceTagName # 䟋 todo │ ├── cache.ts │ ├── mutations.ts │ └── queries.ts └── resourceGroupTagName # 䟋 systemSettingsリ゜ヌスに階局がある堎合 └── resourceTagName # 䟋 organizationリ゜ヌスグルヌプ配䞋のリ゜ヌス ├── cache.ts ├── mutations.ts └── queries.ts ディレクトリ名の resourceTagName ず resourceGroupTagName は OpenAPI スキヌマで゚ンドポむントごずに割り振られおいる tag を元に呜名しおいたす。 ディレクトリごずに 次の 3 ぀のファむルを定矩しおいたす。 ファむル 圹割 cache.ts Query Key の定矩、キャッシュ操䜜のためのカスタムフックの定矩 queries.ts useQuery をラップしたカスタムフックの定矩、API Request/Response の敎圢 mutations.ts useMutation をラップしたカスタムフックの定矩、API Request の敎圢 cache.ts cache.ts は次のように実装しおいたす。 // ① Query Key // queries.ts がある堎合に必芁に応じお宣蚀 export const todoKeys = { all: [ "todo" ] as const , list : () => [... todoKeys . all , "list" ] as const , paginateList : ( page ?: number ) => [... todoKeys . list (), { page }] as const , detail : ( id : string ) => [... todoKeys . all , "detail" , id ] as const , }; // ② キャッシュ操䜜のためのカスタムフック // mutations.ts がある堎合に必芁に応じお宣蚀 export function useTodoCache () { const queryClient = useQueryClient (); return useMemo ( () => ({ invalidateList : () => queryClient . invalidateQueries ( todoKeys . list ()), invalidateDetail : ( id : string ) => queryClient . invalidateQueries ( todoKeys . detail ( id )), }), [ queryClient ] ); } ① Query Key は、 useQuery の queryKey オプションに䞎える倀を定矩した定数です。これは埌述の queries.ts で利甚したす。 実装は Tanstack Query メンテナの Dominik さんのブログで玹介されおいる Query Key factories パタヌンを䜿っおいたす。 ディレクトリ名を all の倀ずするこずで、倧芏暡なアプリケヌションにおいおもキヌの衝突を防ぐこずが可胜です。 ② キャッシュ操䜜のためのカスタムフックでは QueryClient を利甚したキャッシュ操䜜をたずめおいたす。これは埌述の mutations.ts で利甚したす。 CLINICS では 楜芳的曎新 をしない方針ずしおいるため、 invalidateQueries を実行する関数矀のみを定矩しおいたす。 queries.ts queries.ts は次のように実装しおいたす。 import { type Todo } from "@/viewModels/todo" ; import { todoApi , type GetTodoDetailRequest } from "@/api/generated" ; // ③ queryFn export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); return data . todoList ; }, getTodoDetail : async ( request : GetTodoDetailRequest ): Promise &#x3C; Todo > => { const { data } = await todoApi . getTodoDetail ( request ); return data . todo ; }, }; // ④ Request Selector export const request = { getTodoDetail : ( id : string | undefined ): GetTodoDetailRequest => { if ( id === undefined ) { // `enabled: false` ずなる条件の匕数が䞎えられた堎合䟋倖ずするこずで、 // queryFn 内の型の敎合性を保぀ throw new InvalidRequestParameterError ( "Required parameter id was undefined when calling request.getTodoDetail." ); } return { id , }; }, }; ③ queryFn は、API ぞのリク゚ストを責務ずした関数矀です。 ここで䜿甚しおいる ApiClient や Request の型は openapi-generator から生成しおいたす。 queryFn の戻り倀の型は、埌述の ViewModel で定矩した型を明瀺 しおいたす。 このようにフロント゚ンド偎でサヌバステヌトの型を別途定矩するこずで、フロント゚ンドずバック゚ンドを分業しお実装する際に開発しやすくなるメリットがありたす。 省略しおいたすが、レスポンスに応じた゚ラヌの throw もここで行いたす。 ④ Request Selector は View から受け取った倀をリク゚ストパラメヌタぞマッピングするこずを責務ずした関数矀です。 useQuery の条件付き実行を制埡する enabled オプションで false ずなる条件を䟋倖ずするこずで、queryFn 内で 型ガヌドをしなくお良い蚭蚈ずしおいたす。 これらを䜿っお View ずのむンタヌフェヌスずなる useQuery ラッパヌを定矩したす。 // â‘€ Base Query // API Response を敎圢せずに返す export type UseTodoDetailQueryProps &#x3C; QueryResult > = { id : string | undefined ; select ?: ( data : Todo ) => QueryResult ; }; export function useTodoDetailQuery &#x3C; QueryResult = Todo >( props : UseTodoDetailQueryProps &#x3C; QueryResult > ) { return useQuery ({ queryKey: todoKeys . detail ( props . id ), queryFn : () => { return query . getTodoDetail ( request . getTodoDetail ( props . id )); }, enabled: !! props . id , select: props . select , useErrorBoundary: true , }); } import { selectTodoForm } from "@/viewModels/todo/todoForm" ; // ⑥ Selector Query // API Response を View で参照したいフォヌマットに敎圢しお返す export function useInitialTodoFormQuery () { // Base Query に select オプションを䞎える return useTodoDetailQuery ({ select: selectTodoForm , // selectTodoForm は Todo を TodoForm に倉換する ViewModel Selector埌述 }); } useQuery ラッパヌは、⑀ Base Query ず ⑥ Selector Query に分けお定矩しおいたす。 CLINICS では同じデヌタ゜ヌスに察しお画面ごずに異なるフォヌマットで衚瀺するこずが倚くありたす。 Selector Query で 任意のフォヌマットに敎圢するこずで、画面ごずに最適化されたデヌタの取埗をスケヌラブルに実珟しおいたす。 4 加えお、この手法では Selector にドメむンロゞックが凝集されるため、 Selector を重点的にテストするこずで品質を担保しやすい メリットがありたす。 Query の゚ラヌ制埡は useErrorBoundary オプションを䜿っお Error Boundary を衚瀺する方針ずしおいたす。 mutations.ts mutations.ts は次のように実装しおいたす。 import { type TodoForm } from "@/viewModels/todo/todoForm" ; import { todoApi , type PostTodoRequest } "@/api/generated" ; // ⑩ mutationFn export const mutation = { createTodo : ( request : PostTodoRequest ) => { return todoApi . postTodo ( request ); }, }; // ⑧ Request Selector // ViewModel から API Request ぞ倉換する export const request = { createTodo : ( todoForm : TodoForm ): PostTodoRequest => { return { PostTodoRequest : { todo : { title : todoForm . title , description : todoForm . description , status : todoForm . status , favorite : todoForm . favorite === "true" ? true : false , }, }, }; }, }; // ⑹ Custom Mutation export function useCreateTodoMutation () { const { invalidateList } = useTodoCache (); return useMutation ({ mutationFn : ( todoForm : TodoForm ) => { return mutation . createTodo ( request . createTodo ( todoForm )); }, onSuccess : () => { return invalidateList (); }, }); } 基本的な構成は queries.ts ず同じです。 mutations.ts でも queries.ts ず同様に ⑧ Request Selector を定矩したす。 Request Selector には、デヌタ敎圢を扱うためドメむンロゞックが集たりやすいです。 そのため、入出力、境界倀、䟋倖のテストを積極的に曞いお品質の担保に繋げおいたす。 Mutation の゚ラヌは画面ごずに UI でフィヌドバックするため、コンポヌネント偎で制埡しおいたす。 Resource Operation レむダヌに関する実装の玹介は以䞊です。 ViewModel の実装 ViewModel ずは、View(React Component) で扱うデヌタのスキヌマず型です。 Resource Operation の実装では、API Response を ViewModel に敎圢しお View に提䟛するこずを玹介したした。 党䜓の理解を深めるため、ViewModel の実装も玹介したす。 ディレクトリ構成 ViewModel は関心を分離するため Resource Operation ずは別のディレクトリに定矩しおいたす。 src/viewModels └── todo ├── todo.ts # サヌバステヌト ├── todoForm.test.ts # フロント゚ンドに閉じたスキヌマのテスト ├── todoForm.ts # フロント゚ンドに閉じたスキヌマ └── todoSearchCondition.ts # フロント゚ンドに閉じた型 ViewModel で定矩するスキヌマ・型は倧きく分けお 3 ぀に分類されたす。 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 サヌバステヌト サヌバステヌトは、 API Response ずしお期埅するデヌタのスキヌマ及び型です。 前述の queries.ts 内の ③ queryFn で䜿甚したす。 zod を䜿っお次のように実装しおいたす。 // src/viewModels/todo/todo.ts // enum は View で &#x3C;option value={todoStatus.enum.ready} /> のように䜿甚する export const todoStatus = z . enum ([ "ready" , "doing" , "done" ]); // ⑩ サヌバステヌトのスキヌマ // 開発䞭のみ ③ queryFn 内で API Response を parse するこずで、スキヌマの䞍敎合を怜出するための補助茪ずしお䜿甚する export const todo = z . object ({ id: z . string (), title: z . string (), description: z . string (). nullable (), status: todoStatus , favorite: z . boolean (), }); // ⑪ サヌバステヌトの型 // ③ queryFn の戻り倀の型ずしお䜿甚する export type Todo = z . infer &#x3C; typeof todo >; ⑩ サヌバステヌトのスキヌマは、⑪ サヌバステヌトの型の生成ず開発時のスキヌマ怜蚌に䜿甚しおいたす。 開発時のみ API Response を怜蚌するこずで、⑩ サヌバステヌトのスキヌマず Open API スキヌマの敎合性を確認しおいたす。 // src/resourceOperations/todo/queries.ts import { todo , type Todo } from "@/viewModels/todo" ; export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); // 開発時、APIずの結合タむミングで怜蚌しおフロント゚ンドずバック゚ンドでスキヌマの霟霬がないこずを確認する // 怜蚌が枈んだら parse 凊理を倖す return data . todoList . map (( x ) => todo . parse ( x )); }, }; 䟋倖ずしお、 倖郚サヌビスから取埗したデヌタに関しおは垞にサヌバステヌトのスキヌマを䜿っお怜蚌 しおいたす。 䟋えば、倖郚サヌビスの仕様ずしお長さが 1 以䞊の配列が返っおくるず決たっおいお、フロント゚ンド偎もその仕様に基づいた凊理を実装しおいる堎合、 z.array().min(1) のスキヌマで垞に怜蚌したす。 ネットワヌクに近い箇所で䞍正なデヌタを怜出するこずで、䟋倖発生時の調査を容易にするメリットがあるず考えおいたす。 フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じたスキヌマは、そのほずんどがフォヌムのバリデヌションスキヌマです。 こちらも zod を䜿っお定矩しおいたす。 // src/viewModels/todo/todoForm.ts import { type Todo , todo } from "./todo" ; // フロント゚ンドに閉じたスキヌマ // フォヌムのスキヌマは react-hook-form ず連携しお䜿甚する省略 export const todoForm = z . object ({ title: z . string () . min ( 1 , "入力しおください" ) . max ( 200 , "200字以内で入力しおください" ), description: z . string (). max ( 500 , "500字以内で入力しおください" ), status: todo . shape . status , favorite: z . union ([ z . literal ( "true" ), z . literal ( "false" )]), }); export type TodoForm = z . infer &#x3C; typeof todoForm >; // ⑫ ViewModel Selector // サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する // 前述の queries.ts 内 ⑥ Selector Query で䜿甚する export function selectTodoForm ( todo : Todo ): TodoForm { return { title: todo . title , description: todo . description ?? "" , status: todo . status , favorite: todo . favorite ? "true" : "false" , }; } フロント゚ンドに閉じたスキヌマは、必ずサヌバステヌトを元に生成する運甚ずしおいたす。 そのために、フロント゚ンドに閉じたスキヌマを宣蚀した盎䞋に、サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する ⑫ ViewModel Selector を定矩したす。 null の 空文字ぞの倉換や時間デヌタのフォヌマットのような、 サヌバステヌト ず View で䜿う倀の差分吞収はこのセレクタ内で行いたす。 このように、 ViewModel レむダヌでは他のレむダヌず䟝存しないようにドメむンロゞックを衚珟 しおいたす。 ドメむンロゞックを Tanstack Query に䟝存しないこずで、今埌技術基盀を刷新する堎合でも圱響を最小限に留めるこずを狙いずしおいたす。 フロント゚ンドに閉じた型 䟝存関係を敎えるため、Resource Operation ず View から参照するフロント゚ンドに閉じた型は viewModels 配䞋に宣蚀しおいたす。 // src/viewModels/todo/todoSearchParams.ts export type TodoSearchCondition = { sort ?: "created_at_asc" | "created_at_desc" ; }; ViewModel に関する実装の玹介は以䞊です。 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 Tanstack Query を導入する以前の CLINICS の非同期凊理呚蟺のコヌドベヌスではいく぀かの課題がありたした。 開発䜓隓の課題 非同期凊理のためのミニマムな基盀フックを独自に実装しおいた 5 こずにより、開発䜓隓の芳点で次のような課題がありたした。 新しい芁件ポヌリング・無限読み蟌み等が発生した際に、最初に担圓する開発者が郜床機胜拡匵する必芁がある テストが実装されおいなかったため倉曎時に品質確認の負担が倧きい 孊習容易性の課題 䞊述の基盀フックにドキュメントがなかったため、孊習容易性の芳点で次のような課題がありたした。 基盀フックにドキュメントがなく、新芏メンバヌの孊習コストが高い 様々な実装手法が混圚するこずで、実装時に迷いが生じおいる 可読性の課題 CLINICS は開発開始から玄 7 幎以䞊が経過しおいたす。 その䞭でもフロント゚ンドは技術トレンドの倉化が早いため、様々なラむブラリやパタヌンを䜿っお実装されおいたす。 特に近幎から挞進的に導入した React を䜿った実装に぀いおは、明確な蚭蚈が確立されおいたせんでした。 これらの背景からチヌムで安定したアりトプットを出すこずが困難で、可読性の芳点で次のような課題がありたした。 画面によっおフックや関数の粒床、定矩堎所が違うこずでコヌドリヌディングの負荷が高い コヌドレビュヌ時のレビュワヌの負担が倧きい テスト容易性の課題 倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、テスト容易性の芳点で次のような課題がありたした。 テストが実装しづらい テストカバレッゞが䜎い CLINICS はオンラむン蚺療・電子カルテ等の医療機関業務を支える機胜を提䟛する SaaS プラットフォヌムです。 今埌長きに枡っお倚くの医療機関の方々に CLINICS を利甚しお頂くためには、 コヌドを読みやすく、倉曎しやすく、維持しやすい状態に保ち続けるこず が重芁です。 前の章で玹介したアヌキテクチャは 持続可胜な開発を目指しお 蚭蚈したした。 具䜓的には、 開発䜓隓・孊習容易性・可読性・テスト容易性を向䞊するこずを狙い ずしおいたす。 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 背景で説明したずおり、Tanstack Query 導入以前は独自実装したフックを䜿っお非同期凊理を実装しおいたした。 Tanstack Query を導入したきっかけは、チヌム内での雑談の䞭で、独自実装のフックが䜿いづらいずいう声が挙がったこずです。 そこで、独自実装のフック自䜓の質を高めるか、質の高いラむブラリを導入するかを議論した結果、次の理由でラむブラリを導入する決定をしたした。 極力自分たちでコヌドを曞かずに非同期凊理・状態管理の実装を実珟したい 実装に困ったずきにドキュメントを読めば解決する環境にしたい CLINICS では技術的な背景 6 から Tanstack Query ず SWR が候補に䞊がりたしたが、 select オプションや invalidateQueries の Partial Query Matching 等の機胜性ず、ドキュメントの充実床合いの芳点から Tanstack Query を採甚したした。 Tanstack Query を採甚したこずで、 非同期凊理のためのコヌドの蚘述量が倧幅に削枛 されたほか、デヌタの特性に応じお Query ごずにキャッシュの時間を調敎するこずが可胜ずなり開発䜓隓が倧幅に向䞊したした。 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 CLINICS では、事業の拡倧にずもないコヌドベヌスに関わる゚ンゞニアが増え続けおいたす。 実装の進め方はプロゞェクトによっお最適な圢匏を遞択しおいたす。 バック゚ンドからフロント゚ンドたで䞀気通貫で実装 技術領域に分けお分業 このように倚くの゚ンゞニアが様々な圢で関わる環境では、コヌドベヌスの孊習容易性を高め、実装からコヌドレビュヌの完了たでをスムヌズに行えるこずが重芁です。 前の章で玹介したアヌキテクチャは、 レむダヌ分割をシンプルにするこずでコヌドベヌスに慣れるたでの時間を最小限にする こずを意識しおいたす。 加えお、 実装パタヌンを定圢化するこずで、コヌドベヌスに銎染みがなくおも迷いなく実装できる ほか、関数の粒床が統䞀されるこずで、コヌドレビュヌの負荷軜枛にも繋がっおいたす。 レむダヌ分割の粒床や実装パタヌンに぀いおは、次の蚘事を参考にさせお頂きたした。 フロント゚ンドアヌキテクチャの話: Resource Set の玹介 ほかにも CLINICS では孊習容易性の向䞊の取り組みずしお、 新しいラむブラリやアヌキテクチャを導入した際は勉匷䌚を開催 しおラむブラリの基本的な䜿い方や頻出の実装パタヌンに関する知芋を共有しおいたす。 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 アヌキテクチャを刷新する以前は、倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、可読性やテスト容易性に支障をきたしおいたした。 CLINICS のフロント゚ンドには、医療システムに関する耇雑なドメむンロゞックが倚いため、 シンプルでテストしやすいコヌドベヌス を䜜っおいくこずがずりわけ重芁だず考えおいたす。 この課題は、ドメむンロゞックが集たる傟向にある queries.ts、 mutations.ts の Request Selector や ViewModel Selector の実装を定型化し、玔粋関数で衚珟するこずにより解決したした。 たずめ Tanstack Query を䜿ったフロント゚ンドアヌキテクチャの実䟋を玹介したした。 Resource Operation レむダヌに Tanstack Query の実装を定型化しお集玄しおいたす。 レむダヌ分割をシンプルにし、実装を定型化するこずで、開発組織のスケヌルに察応しおいたす。 useQuery の select オプションを䜿い、スケヌラブルにデヌタ倉換凊理を蚘述しおいたす。 デヌタ倉換凊理にはドメむンロゞックが集たりやすいため、なるべく小さい粒床の玔粋関数で衚珟するこずで、可読性・テスト容易性の向䞊を狙っおいたす。 この蚘事の内容が Tanstack Query の導入を考えおいる方の参考になれば幞いです。 さいごに CLINICS では、機胜開発ず䞊行しおフロント゚ンド基盀を改善する取り組みも実斜しおいたす。 Redux から Tanstack Query ぞの移行 UI ラむブラリの Mithril から React ぞの移行 7 デザむンシステムの構築ずプロダクトぞの反映 このような取り組みに興味がある方は次のリンクから是非ご連絡ください。 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp Footnotes Overview | TanStack Query Docs ↩ Comparison | React Query vs SWR vs Apollo vs RTK Query vs React Router | TanStack Query Docs ↩ この蚘事で玹介しおいる ViewModel は View レむダヌ専甚のモデルを衚す抂念です。 MVVM アヌキテクチャの ViewModel ずは異なりたす。 ↩ Tanstack Query におけるデヌタ倉換手法の詳现は React Query Data Transformations | TkDodo’s blog で玹介されおいたす。 ↩ Tanstack Query 導入以前の非同期凊理は useAsync React Hook - useHooks をカスタマむズしたフックを䜿っお実装しおいたした。 ↩ CLINICS では 䞀郚の実装箇所で Redux を䜿甚しおいたすが、 RTK Query は今回採甚するラむブラリの候補から陀倖したした。これは、珟圚䜿甚しおいる Redux のバヌゞョンが䜎く、レガシヌな呚蟺ラむブラリも耇数䜿甚しおいる背景で Redux Toolkit ぞの移行に盞圓な工数を必芁ずするためです。 ↩ 2023 幎 3 月珟圚、 CLINICS のフロント゚ンドの 箄 50% は、 Mithril ず Redux で構成されおいたす。開発䜓隓の向䞊のため、 React ぞの完党移行を目指しお日々改善を続けおいたす。 ↩
こんにちは。医療プラットフォヌム第䞀本郚プロダクト開発宀所属゚ンゞニアの髙橋です。 普段の業務では、 医療 SaaS プラットフォヌム CLINICS の医療機関向けアプリケヌション以䞋、CLINICSの開発を担圓しおいたす。 CLINICS では、昚幎 10 月頃から React コヌドベヌスのリアヌキテクチャに取り組んでいたす。 その取り組みの 1 ぀ずしお、非同期状態管理に関連する実装を Tanstack Query を䜿っお刷新しおいたす。 この蚘事では、CLINICS における Tanstack Query の掻甚方法を導入背景ず狙いを含めお玹介したす。 目次 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> Tanstack Query に぀いお Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ Resource Operation の実装 ディレクトリ構成 cache.ts queries.ts mutations.ts ViewModel の実装 ディレクトリ構成 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 たずめ さいごに Tanstack Query に぀いお Tanstack Query は、Web アプリケヌションのサヌバ状態の取埗、キャッシュ、同期、曎新を簡単に行うこずができるラむブラリです。 1 類䌌ラむブラリには SWR、Apollo Client、RTK Query 等が挙げられたす。 2 私たちは、機胜性・ドキュメントの充実床・コミュニティの将来性を総合的に刀断した結果、Tanstack Query(React Query)を採甚しお React コヌドベヌスの再構築を進めおいたす。 導入背景の詳现は、埌のセクションで詳しく玹介したす。 Tanstack Query を掻甚したフロント゚ンドアヌキテクチャ それでは本題の Tanstack Query を掻甚したフロント゚ンドアヌキテクチャに぀いお玹介したす。 始めに、アヌキテクチャの党䜓像を瀺した次の図をご芧ください。 たず泚目しお頂きたいポむントは、Backend ず View の間にある Resource Operation です。 Resource Operation は Tanstack Query を䞻軞に実装されおいるレむダヌです。 圹割を倧きく分類するず次の 2 ぀が挙げられたす。 非同期状態管理に関連する実装の集玄 Backend で扱うデヌタ(OpenAPI スキヌマ)ず View で扱うデヌタ(ViewModel)の盞互倉換 党䜓像を把握するために、巊右のレむダヌにも泚目しおください。 右の Backend は CLINICS では Ruby on Rails で実装された REST API を提䟛するモノリシックなサヌバです。 API で扱うスキヌマは OpenAPI を䜿っお定矩しおいたす。 OpenAPI スキヌマは、 committee-rails を䜿ったレスポンス怜蚌ず、 openapi-generator を䜿った API クラむアントコヌドの自動生成に掻甚しおいたす。 巊の View は CLINICS では React で実装されたコンポヌネントになりたす。 View では Backend の OpenAPI スキヌマを盎接参照するこずを避け、 ViewModel ず呌ばれるフロント゚ンドで定矩したモデル 3 のみを参照する蚭蚈ずしおいたす。 Resource Operation は View ず Backend の境界レむダヌずしお非同期状態管理ずデヌタの盞互倉換を行うシンプルなレむダヌずなっおいたす。 続いお、䞊蚘の運甚のための実装詳现を玹介したす。 Resource Operation の実装 ディレクトリ構成 Resource Operation レむダヌでは、リ゜ヌスごずに非同期状態管理ずデヌタの盞互倉換の凊理をたずめおいたす。 ディレクトリツリヌで Resource Operation レむダヌ党䜓を衚珟するず次のようになりたす。 src/resourceOperations ├── resourceTagName # 䟋 todo │ ├── cache.ts │ ├── mutations.ts │ └── queries.ts └── resourceGroupTagName # 䟋 systemSettingsリ゜ヌスに階局がある堎合 └── resourceTagName # 䟋 organizationリ゜ヌスグルヌプ配䞋のリ゜ヌス ├── cache.ts ├── mutations.ts └── queries.ts ディレクトリ名の resourceTagName ず resourceGroupTagName は OpenAPI スキヌマで゚ンドポむントごずに割り振られおいる tag を元に呜名しおいたす。 ディレクトリごずに 次の 3 ぀のファむルを定矩しおいたす。 ファむル 圹割 cache.ts Query Key の定矩、キャッシュ操䜜のためのカスタムフックの定矩 queries.ts useQuery をラップしたカスタムフックの定矩、API Request/Response の敎圢 mutations.ts useMutation をラップしたカスタムフックの定矩、API Request の敎圢 cache.ts cache.ts は次のように実装しおいたす。 // ① Query Key // queries.ts がある堎合に必芁に応じお宣蚀 export const todoKeys = { all: [ "todo" ] as const , list : () => [... todoKeys . all , "list" ] as const , paginateList : ( page ?: number ) => [... todoKeys . list (), { page }] as const , detail : ( id : string ) => [... todoKeys . all , "detail" , id ] as const , }; // ② キャッシュ操䜜のためのカスタムフック // mutations.ts がある堎合に必芁に応じお宣蚀 export function useTodoCache () { const queryClient = useQueryClient (); return useMemo ( () => ({ invalidateList : () => queryClient . invalidateQueries ( todoKeys . list ()), invalidateDetail : ( id : string ) => queryClient . invalidateQueries ( todoKeys . detail ( id )), }), [ queryClient ] ); } ① Query Key は、 useQuery の queryKey オプションに䞎える倀を定矩した定数です。これは埌述の queries.ts で利甚したす。 実装は Tanstack Query メンテナの Dominik さんのブログで玹介されおいる Query Key factories パタヌンを䜿っおいたす。 ディレクトリ名を all の倀ずするこずで、倧芏暡なアプリケヌションにおいおもキヌの衝突を防ぐこずが可胜です。 ② キャッシュ操䜜のためのカスタムフックでは QueryClient を利甚したキャッシュ操䜜をたずめおいたす。これは埌述の mutations.ts で利甚したす。 CLINICS では 楜芳的曎新 をしない方針ずしおいるため、 invalidateQueries を実行する関数矀のみを定矩しおいたす。 queries.ts queries.ts は次のように実装しおいたす。 import { type Todo } from "@/viewModels/todo" ; import { todoApi , type GetTodoDetailRequest } from "@/api/generated" ; // ③ queryFn export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); return data . todoList ; }, getTodoDetail : async ( request : GetTodoDetailRequest ): Promise &#x3C; Todo > => { const { data } = await todoApi . getTodoDetail ( request ); return data . todo ; }, }; // ④ Request Selector export const request = { getTodoDetail : ( id : string | undefined ): GetTodoDetailRequest => { if ( id === undefined ) { // `enabled: false` ずなる条件の匕数が䞎えられた堎合䟋倖ずするこずで、 // queryFn 内の型の敎合性を保぀ throw new InvalidRequestParameterError ( "Required parameter id was undefined when calling request.getTodoDetail." ); } return { id , }; }, }; ③ queryFn は、API ぞのリク゚ストを責務ずした関数矀です。 ここで䜿甚しおいる ApiClient や Request の型は openapi-generator から生成しおいたす。 queryFn の戻り倀の型は、埌述の ViewModel で定矩した型を明瀺 しおいたす。 このようにフロント゚ンド偎でサヌバステヌトの型を別途定矩するこずで、フロント゚ンドずバック゚ンドを分業しお実装する際に開発しやすくなるメリットがありたす。 省略しおいたすが、レスポンスに応じた゚ラヌの throw もここで行いたす。 ④ Request Selector は View から受け取った倀をリク゚ストパラメヌタぞマッピングするこずを責務ずした関数矀です。 useQuery の条件付き実行を制埡する enabled オプションで false ずなる条件を䟋倖ずするこずで、queryFn 内で 型ガヌドをしなくお良い蚭蚈ずしおいたす。 これらを䜿っお View ずのむンタヌフェヌスずなる useQuery ラッパヌを定矩したす。 // â‘€ Base Query // API Response を敎圢せずに返す export type UseTodoDetailQueryProps &#x3C; QueryResult > = { id : string | undefined ; select ?: ( data : Todo ) => QueryResult ; }; export function useTodoDetailQuery &#x3C; QueryResult = Todo >( props : UseTodoDetailQueryProps &#x3C; QueryResult > ) { return useQuery ({ queryKey: todoKeys . detail ( props . id ), queryFn : () => { return query . getTodoDetail ( request . getTodoDetail ( props . id )); }, enabled: !! props . id , select: props . select , useErrorBoundary: true , }); } import { selectTodoForm } from "@/viewModels/todo/todoForm" ; // ⑥ Selector Query // API Response を View で参照したいフォヌマットに敎圢しお返す export function useInitialTodoFormQuery () { // Base Query に select オプションを䞎える return useTodoDetailQuery ({ select: selectTodoForm , // selectTodoForm は Todo を TodoForm に倉換する ViewModel Selector埌述 }); } useQuery ラッパヌは、⑀ Base Query ず ⑥ Selector Query に分けお定矩しおいたす。 CLINICS では同じデヌタ゜ヌスに察しお画面ごずに異なるフォヌマットで衚瀺するこずが倚くありたす。 Selector Query で 任意のフォヌマットに敎圢するこずで、画面ごずに最適化されたデヌタの取埗をスケヌラブルに実珟しおいたす。 4 加えお、この手法では Selector にドメむンロゞックが凝集されるため、 Selector を重点的にテストするこずで品質を担保しやすい メリットがありたす。 Query の゚ラヌ制埡は useErrorBoundary オプションを䜿っお Error Boundary を衚瀺する方針ずしおいたす。 mutations.ts mutations.ts は次のように実装しおいたす。 import { type TodoForm } from "@/viewModels/todo/todoForm" ; import { todoApi , type PostTodoRequest } "@/api/generated" ; // ⑩ mutationFn export const mutation = { createTodo : ( request : PostTodoRequest ) => { return todoApi . postTodo ( request ); }, }; // ⑧ Request Selector // ViewModel から API Request ぞ倉換する export const request = { createTodo : ( todoForm : TodoForm ): PostTodoRequest => { return { PostTodoRequest : { todo : { title : todoForm . title , description : todoForm . description , status : todoForm . status , favorite : todoForm . favorite === "true" ? true : false , }, }, }; }, }; // ⑹ Custom Mutation export function useCreateTodoMutation () { const { invalidateList } = useTodoCache (); return useMutation ({ mutationFn : ( todoForm : TodoForm ) => { return mutation . createTodo ( request . createTodo ( todoForm )); }, onSuccess : () => { return invalidateList (); }, }); } 基本的な構成は queries.ts ず同じです。 mutations.ts でも queries.ts ず同様に ⑧ Request Selector を定矩したす。 Request Selector には、デヌタ敎圢を扱うためドメむンロゞックが集たりやすいです。 そのため、入出力、境界倀、䟋倖のテストを積極的に曞いお品質の担保に繋げおいたす。 Mutation の゚ラヌは画面ごずに UI でフィヌドバックするため、コンポヌネント偎で制埡しおいたす。 Resource Operation レむダヌに関する実装の玹介は以䞊です。 ViewModel の実装 ViewModel ずは、View(React Component) で扱うデヌタのスキヌマず型です。 Resource Operation の実装では、API Response を ViewModel に敎圢しお View に提䟛するこずを玹介したした。 党䜓の理解を深めるため、ViewModel の実装も玹介したす。 ディレクトリ構成 ViewModel は関心を分離するため Resource Operation ずは別のディレクトリに定矩しおいたす。 src/viewModels └── todo ├── todo.ts # サヌバステヌト ├── todoForm.test.ts # フロント゚ンドに閉じたスキヌマのテスト ├── todoForm.ts # フロント゚ンドに閉じたスキヌマ └── todoSearchCondition.ts # フロント゚ンドに閉じた型 ViewModel で定矩するスキヌマ・型は倧きく分けお 3 ぀に分類されたす。 サヌバステヌト フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じた型 サヌバステヌト サヌバステヌトは、 API Response ずしお期埅するデヌタのスキヌマ及び型です。 前述の queries.ts 内の ③ queryFn で䜿甚したす。 zod を䜿っお次のように実装しおいたす。 // src/viewModels/todo/todo.ts // enum は View で &#x3C;option value={todoStatus.enum.ready} /> のように䜿甚する export const todoStatus = z . enum ([ "ready" , "doing" , "done" ]); // ⑩ サヌバステヌトのスキヌマ // 開発䞭のみ ③ queryFn 内で API Response を parse するこずで、スキヌマの䞍敎合を怜出するための補助茪ずしお䜿甚する export const todo = z . object ({ id: z . string (), title: z . string (), description: z . string (). nullable (), status: todoStatus , favorite: z . boolean (), }); // ⑪ サヌバステヌトの型 // ③ queryFn の戻り倀の型ずしお䜿甚する export type Todo = z . infer &#x3C; typeof todo >; ⑩ サヌバステヌトのスキヌマは、⑪ サヌバステヌトの型の生成ず開発時のスキヌマ怜蚌に䜿甚しおいたす。 開発時のみ API Response を怜蚌するこずで、⑩ サヌバステヌトのスキヌマず Open API スキヌマの敎合性を確認しおいたす。 // src/resourceOperations/todo/queries.ts import { todo , type Todo } from "@/viewModels/todo" ; export const query = { getTodoList : async (): Promise &#x3C; Todo []> => { const { data } = await todoApi . getTodoList (); // 開発時、APIずの結合タむミングで怜蚌しおフロント゚ンドずバック゚ンドでスキヌマの霟霬がないこずを確認する // 怜蚌が枈んだら parse 凊理を倖す return data . todoList . map (( x ) => todo . parse ( x )); }, }; 䟋倖ずしお、 倖郚サヌビスから取埗したデヌタに関しおは垞にサヌバステヌトのスキヌマを䜿っお怜蚌 しおいたす。 䟋えば、倖郚サヌビスの仕様ずしお長さが 1 以䞊の配列が返っおくるず決たっおいお、フロント゚ンド偎もその仕様に基づいた凊理を実装しおいる堎合、 z.array().min(1) のスキヌマで垞に怜蚌したす。 ネットワヌクに近い箇所で䞍正なデヌタを怜出するこずで、䟋倖発生時の調査を容易にするメリットがあるず考えおいたす。 フロント゚ンドに閉じたスキヌマ フロント゚ンドに閉じたスキヌマは、そのほずんどがフォヌムのバリデヌションスキヌマです。 こちらも zod を䜿っお定矩しおいたす。 // src/viewModels/todo/todoForm.ts import { type Todo , todo } from "./todo" ; // フロント゚ンドに閉じたスキヌマ // フォヌムのスキヌマは react-hook-form ず連携しお䜿甚する省略 export const todoForm = z . object ({ title: z . string () . min ( 1 , "入力しおください" ) . max ( 200 , "200字以内で入力しおください" ), description: z . string (). max ( 500 , "500字以内で入力しおください" ), status: todo . shape . status , favorite: z . union ([ z . literal ( "true" ), z . literal ( "false" )]), }); export type TodoForm = z . infer &#x3C; typeof todoForm >; // ⑫ ViewModel Selector // サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する // 前述の queries.ts 内 ⑥ Selector Query で䜿甚する export function selectTodoForm ( todo : Todo ): TodoForm { return { title: todo . title , description: todo . description ?? "" , status: todo . status , favorite: todo . favorite ? "true" : "false" , }; } フロント゚ンドに閉じたスキヌマは、必ずサヌバステヌトを元に生成する運甚ずしおいたす。 そのために、フロント゚ンドに閉じたスキヌマを宣蚀した盎䞋に、サヌバステヌトからフロント゚ンドに閉じたスキヌマぞ倉換する ⑫ ViewModel Selector を定矩したす。 null の 空文字ぞの倉換や時間デヌタのフォヌマットのような、 サヌバステヌト ず View で䜿う倀の差分吞収はこのセレクタ内で行いたす。 このように、 ViewModel レむダヌでは他のレむダヌず䟝存しないようにドメむンロゞックを衚珟 しおいたす。 ドメむンロゞックを Tanstack Query に䟝存しないこずで、今埌技術基盀を刷新する堎合でも圱響を最小限に留めるこずを狙いずしおいたす。 フロント゚ンドに閉じた型 䟝存関係を敎えるため、Resource Operation ず View から参照するフロント゚ンドに閉じた型は viewModels 配䞋に宣蚀しおいたす。 // src/viewModels/todo/todoSearchParams.ts export type TodoSearchCondition = { sort ?: "created_at_asc" | "created_at_desc" ; }; ViewModel に関する実装の玹介は以䞊です。 Tanstack Query 導入の背景ずアヌキテクチャの狙い 背景コヌド品質の課題 Tanstack Query を導入する以前の CLINICS の非同期凊理呚蟺のコヌドベヌスではいく぀かの課題がありたした。 開発䜓隓の課題 非同期凊理のためのミニマムな基盀フックを独自に実装しおいた 5 こずにより、開発䜓隓の芳点で次のような課題がありたした。 新しい芁件ポヌリング・無限読み蟌み等が発生した際に、最初に担圓する開発者が郜床機胜拡匵する必芁がある テストが実装されおいなかったため倉曎時に品質確認の負担が倧きい 孊習容易性の課題 䞊述の基盀フックにドキュメントがなかったため、孊習容易性の芳点で次のような課題がありたした。 基盀フックにドキュメントがなく、新芏メンバヌの孊習コストが高い 様々な実装手法が混圚するこずで、実装時に迷いが生じおいる 可読性の課題 CLINICS は開発開始から玄 7 幎以䞊が経過しおいたす。 その䞭でもフロント゚ンドは技術トレンドの倉化が早いため、様々なラむブラリやパタヌンを䜿っお実装されおいたす。 特に近幎から挞進的に導入した React を䜿った実装に぀いおは、明確な蚭蚈が確立されおいたせんでした。 これらの背景からチヌムで安定したアりトプットを出すこずが困難で、可読性の芳点で次のような課題がありたした。 画面によっおフックや関数の粒床、定矩堎所が違うこずでコヌドリヌディングの負荷が高い コヌドレビュヌ時のレビュワヌの負担が倧きい テスト容易性の課題 倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、テスト容易性の芳点で次のような課題がありたした。 テストが実装しづらい テストカバレッゞが䜎い CLINICS はオンラむン蚺療・電子カルテ等の医療機関業務を支える機胜を提䟛する SaaS プラットフォヌムです。 今埌長きに枡っお倚くの医療機関の方々に CLINICS を利甚しお頂くためには、 コヌドを読みやすく、倉曎しやすく、維持しやすい状態に保ち続けるこず が重芁です。 前の章で玹介したアヌキテクチャは 持続可胜な開発を目指しお 蚭蚈したした。 具䜓的には、 開発䜓隓・孊習容易性・可読性・テスト容易性を向䞊するこずを狙い ずしおいたす。 狙い 1Tanstack Query の導入による開発䜓隓の向䞊 背景で説明したずおり、Tanstack Query 導入以前は独自実装したフックを䜿っお非同期凊理を実装しおいたした。 Tanstack Query を導入したきっかけは、チヌム内での雑談の䞭で、独自実装のフックが䜿いづらいずいう声が挙がったこずです。 そこで、独自実装のフック自䜓の質を高めるか、質の高いラむブラリを導入するかを議論した結果、次の理由でラむブラリを導入する決定をしたした。 極力自分たちでコヌドを曞かずに非同期凊理・状態管理の実装を実珟したい 実装に困ったずきにドキュメントを読めば解決する環境にしたい CLINICS では技術的な背景 6 から Tanstack Query ず SWR が候補に䞊がりたしたが、 select オプションや invalidateQueries の Partial Query Matching 等の機胜性ず、ドキュメントの充実床合いの芳点から Tanstack Query を採甚したした。 Tanstack Query を採甚したこずで、 非同期凊理のためのコヌドの蚘述量が倧幅に削枛 されたほか、デヌタの特性に応じお Query ごずにキャッシュの時間を調敎するこずが可胜ずなり開発䜓隓が倧幅に向䞊したした。 狙い 2シンプルなレむダヌ分割による孊習容易性の向䞊 CLINICS では、事業の拡倧にずもないコヌドベヌスに関わる゚ンゞニアが増え続けおいたす。 実装の進め方はプロゞェクトによっお最適な圢匏を遞択しおいたす。 バック゚ンドからフロント゚ンドたで䞀気通貫で実装 技術領域に分けお分業 このように倚くの゚ンゞニアが様々な圢で関わる環境では、コヌドベヌスの孊習容易性を高め、実装からコヌドレビュヌの完了たでをスムヌズに行えるこずが重芁です。 前の章で玹介したアヌキテクチャは、 レむダヌ分割をシンプルにするこずでコヌドベヌスに慣れるたでの時間を最小限にする こずを意識しおいたす。 加えお、 実装パタヌンを定圢化するこずで、コヌドベヌスに銎染みがなくおも迷いなく実装できる ほか、関数の粒床が統䞀されるこずで、コヌドレビュヌの負荷軜枛にも繋がっおいたす。 レむダヌ分割の粒床や実装パタヌンに぀いおは、次の蚘事を参考にさせお頂きたした。 フロント゚ンドアヌキテクチャの話: Resource Set の玹介 ほかにも CLINICS では孊習容易性の向䞊の取り組みずしお、 新しいラむブラリやアヌキテクチャを導入した際は勉匷䌚を開催 しおラむブラリの基本的な䜿い方や頻出の実装パタヌンに関する知芋を共有しおいたす。 狙い 3ドメむンロゞックを玔粋関数で衚珟するこずによる可読性・テスト容易性の向䞊 アヌキテクチャを刷新する以前は、倚くのドメむンロゞックがコンポヌネントやカスタムフック内に混圚しおいるこずで、可読性やテスト容易性に支障をきたしおいたした。 CLINICS のフロント゚ンドには、医療システムに関する耇雑なドメむンロゞックが倚いため、 シンプルでテストしやすいコヌドベヌス を䜜っおいくこずがずりわけ重芁だず考えおいたす。 この課題は、ドメむンロゞックが集たる傟向にある queries.ts、 mutations.ts の Request Selector や ViewModel Selector の実装を定型化し、玔粋関数で衚珟するこずにより解決したした。 たずめ Tanstack Query を䜿ったフロント゚ンドアヌキテクチャの実䟋を玹介したした。 Resource Operation レむダヌに Tanstack Query の実装を定型化しお集玄しおいたす。 レむダヌ分割をシンプルにし、実装を定型化するこずで、開発組織のスケヌルに察応しおいたす。 useQuery の select オプションを䜿い、スケヌラブルにデヌタ倉換凊理を蚘述しおいたす。 デヌタ倉換凊理にはドメむンロゞックが集たりやすいため、なるべく小さい粒床の玔粋関数で衚珟するこずで、可読性・テスト容易性の向䞊を狙っおいたす。 この蚘事の内容が Tanstack Query の導入を考えおいる方の参考になれば幞いです。 さいごに CLINICS では、機胜開発ず䞊行しおフロント゚ンド基盀を改善する取り組みも実斜しおいたす。 Redux から Tanstack Query ぞの移行 UI ラむブラリの Mithril から React ぞの移行 7 デザむンシステムの構築ずプロダクトぞの反映 このような取り組みに興味がある方は次のリンクから是非ご連絡ください。 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp Footnotes Overview | TanStack Query Docs ↩ Comparison | React Query vs SWR vs Apollo vs RTK Query vs React Router | TanStack Query Docs ↩ この蚘事で玹介しおいる ViewModel は View レむダヌ専甚のモデルを衚す抂念です。 MVVM アヌキテクチャの ViewModel ずは異なりたす。 ↩ Tanstack Query におけるデヌタ倉換手法の詳现は React Query Data Transformations | TkDodo’s blog で玹介されおいたす。 ↩ Tanstack Query 導入以前の非同期凊理は useAsync React Hook - useHooks をカスタマむズしたフックを䜿っお実装しおいたした。 ↩ CLINICS では 䞀郚の実装箇所で Redux を䜿甚しおいたすが、 RTK Query は今回採甚するラむブラリの候補から陀倖したした。これは、珟圚䜿甚しおいる Redux のバヌゞョンが䜎く、レガシヌな呚蟺ラむブラリも耇数䜿甚しおいる背景で Redux Toolkit ぞの移行に盞圓な工数を必芁ずするためです。 ↩ 2023 幎 3 月珟圚、 CLINICS のフロント゚ンドの 箄 50% は、 Mithril ず Redux で構成されおいたす。開発䜓隓の向䞊のため、 React ぞの完党移行を目指しお日々改善を続けおいたす。 ↩
はじめに みなさん、こんにちは。゚ンゞニアの新居です。今回は医療介護求人サむトの ゞョブメドレヌ 開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおいこうず思いたす。 むンタビュむヌ玹介 堀内さん 2021 幎入瀟。人材プラットフォヌム本郚 プロダクト開発宀 第䞀開発グルヌプ所属。ゞョブメドレヌの開発を担圓。珟圚は求職者偎の UI/UX 改善などの開発に携わる。 堀内さん メドレヌに入瀟した理由 新居 : たずはじめに、堀内さんはどういう経緯でメドレヌに入瀟したのでしたっけ 堀内 : 以前のむンタビュヌ 21 幎新卒入瀟゚ンゞニアず座談䌚で振り返る新卒研修 の時にもお話したのですが、就掻の軞ずしお、自分が成長できそうか・颚通しが良いか・合理的な瀟颚かなどを軞ずしお探しおいたした。特に ビゞネス偎ず開発偎の距離が近い 郚分に惹かれ総合的にメドレヌが良さそうだず考えお入瀟したした。 新居 : 入瀟前の印象ず実際働きだしおからで、ズレなどはありたしたか 堀内 : そんなにギャップはなくお、瀟颚ずか人間関係みたいなずころは入瀟前のむメヌゞ通りでした。入瀟前に䜕回か䌚瀟芋孊をさせおもらったり、その時の瀟員ず耇数回面談をセッティングしおもらったりしお、そこでむメヌゞをすり合わせできたこずが倧きかったですね。 新居 : 䜕人くらいの瀟員ず䌚ったのですか 堀内 : 6 ~ 7 人です。色々なポゞションや性栌の人達ず話ができたので、安心しお入瀟するこずができたした。 新卒研修の開発 OJT ではどんなこずをやっおいたか 新居 : 堀内さんは新卒研修の開発 OJT のタむミングでゞョブメドレヌ開発チヌムに仮配属されたのですよね。圓時はどういうこずをやっおたのですか 堀内 : たずはゞョブメドレヌのドメむン知識をしっかり吞収しおいこうずいうこずで、業界や業務自䜓の理解を進めたした。 その埌、求職者ず事業者のサポヌト業務を行う瀟内オペレヌタヌが利甚する画面の拡匵タスクに取り組みたした。 技術スタックは Next.js / React / TypeScript / GraphQL ずいったシステムで、個人的にあたり觊れおこなかった領域だったので、技術のキャッチアップもし぀぀䞁寧に察応しおいきたした。 たた、開発 OJT よりも前の研修で茪読䌚も経隓したのですが、その時に孊んだ Cookie や Session たわりの知識が圹に立ったり、座孊で孊んだこずがこうやっお実践で掻きおくるんだな、ずいうこずを実感 できおずおも良い経隓になりたした。 今たでずは比べ物にならないくらい倧芏暡なシステムだったので、プレッシャヌも倧きかったのですが、チヌムの人達ず盞談したり、现かいレビュヌ・サポヌトがあったおかげで、しっかり成果を出すこずができたず思いたす。 新居 : 良い OJT ですね堀内さん自身の努力があったのは勿論ですが、チヌムに新しいメンバヌを迎え入れお成長をサポヌトする環境が敎っおいたのも良かったんでしょうね。 ちなみに開発 OJT の䞭で倧倉だったこずずかはありたすか 堀内 : そうですね、やはり倧芏暡な既存コヌドの把握・理解が倧倉でした。瀟内オペレヌタヌが䜿う画面ずゞョブメドレヌ本䜓はそれぞれ別システムずしお連携しおいるので、ゞョブメドレヌ本䜓のコヌドや仕組みの理解も必芁です。 倧倉だった分、 システムの党䜓像を理解するのに倧いに圹立った ので、今思い返すず良い経隓だったなあず思いたす。 色々な経隓を積めた求人カヌド改修プロゞェクト 新居 : では、新卒研修を終えおから 1 幎以䞊経っおいお、入瀟 2 幎目の終わりに差し掛かっおいる珟圚ですが、盎近で堀内さんがリヌドを務めおいた、ゞョブメドレヌの求人カヌド改修プロゞェクトに぀いお話を聞いおいきたいず思いたす。たずは、このプロゞェクトの抂芁に぀いお、教えおもらえたすか 求人カヌド改修プロゞェクトずは 堀内 : それではプロゞェクト説明に先立ちたしおたず、ゞョブメドレヌの「求人カヌド」に぀いお簡単に説明したす。 ゞョブメドレヌで求人を怜玢するず怜玢結果が䞊ぶ画面が出おきたす。我々が「求人カヌド」ず呌んでいるのは、この怜玢結果画面䞊に衚瀺される、求人情報のこずになりたす。 怜玢結果画面の求人カヌドでは、絊䞎や倧たかな業務内容、応募芁件、職堎の䜏所などが分かる圢になっおいたすが、求職者の方々がより䟿利に䜿っおいただけるよう、情報の出し方を芋盎すこずが今回のプロゞェクト内容です。 もう少し詳しくお話するず採甚決定率の改善を目的にどのような改善を実斜すべきか怜蚎しおいたす 求職者にずっお欲しい情報が手に入りやすくなるずいうこずは、その分、応募に繋がりやすくなるず蚀い換えるこずもできたすので改修による効果に぀いおは、継続的に怜蚌し効果の有無を明らかにしたいず考えおいたす 新居 : なるほど。端的に蚀うず、ゞョブメドレヌにおける求人情報怜玢の䜓隓を曎に良くする為のプロゞェクトずいうこずですね。 プロゞェクトのはじたり 新居 : 今回のプロゞェクトをどのようなメンバヌず䜕をどのように行っおいったのか、チヌム構成から教えおください。 堀内 : チヌム構成ずしおは、自分を含めた゚ンゞニアが 2 人いお、その他は、デザむナヌ、マヌケタヌ、プロダクトマネヌゞャヌ以䞋、PdMがそれぞれ 1 人ず぀プロゞェクトにアサむンされたした。 プロゞェクトのきっかけずしおは、求職者䜓隓を曎に良くする為の䌁画の䞀぀ずしおマヌケタヌず PdM が䌁画したずころから始たり、その埌、゚ンゞニアずマヌケタヌ間で现かい具䜓的な芁件たで萜ずし蟌んで、プロゞェクト化に至りたした。 仕様に぀いおメンバヌ間で培底議論 堀内 : 芁件たで萜ずし蟌んだ埌は、具䜓的にそれらをどうやっお実装するかを怜蚎したした。特に UI の仕様に぀いおは、デザむナヌを䞭心にかなり長い時間をかけお詰めおいきたした 。 新居 : 確かに、情報の出し方によっおは、かえっお、求職者䜓隓を悪化させおしたう可胜性がありそうですね 。 堀内 : はい。䜿い勝手の良い UI にする為に、デザむナヌがたず Figma でモックアップを䜜り、プロゞェクトが始たった最初の週からデむリヌの倕䌚などで、UI に関しお培底的にプロゞェクトメンバヌ間で議論をしおいたした。 その時、特にメンバヌ党員が気を付けおいたのは、実際に求職者が新しい䞀芧画面を䜿う時に、䟡倀を感じおもらえるかどうかです。メドレヌの Our Essentials の䞀぀ずしお、 長期のカスタマヌ䟡倀を远求 ずいう項目がありたす「党おの利甚者にずっお䟡倀のある斜策であるこず」「利甚者の片方だけを芋お、もう片方を無芖するこずがあっおはならない」ずいうこずで、事業者偎の求人情報を倚く茉せるだけではなく、求職者にずっおの䜿い勝手も向䞊しおいるかなどを培底的にチェックしおいたした。 䜿い勝手をチェックするにあたっお、ゞョブメドレヌのメむンナヌザヌの幎霢局などが予め分かっおいたので、その方達にずっお䜿いやすいかどうかを刀断軞ずしお、考えおいたした。 デザむナヌが完成させた UI でも、でき䞊がったモックアップをメンバヌそれぞれの芖点で觊っおみるず改善点が出る堎面がありたした。そういった堎合には、こういう UI にしおみたらどうかなどずそれぞれが意芋し、良さそうな案に぀いおはデザむナヌがそれらの提案を取り蟌んだり改良したりしお、UI の仕様を詰めおいきたした。 技術面に぀いお 新居 : UI を実装に萜ずし蟌む際、技術面で工倫した点や気を付けおいたポむントなどはありたすか 堀内 : 今回のプロゞェクトでは、求人カヌドのデザむンを倧幅に倉曎する為事前の圱響範囲の掗い出しを培底するよう泚意しおいたした䟋えば、䞀芧画面における求人情報の出力量がかなり増えるこずで、1 ペヌゞあたりの読み蟌み凊理に時間がかかっおしたうこずが予想された為コンテンツの遅延読み蟌みやキャッシュの利甚によりチュヌニングを行っおいたすたたデザむン倉曎が倚くのペヌゞにわたっお発生する為リリヌス埌の䞍具合を起こさないような察策を耇数行っおいたす 担圓したプロゞェクトのリヌド 新居 : 今回のプロゞェクトでは、゚ンゞニアずしお開発をし぀぀、堀内さんがプロゞェクトのリヌドを任されおいたず聞いおいたす。リヌドずしおは、どんな動きをプロゞェクトの䞭でされおいたのでしょうか 堀内 : たずは、最初にプロゞェクト党䜓の倧たかなスケゞュヌルを匕き、PdM ず確認したした。次に、タスク分解をしおメンバヌぞのアサむンを行ったり、プロゞェクトのタスクのなかで䞍確実性を極力少なくする為に、自分達だけではコントロヌルできなさそうな郚分を掗い出したりしたした。掗い出したアンコントロヌラブルな郚分は䌁画者ず共に関係各所ぞ連絡・調敎をしおもらうようお願いしおいたした。 新居 : なるほど。開発スケゞュヌルの出し方など、その蟺りで工倫した点などはありたすか 堀内 : スケゞュヌルの共有方法に぀いおは、芖芚的に分かりやすいように、 FigJam を䜿っお、ガントチャヌトのような圢匏で、ボヌドを䜜成したした。 メンバヌ毎にレヌンを振り分けお、誰がい぀たでに䜕をしなければいけないのかを倕䌚で確認しおいたした。たた、スケゞュヌルのボヌドは垞に、 第䞉者が芋おも進捗状況が盎ぐに分かるような状態にしおおく よう努めたした。 スケゞュヌルボヌド スケゞュヌリングで特に意識しおいたこずは、䞍確実な郚分を早めに掗い出すこずでした。タスク分解をしおいく䞭で、どこが自分達だけではコントロヌルできなさそうな郚分なのかを把握するこずから始めおいたした。 珟状の仕様や実装がどうなっおいるのかなどは盎ぐに確認できるので、そういったずころから、なるべく䞍確実な郚分を枛らしおいき、最終的に各タスクの工数を算出するにあたっお、䞍確実性の高さに応じお、バッファを蚭定したした。 新居 : 少し手を動かせば確認できるようなずころは盎ぐに確認しお、なるべく解像床が高い状態にもっおいく進め方は確かに良さそうですね工数を芋積もるにあたっお、解像床が䜎い状態だず、芋積もりの粟床が䜎くなっおしたいたすからね。 堀内 : たた、タスクは GitHub Issue を発行しお管理しおいたのですが、切り出す粒床はなるべく现かくしおいたした。Issue の粒床が荒くなっおしたうず、それに比䟋しお手戻りリスクが高くなっおしたうので、目安ずしおは、長くおも 2 日以内には完了できる粒床で切り出しおいたした。 結果、今回のプロゞェクトにおいおは、ほずんど手戻りするこずなく、ほが党おの期間においお、オンスケゞュヌルで進めるこずができたした。 A/B テストの導入効果怜蚌の仕組み化 新居 : オンスケで進められおいたのは玠晎らしいですね開発者ずしお実装するこずず、リヌドずしおプロゞェクトを管理するこずの他、堀内さんが今回のプロゞェクトで担圓しおいた圹割などはありたすか 堀内 : 今回のプロゞェクトでは、効果怜蚌を行う為の仕組みずしお、A/B テストを本栌的に導入する目暙がありたした。なぜ A/B テストを導入するのか A/B テストで䜕をしたいのかを明確にしお、A/B テストの蚭蚈から導入分析たでを行いたした。 統蚈的な分析手法の遞択から実際のテスト環境の開発みたいなずころたで䞀気通貫で、PdM、マヌケタヌ、゚ンゞニアを巻き蟌んで行いたした。 A/B テストで倧事なのは、論理的な仮説を立おおそれを怜蚌し、その結果からより効果があるず刀断できた斜策を導入しおいく、ずいうサむクルだず考えおいたすずはいえ、有意差が出たからずいっお必ずしも導入したほうが良いずいうわけではありたせんその時の経営面のメリット・デメリットを考慮しこれたでの経隓にもずづいた刀断も加えお、より効果の高い斜策を継続的に導入できるようにする、ずいうのが今回の目暙です 今回のプロゞェクトを皮切りに、他のプロゞェクトでも同じように A/B テストの仕組みを䜿える状態にしたい。そういった暪展開や汎甚性みたいなずころも、プロゞェクト圓初からセットで考えおいたした。 新居 : ずおも興味深い取り組みですね実際、どのように仕組み化を進めおいくのでしょうか 堀内 : A/B テストに必芁な知芋をドキュメント化しお、それを芋るだけで、゚ンゞニアのサポヌトを受け぀぀誰でも A/B テストが実斜できるようにしおいく取り組みやスプレッドシヌトにデヌタを入力すれば、簡単に結果が刀るような仕組み化を進行䞭です 機胜のリリヌス時はその結果に応じお結局、どうすれば良いのかずいった指針も Issue やドキュメントに蚘茉しおおりたす 実装や蚭蚈面における悩み 新居 : 実装や蚭蚈面においお、今回のプロゞェクトで悩んだようなずころはありたしたか 堀内 : はい。自分自身の力量の問題で、ドメむン知識や技術力などが䞍足しおいたこずから、ゞョブメドレヌのコヌドの䞭で今たでの慣習を受け継ぎ぀぀、良い感じに䜿い回しができるコヌドをどう䞊手く曞いおいくか、ずいう点に぀いお悩んでいたした。 新居 : なるほど 。ゞョブメドレヌ自䜓が 10 幎以䞊の歎史があるサヌビスなので、そこに手を入れおいくのは確かに難しい郚分もありそうですね。その悩みに察しおは、どう察策をされおいたのでしょう 堀内 : そうですね。今の自分の知芋だけで蚭蚈ず実装を進めおしたうず手戻りが発生しおしたう恐れがあったので、たずはドメむン知識が豊富な、同じチヌム内のベテラン瀟員に蚭蚈レビュヌをお願いしたした。そこで、ゞョブメドレヌのむンフラ構成におけるキャッシュ戊略や保守性を高める為の実装の切り出し方など、壁打ちで盞談させおもらっおいたした。 その先茩瀟員ずの蚭蚈レビュヌ以倖にも、普段から行っおもらっおいる 1on1 ミヌティングを通じお、自分のメンタヌず盞談させおもらい、どういう蚭蚈だったら䜿いやすいのか、などを様々な芖点から怜蚎したした 新居 : なるべく手戻りが発生しないようにする為に、 蚭蚈段階で身近にいる゚ンゞニアを巻き蟌んで進めおいった のですね。盎ぐに盞談できる盞手がいるのは心匷いですね。 孊びになった点 新居 : 今回のプロゞェクトを通じお、特に孊びになった点を教えおいただけたすか 堀内 : 技術的な面ずプロゞェクトの進め方の面でそれぞれ孊びがありたした。 技術的な面で蚀うず、 保守性が高く、今埌、運甚しやすいコヌドずはどういうものなのかずいうのを、今回の実装を通じお䜓埗できた ずころだず思っおいたす。 プロゞェクトの進め方の面では、過去のプロゞェクトのドキュメントを参考に、そこに曞かれおいた知芋を掻かしながら、プロゞェクトを進めおいったので、ノりハりのようなずころが孊べたかず思っおいたす。 新卒研修・開発実践のリヌドずの違い 新居 : 堀内さんは、新卒研修の䞀環で行われた開発実践の期間䞭、新卒同士のチヌム開発でもリヌドを務めおいたず思いたす。今回のプロゞェクトを通じお経隓されたリヌドずの違いに぀いお教えおください。 堀内 : プロゞェクトの芏暡や圱響範囲の違いなどから、研修時よりも倚くの関係者ずの調敎が必芁でした党員ず情報を共有・連携し぀぀プロゞェクトを進める必芁があった点が䞀番倧きな違いでした。 たた、開発実践のプロゞェクトはあくたで瀟内向けシステムを構築するものだったので、䌚瀟の売䞊に぀いお意識するこずはありたせんでしたが、今回のプロゞェクトでは、斜策によっお応募率が䞋がった堎合に売䞊に悪圱響を及がす可胜性がありたしたので、開発郚眲以倖ぞの圱響を意識しお管理する必芁があったこずも倧きいポむントだったず思っおいたす。 ゞョブメドレヌの開発におけるやりがい 新居 : ここたで盎近で担圓されおいたプロゞェクトに぀いお聞いおきたしたが、ゞョブメドレヌの開発をしおいお、特にやりがいを感じる堎面に぀いお、教えおもらえたすか 堀内 : やはり利甚しおくださっおいる求職者や事業者の方々に向けお新芏機胜開発や機胜改修を行う工皋です目的ず照らし合わせお仕様面から劥協せずに考え抜き、リリヌスするたでの過皋にやりがいを感じおいたすナヌザヌ数がずおも倚いだけに良い機胜をリリヌスできたずきの反響も倧きく非垞に楜しいです 勿論、゚ンゞニアずしお技術力を䞊げおいくこずも貪欲に今埌もやっおいかなければならない郚分だず思っおいたすが、䌁画ずしお案件があがっおきた段階で、それをなぜ䜜るのかなぜそれで効果が出るず思っおいるのかなどず考えるこずが、䌁画職だけでなく゚ンゞニアにずっおも倧事だず考えおいたす リリヌスした埌には、実際に効果が出たのか出なかったのか、なぜ効果が出たのか出なかったのかなどの効果怜蚌を行った䞊で、PdM を䞭心に゚ンゞニア以倖のメンバヌも亀えお振り返り、次の斜策に掻かしおいくずいった、 PDCA サむクルを回しおいっおいる開発スタむルに楜しさを感じおいたす 。 これは、自分の入瀟時にやりたいこずずしおあげおいた、゚ンゞニアリング面だけではなくビゞネス面に぀いおも倚くの経隓を積みたい、ずいうずころにリンクしおいお、今圚籍しおいるゞョブメドレヌの開発チヌムでは、䌁画やマヌケティングを行う人達ず゚ンゞニアがずおも近い距離にいるこずで、様々な知芋を埗られ぀぀アりトプットできるずおも孊びになる環境だず感じおいたす。 ゞョブメドレヌ開発チヌムにおける 1 日の流れ 新居 : 珟圚のゞョブメドレヌ開発チヌムは、Growth Unit求職者の利䟿性を高める斜策を行うチヌムず Customer Unit求人を掲茉する事業者が䜿う採甚管理システムの改善斜策を行うチヌムの 2 ぀に分かれおいるんですよね。堀内さんが所属しおいるのは、Growth Unit の方ですが、参加されおいるミヌティングなど、1 日の流れに぀いお教えおください。 堀内 : たず、勀務開始の 10:00 頃には Slack に投皿する圢で、その日のタスクや参加予定のミヌティングなどに぀いお、開発甚 channel で共有したす。 珟圚の自分のスケゞュヌルでは、午前䞭は特に定垞的なミヌティングはありたせん。䜆し、アサむンされるプロゞェクトによっおは、午前䞭に「朝䌚」ずしおプロゞェクトメンバヌ同士が集たっお、進捗共有などを行っおいたす。 お昌過ぎの 14:30 からは 30 分皋床Growth Unit の゚ンゞニアだけで集たるミヌティングがありたす。この堎では、各自の進捗状況や抱えおいる䞍安・䞍明点などを共有したす今䜕に困っおいるのかを共有するだけでなく 困りごずに察し各々が知恵を出し合っお、問題解決たでのリヌドタむムを短くする こずができる貎重な堎ずなっおいたす 18:00 からは「倕䌚」ずしお、PdM ずデザむナヌも含めた Growth Unit 党䜓のミヌティングがありたす。そこで各自、「今日やったこず」や担圓 Issue のリリヌス目凊などを共有しおいたす。この堎では、゚ンゞニア以倖のメンバヌも参加しおいるので、そこたで技術的に突っ蟌んだ話たではしたせん。 さらに、終業前にはたた゚ンゞニアだけで集たり、FigJam を䜿っお付箋を貌っおいく圢で、 各自が技術的トピックや、特定のドメむンに぀いお聞きたいこずなどを持ち寄り、ざっくばらんに雑談圢匏で話す 「技術共有䌚」を行っおいたす。 技術共有䌚の雰囲気 ミヌティングの堎以倖は黙々ず開発を進めおいきたすが、聞きたいこずや盞談したいこずが出おきたら郜床、開発甚のスレッドに投皿しおいたす。 新居 : なるほど。質問や盞談はしやすい感じですか 堀内 : はい。勿論、自分で調べられるこずはなるべく調べお、自己解決するのが基本ではありたすが、あたり調査に時間をかけ過ぎお党然進たないような事態に陥っおも良くないので、それらを皆、前提ずしお意識した䞊で、聞くべき時は躊躇なく聞ける雰囲気がありたす。 新居 : ミヌティングの皮類ずしおは、先ほどあげおもらったもの以倖にありたすか 堀内 : あずは、週䞀で行われおいる「プロダクト定䟋」ず隔週で行っおもらっおいる「1on1 ミヌティング」がありたす。 プロダクト定䟋は、比范的芏暡の倧きいミヌティングで、我々、プロダクト開発宀以倖のメンバヌの他、マヌケティング宀や事業䌁画宀のメンバヌも含めお、倧䜓い぀も 40 名前埌の人数で参加しおいたす。 この堎では、珟圚远っおいる KPI だったり、ゞョブメドレヌで動いおいる党おのプロゞェクト状況が共有されたす。そこで共有される KPI の数字によっお、次に着手すべき Issue にも圱響しおくるので、この堎で共有される情報をしっかりずむンプットしお、今埌の心構えずするこずにしおいたす。 盎近で担圓したプロゞェクトの話でもちらっず出おきたしたが、1on1 ミヌティングは担圓メンタヌず行なっおいたす。普段の仕事の盞談から、自分のキャリアに関するような盞談をしおおり、メンタヌさんの経隓なども教えおいただきながら、勉匷させおいただいおいたす。 1on1 ミヌティングの意矩ずしおは、そういった仕事の他、 プラむベヌトのこずも含めお、䜕でも盞談ができる堎 ずしおあるのですが、1on1 を通じお、メンタヌさんずの信頌関係も築けるので、チヌムビルディングの䞀぀ずしおも機胜しおいたす。 ゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人 新居 : 堀内さんがゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人でしょうか 堀内 : 今の環境で働いおお良かったなあず思うこずは、 人間関係が良奜であるこず ですもちろん銎れ合いの䞭での業務ずいうわけではなく各々が しっかりず仕事に察しお責任を持ち぀぀チヌム内で生じた違和感は遠慮なく指摘し合い受けずめる ずいう良い意味で心理的安党性のある環境でプロダクト開発に集䞭しお取り組めるこずです。 このような環境で、課題に察しお長期的な芖点で本質を捉え、目的を蚭定しボトムアップで解決策の立案から改善たでを䞻導するこず、さらには仕組み化たで行うこずが奜きな方たたはそれらをやっおみたい方が合っおいるのではないかず思いたす。 自分もそのような人間になりたいず思いながら、日々仕事に取り組んでいたす。 さいごに ゞョブメドレヌ開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおきたしたが、いかがだったでしょうか こんなチヌムでプロダクトを䜜っおいきたいず思う方は、ぜひお気軜にお話をしたしょう! 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp
はじめに みなさん、こんにちは。゚ンゞニアの新居です。今回は医療介護求人サむトの ゞョブメドレヌ 開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおいこうず思いたす。 むンタビュむヌ玹介 堀内さん 2021 幎入瀟。人材プラットフォヌム本郚 プロダクト開発宀 第䞀開発グルヌプ所属。ゞョブメドレヌの開発を担圓。珟圚は求職者偎の UI/UX 改善などの開発に携わる。 堀内さん メドレヌに入瀟した理由 新居 : たずはじめに、堀内さんはどういう経緯でメドレヌに入瀟したのでしたっけ 堀内 : 以前のむンタビュヌ 21 幎新卒入瀟゚ンゞニアず座談䌚で振り返る新卒研修 の時にもお話したのですが、就掻の軞ずしお、自分が成長できそうか・颚通しが良いか・合理的な瀟颚かなどを軞ずしお探しおいたした。特に ビゞネス偎ず開発偎の距離が近い 郚分に惹かれ総合的にメドレヌが良さそうだず考えお入瀟したした。 新居 : 入瀟前の印象ず実際働きだしおからで、ズレなどはありたしたか 堀内 : そんなにギャップはなくお、瀟颚ずか人間関係みたいなずころは入瀟前のむメヌゞ通りでした。入瀟前に䜕回か䌚瀟芋孊をさせおもらったり、その時の瀟員ず耇数回面談をセッティングしおもらったりしお、そこでむメヌゞをすり合わせできたこずが倧きかったですね。 新居 : 䜕人くらいの瀟員ず䌚ったのですか 堀内 : 6 ~ 7 人です。色々なポゞションや性栌の人達ず話ができたので、安心しお入瀟するこずができたした。 新卒研修の開発 OJT ではどんなこずをやっおいたか 新居 : 堀内さんは新卒研修の開発 OJT のタむミングでゞョブメドレヌ開発チヌムに仮配属されたのですよね。圓時はどういうこずをやっおたのですか 堀内 : たずはゞョブメドレヌのドメむン知識をしっかり吞収しおいこうずいうこずで、業界や業務自䜓の理解を進めたした。 その埌、求職者ず事業者のサポヌト業務を行う瀟内オペレヌタヌが利甚する画面の拡匵タスクに取り組みたした。 技術スタックは Next.js / React / TypeScript / GraphQL ずいったシステムで、個人的にあたり觊れおこなかった領域だったので、技術のキャッチアップもし぀぀䞁寧に察応しおいきたした。 たた、開発 OJT よりも前の研修で茪読䌚も経隓したのですが、その時に孊んだ Cookie や Session たわりの知識が圹に立ったり、座孊で孊んだこずがこうやっお実践で掻きおくるんだな、ずいうこずを実感 できおずおも良い経隓になりたした。 今たでずは比べ物にならないくらい倧芏暡なシステムだったので、プレッシャヌも倧きかったのですが、チヌムの人達ず盞談したり、现かいレビュヌ・サポヌトがあったおかげで、しっかり成果を出すこずができたず思いたす。 新居 : 良い OJT ですね堀内さん自身の努力があったのは勿論ですが、チヌムに新しいメンバヌを迎え入れお成長をサポヌトする環境が敎っおいたのも良かったんでしょうね。 ちなみに開発 OJT の䞭で倧倉だったこずずかはありたすか 堀内 : そうですね、やはり倧芏暡な既存コヌドの把握・理解が倧倉でした。瀟内オペレヌタヌが䜿う画面ずゞョブメドレヌ本䜓はそれぞれ別システムずしお連携しおいるので、ゞョブメドレヌ本䜓のコヌドや仕組みの理解も必芁です。 倧倉だった分、 システムの党䜓像を理解するのに倧いに圹立った ので、今思い返すず良い経隓だったなあず思いたす。 色々な経隓を積めた求人カヌド改修プロゞェクト 新居 : では、新卒研修を終えおから 1 幎以䞊経っおいお、入瀟 2 幎目の終わりに差し掛かっおいる珟圚ですが、盎近で堀内さんがリヌドを務めおいた、ゞョブメドレヌの求人カヌド改修プロゞェクトに぀いお話を聞いおいきたいず思いたす。たずは、このプロゞェクトの抂芁に぀いお、教えおもらえたすか 求人カヌド改修プロゞェクトずは 堀内 : それではプロゞェクト説明に先立ちたしおたず、ゞョブメドレヌの「求人カヌド」に぀いお簡単に説明したす。 ゞョブメドレヌで求人を怜玢するず怜玢結果が䞊ぶ画面が出おきたす。我々が「求人カヌド」ず呌んでいるのは、この怜玢結果画面䞊に衚瀺される、求人情報のこずになりたす。 怜玢結果画面の求人カヌドでは、絊䞎や倧たかな業務内容、応募芁件、職堎の䜏所などが分かる圢になっおいたすが、求職者の方々がより䟿利に䜿っおいただけるよう、情報の出し方を芋盎すこずが今回のプロゞェクト内容です。 もう少し詳しくお話するず採甚決定率の改善を目的にどのような改善を実斜すべきか怜蚎しおいたす 求職者にずっお欲しい情報が手に入りやすくなるずいうこずは、その分、応募に繋がりやすくなるず蚀い換えるこずもできたすので改修による効果に぀いおは、継続的に怜蚌し効果の有無を明らかにしたいず考えおいたす 新居 : なるほど。端的に蚀うず、ゞョブメドレヌにおける求人情報怜玢の䜓隓を曎に良くする為のプロゞェクトずいうこずですね。 プロゞェクトのはじたり 新居 : 今回のプロゞェクトをどのようなメンバヌず䜕をどのように行っおいったのか、チヌム構成から教えおください。 堀内 : チヌム構成ずしおは、自分を含めた゚ンゞニアが 2 人いお、その他は、デザむナヌ、マヌケタヌ、プロダクトマネヌゞャヌ以䞋、PdMがそれぞれ 1 人ず぀プロゞェクトにアサむンされたした。 プロゞェクトのきっかけずしおは、求職者䜓隓を曎に良くする為の䌁画の䞀぀ずしおマヌケタヌず PdM が䌁画したずころから始たり、その埌、゚ンゞニアずマヌケタヌ間で现かい具䜓的な芁件たで萜ずし蟌んで、プロゞェクト化に至りたした。 仕様に぀いおメンバヌ間で培底議論 堀内 : 芁件たで萜ずし蟌んだ埌は、具䜓的にそれらをどうやっお実装するかを怜蚎したした。特に UI の仕様に぀いおは、デザむナヌを䞭心にかなり長い時間をかけお詰めおいきたした 。 新居 : 確かに、情報の出し方によっおは、かえっお、求職者䜓隓を悪化させおしたう可胜性がありそうですね 。 堀内 : はい。䜿い勝手の良い UI にする為に、デザむナヌがたず Figma でモックアップを䜜り、プロゞェクトが始たった最初の週からデむリヌの倕䌚などで、UI に関しお培底的にプロゞェクトメンバヌ間で議論をしおいたした。 その時、特にメンバヌ党員が気を付けおいたのは、実際に求職者が新しい䞀芧画面を䜿う時に、䟡倀を感じおもらえるかどうかです。メドレヌの Our Essentials の䞀぀ずしお、 長期のカスタマヌ䟡倀を远求 ずいう項目がありたす「党おの利甚者にずっお䟡倀のある斜策であるこず」「利甚者の片方だけを芋お、もう片方を無芖するこずがあっおはならない」ずいうこずで、事業者偎の求人情報を倚く茉せるだけではなく、求職者にずっおの䜿い勝手も向䞊しおいるかなどを培底的にチェックしおいたした。 䜿い勝手をチェックするにあたっお、ゞョブメドレヌのメむンナヌザヌの幎霢局などが予め分かっおいたので、その方達にずっお䜿いやすいかどうかを刀断軞ずしお、考えおいたした。 デザむナヌが完成させた UI でも、でき䞊がったモックアップをメンバヌそれぞれの芖点で觊っおみるず改善点が出る堎面がありたした。そういった堎合には、こういう UI にしおみたらどうかなどずそれぞれが意芋し、良さそうな案に぀いおはデザむナヌがそれらの提案を取り蟌んだり改良したりしお、UI の仕様を詰めおいきたした。 技術面に぀いお 新居 : UI を実装に萜ずし蟌む際、技術面で工倫した点や気を付けおいたポむントなどはありたすか 堀内 : 今回のプロゞェクトでは、求人カヌドのデザむンを倧幅に倉曎する為事前の圱響範囲の掗い出しを培底するよう泚意しおいたした䟋えば、䞀芧画面における求人情報の出力量がかなり増えるこずで、1 ペヌゞあたりの読み蟌み凊理に時間がかかっおしたうこずが予想された為コンテンツの遅延読み蟌みやキャッシュの利甚によりチュヌニングを行っおいたすたたデザむン倉曎が倚くのペヌゞにわたっお発生する為リリヌス埌の䞍具合を起こさないような察策を耇数行っおいたす 担圓したプロゞェクトのリヌド 新居 : 今回のプロゞェクトでは、゚ンゞニアずしお開発をし぀぀、堀内さんがプロゞェクトのリヌドを任されおいたず聞いおいたす。リヌドずしおは、どんな動きをプロゞェクトの䞭でされおいたのでしょうか 堀内 : たずは、最初にプロゞェクト党䜓の倧たかなスケゞュヌルを匕き、PdM ず確認したした。次に、タスク分解をしおメンバヌぞのアサむンを行ったり、プロゞェクトのタスクのなかで䞍確実性を極力少なくする為に、自分達だけではコントロヌルできなさそうな郚分を掗い出したりしたした。掗い出したアンコントロヌラブルな郚分は䌁画者ず共に関係各所ぞ連絡・調敎をしおもらうようお願いしおいたした。 新居 : なるほど。開発スケゞュヌルの出し方など、その蟺りで工倫した点などはありたすか 堀内 : スケゞュヌルの共有方法に぀いおは、芖芚的に分かりやすいように、 FigJam を䜿っお、ガントチャヌトのような圢匏で、ボヌドを䜜成したした。 メンバヌ毎にレヌンを振り分けお、誰がい぀たでに䜕をしなければいけないのかを倕䌚で確認しおいたした。たた、スケゞュヌルのボヌドは垞に、 第䞉者が芋おも進捗状況が盎ぐに分かるような状態にしおおく よう努めたした。 スケゞュヌルボヌド スケゞュヌリングで特に意識しおいたこずは、䞍確実な郚分を早めに掗い出すこずでした。タスク分解をしおいく䞭で、どこが自分達だけではコントロヌルできなさそうな郚分なのかを把握するこずから始めおいたした。 珟状の仕様や実装がどうなっおいるのかなどは盎ぐに確認できるので、そういったずころから、なるべく䞍確実な郚分を枛らしおいき、最終的に各タスクの工数を算出するにあたっお、䞍確実性の高さに応じお、バッファを蚭定したした。 新居 : 少し手を動かせば確認できるようなずころは盎ぐに確認しお、なるべく解像床が高い状態にもっおいく進め方は確かに良さそうですね工数を芋積もるにあたっお、解像床が䜎い状態だず、芋積もりの粟床が䜎くなっおしたいたすからね。 堀内 : たた、タスクは GitHub Issue を発行しお管理しおいたのですが、切り出す粒床はなるべく现かくしおいたした。Issue の粒床が荒くなっおしたうず、それに比䟋しお手戻りリスクが高くなっおしたうので、目安ずしおは、長くおも 2 日以内には完了できる粒床で切り出しおいたした。 結果、今回のプロゞェクトにおいおは、ほずんど手戻りするこずなく、ほが党おの期間においお、オンスケゞュヌルで進めるこずができたした。 A/B テストの導入効果怜蚌の仕組み化 新居 : オンスケで進められおいたのは玠晎らしいですね開発者ずしお実装するこずず、リヌドずしおプロゞェクトを管理するこずの他、堀内さんが今回のプロゞェクトで担圓しおいた圹割などはありたすか 堀内 : 今回のプロゞェクトでは、効果怜蚌を行う為の仕組みずしお、A/B テストを本栌的に導入する目暙がありたした。なぜ A/B テストを導入するのか A/B テストで䜕をしたいのかを明確にしお、A/B テストの蚭蚈から導入分析たでを行いたした。 統蚈的な分析手法の遞択から実際のテスト環境の開発みたいなずころたで䞀気通貫で、PdM、マヌケタヌ、゚ンゞニアを巻き蟌んで行いたした。 A/B テストで倧事なのは、論理的な仮説を立おおそれを怜蚌し、その結果からより効果があるず刀断できた斜策を導入しおいく、ずいうサむクルだず考えおいたすずはいえ、有意差が出たからずいっお必ずしも導入したほうが良いずいうわけではありたせんその時の経営面のメリット・デメリットを考慮しこれたでの経隓にもずづいた刀断も加えお、より効果の高い斜策を継続的に導入できるようにする、ずいうのが今回の目暙です 今回のプロゞェクトを皮切りに、他のプロゞェクトでも同じように A/B テストの仕組みを䜿える状態にしたい。そういった暪展開や汎甚性みたいなずころも、プロゞェクト圓初からセットで考えおいたした。 新居 : ずおも興味深い取り組みですね実際、どのように仕組み化を進めおいくのでしょうか 堀内 : A/B テストに必芁な知芋をドキュメント化しお、それを芋るだけで、゚ンゞニアのサポヌトを受け぀぀誰でも A/B テストが実斜できるようにしおいく取り組みやスプレッドシヌトにデヌタを入力すれば、簡単に結果が刀るような仕組み化を進行䞭です 機胜のリリヌス時はその結果に応じお結局、どうすれば良いのかずいった指針も Issue やドキュメントに蚘茉しおおりたす 実装や蚭蚈面における悩み 新居 : 実装や蚭蚈面においお、今回のプロゞェクトで悩んだようなずころはありたしたか 堀内 : はい。自分自身の力量の問題で、ドメむン知識や技術力などが䞍足しおいたこずから、ゞョブメドレヌのコヌドの䞭で今たでの慣習を受け継ぎ぀぀、良い感じに䜿い回しができるコヌドをどう䞊手く曞いおいくか、ずいう点に぀いお悩んでいたした。 新居 : なるほど 。ゞョブメドレヌ自䜓が 10 幎以䞊の歎史があるサヌビスなので、そこに手を入れおいくのは確かに難しい郚分もありそうですね。その悩みに察しおは、どう察策をされおいたのでしょう 堀内 : そうですね。今の自分の知芋だけで蚭蚈ず実装を進めおしたうず手戻りが発生しおしたう恐れがあったので、たずはドメむン知識が豊富な、同じチヌム内のベテラン瀟員に蚭蚈レビュヌをお願いしたした。そこで、ゞョブメドレヌのむンフラ構成におけるキャッシュ戊略や保守性を高める為の実装の切り出し方など、壁打ちで盞談させおもらっおいたした。 その先茩瀟員ずの蚭蚈レビュヌ以倖にも、普段から行っおもらっおいる 1on1 ミヌティングを通じお、自分のメンタヌず盞談させおもらい、どういう蚭蚈だったら䜿いやすいのか、などを様々な芖点から怜蚎したした 新居 : なるべく手戻りが発生しないようにする為に、 蚭蚈段階で身近にいる゚ンゞニアを巻き蟌んで進めおいった のですね。盎ぐに盞談できる盞手がいるのは心匷いですね。 孊びになった点 新居 : 今回のプロゞェクトを通じお、特に孊びになった点を教えおいただけたすか 堀内 : 技術的な面ずプロゞェクトの進め方の面でそれぞれ孊びがありたした。 技術的な面で蚀うず、 保守性が高く、今埌、運甚しやすいコヌドずはどういうものなのかずいうのを、今回の実装を通じお䜓埗できた ずころだず思っおいたす。 プロゞェクトの進め方の面では、過去のプロゞェクトのドキュメントを参考に、そこに曞かれおいた知芋を掻かしながら、プロゞェクトを進めおいったので、ノりハりのようなずころが孊べたかず思っおいたす。 新卒研修・開発実践のリヌドずの違い 新居 : 堀内さんは、新卒研修の䞀環で行われた開発実践の期間䞭、新卒同士のチヌム開発でもリヌドを務めおいたず思いたす。今回のプロゞェクトを通じお経隓されたリヌドずの違いに぀いお教えおください。 堀内 : プロゞェクトの芏暡や圱響範囲の違いなどから、研修時よりも倚くの関係者ずの調敎が必芁でした党員ず情報を共有・連携し぀぀プロゞェクトを進める必芁があった点が䞀番倧きな違いでした。 たた、開発実践のプロゞェクトはあくたで瀟内向けシステムを構築するものだったので、䌚瀟の売䞊に぀いお意識するこずはありたせんでしたが、今回のプロゞェクトでは、斜策によっお応募率が䞋がった堎合に売䞊に悪圱響を及がす可胜性がありたしたので、開発郚眲以倖ぞの圱響を意識しお管理する必芁があったこずも倧きいポむントだったず思っおいたす。 ゞョブメドレヌの開発におけるやりがい 新居 : ここたで盎近で担圓されおいたプロゞェクトに぀いお聞いおきたしたが、ゞョブメドレヌの開発をしおいお、特にやりがいを感じる堎面に぀いお、教えおもらえたすか 堀内 : やはり利甚しおくださっおいる求職者や事業者の方々に向けお新芏機胜開発や機胜改修を行う工皋です目的ず照らし合わせお仕様面から劥協せずに考え抜き、リリヌスするたでの過皋にやりがいを感じおいたすナヌザヌ数がずおも倚いだけに良い機胜をリリヌスできたずきの反響も倧きく非垞に楜しいです 勿論、゚ンゞニアずしお技術力を䞊げおいくこずも貪欲に今埌もやっおいかなければならない郚分だず思っおいたすが、䌁画ずしお案件があがっおきた段階で、それをなぜ䜜るのかなぜそれで効果が出るず思っおいるのかなどず考えるこずが、䌁画職だけでなく゚ンゞニアにずっおも倧事だず考えおいたす リリヌスした埌には、実際に効果が出たのか出なかったのか、なぜ効果が出たのか出なかったのかなどの効果怜蚌を行った䞊で、PdM を䞭心に゚ンゞニア以倖のメンバヌも亀えお振り返り、次の斜策に掻かしおいくずいった、 PDCA サむクルを回しおいっおいる開発スタむルに楜しさを感じおいたす 。 これは、自分の入瀟時にやりたいこずずしおあげおいた、゚ンゞニアリング面だけではなくビゞネス面に぀いおも倚くの経隓を積みたい、ずいうずころにリンクしおいお、今圚籍しおいるゞョブメドレヌの開発チヌムでは、䌁画やマヌケティングを行う人達ず゚ンゞニアがずおも近い距離にいるこずで、様々な知芋を埗られ぀぀アりトプットできるずおも孊びになる環境だず感じおいたす。 ゞョブメドレヌ開発チヌムにおける 1 日の流れ 新居 : 珟圚のゞョブメドレヌ開発チヌムは、Growth Unit求職者の利䟿性を高める斜策を行うチヌムず Customer Unit求人を掲茉する事業者が䜿う採甚管理システムの改善斜策を行うチヌムの 2 ぀に分かれおいるんですよね。堀内さんが所属しおいるのは、Growth Unit の方ですが、参加されおいるミヌティングなど、1 日の流れに぀いお教えおください。 堀内 : たず、勀務開始の 10:00 頃には Slack に投皿する圢で、その日のタスクや参加予定のミヌティングなどに぀いお、開発甚 channel で共有したす。 珟圚の自分のスケゞュヌルでは、午前䞭は特に定垞的なミヌティングはありたせん。䜆し、アサむンされるプロゞェクトによっおは、午前䞭に「朝䌚」ずしおプロゞェクトメンバヌ同士が集たっお、進捗共有などを行っおいたす。 お昌過ぎの 14:30 からは 30 分皋床Growth Unit の゚ンゞニアだけで集たるミヌティングがありたす。この堎では、各自の進捗状況や抱えおいる䞍安・䞍明点などを共有したす今䜕に困っおいるのかを共有するだけでなく 困りごずに察し各々が知恵を出し合っお、問題解決たでのリヌドタむムを短くする こずができる貎重な堎ずなっおいたす 18:00 からは「倕䌚」ずしお、PdM ずデザむナヌも含めた Growth Unit 党䜓のミヌティングがありたす。そこで各自、「今日やったこず」や担圓 Issue のリリヌス目凊などを共有しおいたす。この堎では、゚ンゞニア以倖のメンバヌも参加しおいるので、そこたで技術的に突っ蟌んだ話たではしたせん。 さらに、終業前にはたた゚ンゞニアだけで集たり、FigJam を䜿っお付箋を貌っおいく圢で、 各自が技術的トピックや、特定のドメむンに぀いお聞きたいこずなどを持ち寄り、ざっくばらんに雑談圢匏で話す 「技術共有䌚」を行っおいたす。 技術共有䌚の雰囲気 ミヌティングの堎以倖は黙々ず開発を進めおいきたすが、聞きたいこずや盞談したいこずが出おきたら郜床、開発甚のスレッドに投皿しおいたす。 新居 : なるほど。質問や盞談はしやすい感じですか 堀内 : はい。勿論、自分で調べられるこずはなるべく調べお、自己解決するのが基本ではありたすが、あたり調査に時間をかけ過ぎお党然進たないような事態に陥っおも良くないので、それらを皆、前提ずしお意識した䞊で、聞くべき時は躊躇なく聞ける雰囲気がありたす。 新居 : ミヌティングの皮類ずしおは、先ほどあげおもらったもの以倖にありたすか 堀内 : あずは、週䞀で行われおいる「プロダクト定䟋」ず隔週で行っおもらっおいる「1on1 ミヌティング」がありたす。 プロダクト定䟋は、比范的芏暡の倧きいミヌティングで、我々、プロダクト開発宀以倖のメンバヌの他、マヌケティング宀や事業䌁画宀のメンバヌも含めお、倧䜓い぀も 40 名前埌の人数で参加しおいたす。 この堎では、珟圚远っおいる KPI だったり、ゞョブメドレヌで動いおいる党おのプロゞェクト状況が共有されたす。そこで共有される KPI の数字によっお、次に着手すべき Issue にも圱響しおくるので、この堎で共有される情報をしっかりずむンプットしお、今埌の心構えずするこずにしおいたす。 盎近で担圓したプロゞェクトの話でもちらっず出おきたしたが、1on1 ミヌティングは担圓メンタヌず行なっおいたす。普段の仕事の盞談から、自分のキャリアに関するような盞談をしおおり、メンタヌさんの経隓なども教えおいただきながら、勉匷させおいただいおいたす。 1on1 ミヌティングの意矩ずしおは、そういった仕事の他、 プラむベヌトのこずも含めお、䜕でも盞談ができる堎 ずしおあるのですが、1on1 を通じお、メンタヌさんずの信頌関係も築けるので、チヌムビルディングの䞀぀ずしおも機胜しおいたす。 ゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人 新居 : 堀内さんがゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人でしょうか 堀内 : 今の環境で働いおお良かったなあず思うこずは、 人間関係が良奜であるこず ですもちろん銎れ合いの䞭での業務ずいうわけではなく各々が しっかりず仕事に察しお責任を持ち぀぀チヌム内で生じた違和感は遠慮なく指摘し合い受けずめる ずいう良い意味で心理的安党性のある環境でプロダクト開発に集䞭しお取り組めるこずです。 このような環境で、課題に察しお長期的な芖点で本質を捉え、目的を蚭定しボトムアップで解決策の立案から改善たでを䞻導するこず、さらには仕組み化たで行うこずが奜きな方たたはそれらをやっおみたい方が合っおいるのではないかず思いたす。 自分もそのような人間になりたいず思いながら、日々仕事に取り組んでいたす。 さいごに ゞョブメドレヌ開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおきたしたが、いかがだったでしょうか こんなチヌムでプロダクトを䜜っおいきたいず思う方は、ぜひお気軜にお話をしたしょう! 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp
はじめに みなさん、こんにちは。゚ンゞニアの新居です。今回は医療介護求人サむトの ゞョブメドレヌ 開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおいこうず思いたす。 むンタビュむヌ玹介 堀内さん 2021 幎入瀟。人材プラットフォヌム本郚 プロダクト開発宀 第䞀開発グルヌプ所属。ゞョブメドレヌの開発を担圓。珟圚は求職者偎の UI/UX 改善などの開発に携わる。 堀内さん メドレヌに入瀟した理由 新居 : たずはじめに、堀内さんはどういう経緯でメドレヌに入瀟したのでしたっけ 堀内 : 以前のむンタビュヌ 21 幎新卒入瀟゚ンゞニアず座談䌚で振り返る新卒研修 の時にもお話したのですが、就掻の軞ずしお、自分が成長できそうか・颚通しが良いか・合理的な瀟颚かなどを軞ずしお探しおいたした。特に ビゞネス偎ず開発偎の距離が近い 郚分に惹かれ総合的にメドレヌが良さそうだず考えお入瀟したした。 新居 : 入瀟前の印象ず実際働きだしおからで、ズレなどはありたしたか 堀内 : そんなにギャップはなくお、瀟颚ずか人間関係みたいなずころは入瀟前のむメヌゞ通りでした。入瀟前に䜕回か䌚瀟芋孊をさせおもらったり、その時の瀟員ず耇数回面談をセッティングしおもらったりしお、そこでむメヌゞをすり合わせできたこずが倧きかったですね。 新居 : 䜕人くらいの瀟員ず䌚ったのですか 堀内 : 6 ~ 7 人です。色々なポゞションや性栌の人達ず話ができたので、安心しお入瀟するこずができたした。 新卒研修の開発 OJT ではどんなこずをやっおいたか 新居 : 堀内さんは新卒研修の開発 OJT のタむミングでゞョブメドレヌ開発チヌムに仮配属されたのですよね。圓時はどういうこずをやっおたのですか 堀内 : たずはゞョブメドレヌのドメむン知識をしっかり吞収しおいこうずいうこずで、業界や業務自䜓の理解を進めたした。 その埌、求職者ず事業者のサポヌト業務を行う瀟内オペレヌタヌが利甚する画面の拡匵タスクに取り組みたした。 技術スタックは Next.js / React / TypeScript / GraphQL ずいったシステムで、個人的にあたり觊れおこなかった領域だったので、技術のキャッチアップもし぀぀䞁寧に察応しおいきたした。 たた、開発 OJT よりも前の研修で茪読䌚も経隓したのですが、その時に孊んだ Cookie や Session たわりの知識が圹に立ったり、座孊で孊んだこずがこうやっお実践で掻きおくるんだな、ずいうこずを実感 できおずおも良い経隓になりたした。 今たでずは比べ物にならないくらい倧芏暡なシステムだったので、プレッシャヌも倧きかったのですが、チヌムの人達ず盞談したり、现かいレビュヌ・サポヌトがあったおかげで、しっかり成果を出すこずができたず思いたす。 新居 : 良い OJT ですね堀内さん自身の努力があったのは勿論ですが、チヌムに新しいメンバヌを迎え入れお成長をサポヌトする環境が敎っおいたのも良かったんでしょうね。 ちなみに開発 OJT の䞭で倧倉だったこずずかはありたすか 堀内 : そうですね、やはり倧芏暡な既存コヌドの把握・理解が倧倉でした。瀟内オペレヌタヌが䜿う画面ずゞョブメドレヌ本䜓はそれぞれ別システムずしお連携しおいるので、ゞョブメドレヌ本䜓のコヌドや仕組みの理解も必芁です。 倧倉だった分、 システムの党䜓像を理解するのに倧いに圹立った ので、今思い返すず良い経隓だったなあず思いたす。 色々な経隓を積めた求人カヌド改修プロゞェクト 新居 : では、新卒研修を終えおから 1 幎以䞊経っおいお、入瀟 2 幎目の終わりに差し掛かっおいる珟圚ですが、盎近で堀内さんがリヌドを務めおいた、ゞョブメドレヌの求人カヌド改修プロゞェクトに぀いお話を聞いおいきたいず思いたす。たずは、このプロゞェクトの抂芁に぀いお、教えおもらえたすか 求人カヌド改修プロゞェクトずは 堀内 : それではプロゞェクト説明に先立ちたしおたず、ゞョブメドレヌの「求人カヌド」に぀いお簡単に説明したす。 ゞョブメドレヌで求人を怜玢するず怜玢結果が䞊ぶ画面が出おきたす。我々が「求人カヌド」ず呌んでいるのは、この怜玢結果画面䞊に衚瀺される、求人情報のこずになりたす。 怜玢結果画面の求人カヌドでは、絊䞎や倧たかな業務内容、応募芁件、職堎の䜏所などが分かる圢になっおいたすが、求職者の方々がより䟿利に䜿っおいただけるよう、情報の出し方を芋盎すこずが今回のプロゞェクト内容です。 もう少し詳しくお話するず採甚決定率の改善を目的にどのような改善を実斜すべきか怜蚎しおいたす 求職者にずっお欲しい情報が手に入りやすくなるずいうこずは、その分、応募に繋がりやすくなるず蚀い換えるこずもできたすので改修による効果に぀いおは、継続的に怜蚌し効果の有無を明らかにしたいず考えおいたす 新居 : なるほど。端的に蚀うず、ゞョブメドレヌにおける求人情報怜玢の䜓隓を曎に良くする為のプロゞェクトずいうこずですね。 プロゞェクトのはじたり 新居 : 今回のプロゞェクトをどのようなメンバヌず䜕をどのように行っおいったのか、チヌム構成から教えおください。 堀内 : チヌム構成ずしおは、自分を含めた゚ンゞニアが 2 人いお、その他は、デザむナヌ、マヌケタヌ、プロダクトマネヌゞャヌ以䞋、PdMがそれぞれ 1 人ず぀プロゞェクトにアサむンされたした。 プロゞェクトのきっかけずしおは、求職者䜓隓を曎に良くする為の䌁画の䞀぀ずしおマヌケタヌず PdM が䌁画したずころから始たり、その埌、゚ンゞニアずマヌケタヌ間で现かい具䜓的な芁件たで萜ずし蟌んで、プロゞェクト化に至りたした。 仕様に぀いおメンバヌ間で培底議論 堀内 : 芁件たで萜ずし蟌んだ埌は、具䜓的にそれらをどうやっお実装するかを怜蚎したした。特に UI の仕様に぀いおは、デザむナヌを䞭心にかなり長い時間をかけお詰めおいきたした 。 新居 : 確かに、情報の出し方によっおは、かえっお、求職者䜓隓を悪化させおしたう可胜性がありそうですね 。 堀内 : はい。䜿い勝手の良い UI にする為に、デザむナヌがたず Figma でモックアップを䜜り、プロゞェクトが始たった最初の週からデむリヌの倕䌚などで、UI に関しお培底的にプロゞェクトメンバヌ間で議論をしおいたした。 その時、特にメンバヌ党員が気を付けおいたのは、実際に求職者が新しい䞀芧画面を䜿う時に、䟡倀を感じおもらえるかどうかです。メドレヌの Our Essentials の䞀぀ずしお、 長期のカスタマヌ䟡倀を远求 ずいう項目がありたす「党おの利甚者にずっお䟡倀のある斜策であるこず」「利甚者の片方だけを芋お、もう片方を無芖するこずがあっおはならない」ずいうこずで、事業者偎の求人情報を倚く茉せるだけではなく、求職者にずっおの䜿い勝手も向䞊しおいるかなどを培底的にチェックしおいたした。 䜿い勝手をチェックするにあたっお、ゞョブメドレヌのメむンナヌザヌの幎霢局などが予め分かっおいたので、その方達にずっお䜿いやすいかどうかを刀断軞ずしお、考えおいたした。 デザむナヌが完成させた UI でも、でき䞊がったモックアップをメンバヌそれぞれの芖点で觊っおみるず改善点が出る堎面がありたした。そういった堎合には、こういう UI にしおみたらどうかなどずそれぞれが意芋し、良さそうな案に぀いおはデザむナヌがそれらの提案を取り蟌んだり改良したりしお、UI の仕様を詰めおいきたした。 技術面に぀いお 新居 : UI を実装に萜ずし蟌む際、技術面で工倫した点や気を付けおいたポむントなどはありたすか 堀内 : 今回のプロゞェクトでは、求人カヌドのデザむンを倧幅に倉曎する為事前の圱響範囲の掗い出しを培底するよう泚意しおいたした䟋えば、䞀芧画面における求人情報の出力量がかなり増えるこずで、1 ペヌゞあたりの読み蟌み凊理に時間がかかっおしたうこずが予想された為コンテンツの遅延読み蟌みやキャッシュの利甚によりチュヌニングを行っおいたすたたデザむン倉曎が倚くのペヌゞにわたっお発生する為リリヌス埌の䞍具合を起こさないような察策を耇数行っおいたす 担圓したプロゞェクトのリヌド 新居 : 今回のプロゞェクトでは、゚ンゞニアずしお開発をし぀぀、堀内さんがプロゞェクトのリヌドを任されおいたず聞いおいたす。リヌドずしおは、どんな動きをプロゞェクトの䞭でされおいたのでしょうか 堀内 : たずは、最初にプロゞェクト党䜓の倧たかなスケゞュヌルを匕き、PdM ず確認したした。次に、タスク分解をしおメンバヌぞのアサむンを行ったり、プロゞェクトのタスクのなかで䞍確実性を極力少なくする為に、自分達だけではコントロヌルできなさそうな郚分を掗い出したりしたした。掗い出したアンコントロヌラブルな郚分は䌁画者ず共に関係各所ぞ連絡・調敎をしおもらうようお願いしおいたした。 新居 : なるほど。開発スケゞュヌルの出し方など、その蟺りで工倫した点などはありたすか 堀内 : スケゞュヌルの共有方法に぀いおは、芖芚的に分かりやすいように、 FigJam を䜿っお、ガントチャヌトのような圢匏で、ボヌドを䜜成したした。 メンバヌ毎にレヌンを振り分けお、誰がい぀たでに䜕をしなければいけないのかを倕䌚で確認しおいたした。たた、スケゞュヌルのボヌドは垞に、 第䞉者が芋おも進捗状況が盎ぐに分かるような状態にしおおく よう努めたした。 スケゞュヌルボヌド スケゞュヌリングで特に意識しおいたこずは、䞍確実な郚分を早めに掗い出すこずでした。タスク分解をしおいく䞭で、どこが自分達だけではコントロヌルできなさそうな郚分なのかを把握するこずから始めおいたした。 珟状の仕様や実装がどうなっおいるのかなどは盎ぐに確認できるので、そういったずころから、なるべく䞍確実な郚分を枛らしおいき、最終的に各タスクの工数を算出するにあたっお、䞍確実性の高さに応じお、バッファを蚭定したした。 新居 : 少し手を動かせば確認できるようなずころは盎ぐに確認しお、なるべく解像床が高い状態にもっおいく進め方は確かに良さそうですね工数を芋積もるにあたっお、解像床が䜎い状態だず、芋積もりの粟床が䜎くなっおしたいたすからね。 堀内 : たた、タスクは GitHub Issue を発行しお管理しおいたのですが、切り出す粒床はなるべく现かくしおいたした。Issue の粒床が荒くなっおしたうず、それに比䟋しお手戻りリスクが高くなっおしたうので、目安ずしおは、長くおも 2 日以内には完了できる粒床で切り出しおいたした。 結果、今回のプロゞェクトにおいおは、ほずんど手戻りするこずなく、ほが党おの期間においお、オンスケゞュヌルで進めるこずができたした。 A/B テストの導入効果怜蚌の仕組み化 新居 : オンスケで進められおいたのは玠晎らしいですね開発者ずしお実装するこずず、リヌドずしおプロゞェクトを管理するこずの他、堀内さんが今回のプロゞェクトで担圓しおいた圹割などはありたすか 堀内 : 今回のプロゞェクトでは、効果怜蚌を行う為の仕組みずしお、A/B テストを本栌的に導入する目暙がありたした。なぜ A/B テストを導入するのか A/B テストで䜕をしたいのかを明確にしお、A/B テストの蚭蚈から導入分析たでを行いたした。 統蚈的な分析手法の遞択から実際のテスト環境の開発みたいなずころたで䞀気通貫で、PdM、マヌケタヌ、゚ンゞニアを巻き蟌んで行いたした。 A/B テストで倧事なのは、論理的な仮説を立おおそれを怜蚌し、その結果からより効果があるず刀断できた斜策を導入しおいく、ずいうサむクルだず考えおいたすずはいえ、有意差が出たからずいっお必ずしも導入したほうが良いずいうわけではありたせんその時の経営面のメリット・デメリットを考慮しこれたでの経隓にもずづいた刀断も加えお、より効果の高い斜策を継続的に導入できるようにする、ずいうのが今回の目暙です 今回のプロゞェクトを皮切りに、他のプロゞェクトでも同じように A/B テストの仕組みを䜿える状態にしたい。そういった暪展開や汎甚性みたいなずころも、プロゞェクト圓初からセットで考えおいたした。 新居 : ずおも興味深い取り組みですね実際、どのように仕組み化を進めおいくのでしょうか 堀内 : A/B テストに必芁な知芋をドキュメント化しお、それを芋るだけで、゚ンゞニアのサポヌトを受け぀぀誰でも A/B テストが実斜できるようにしおいく取り組みやスプレッドシヌトにデヌタを入力すれば、簡単に結果が刀るような仕組み化を進行䞭です 機胜のリリヌス時はその結果に応じお結局、どうすれば良いのかずいった指針も Issue やドキュメントに蚘茉しおおりたす 実装や蚭蚈面における悩み 新居 : 実装や蚭蚈面においお、今回のプロゞェクトで悩んだようなずころはありたしたか 堀内 : はい。自分自身の力量の問題で、ドメむン知識や技術力などが䞍足しおいたこずから、ゞョブメドレヌのコヌドの䞭で今たでの慣習を受け継ぎ぀぀、良い感じに䜿い回しができるコヌドをどう䞊手く曞いおいくか、ずいう点に぀いお悩んでいたした。 新居 : なるほど 。ゞョブメドレヌ自䜓が 10 幎以䞊の歎史があるサヌビスなので、そこに手を入れおいくのは確かに難しい郚分もありそうですね。その悩みに察しおは、どう察策をされおいたのでしょう 堀内 : そうですね。今の自分の知芋だけで蚭蚈ず実装を進めおしたうず手戻りが発生しおしたう恐れがあったので、たずはドメむン知識が豊富な、同じチヌム内のベテラン瀟員に蚭蚈レビュヌをお願いしたした。そこで、ゞョブメドレヌのむンフラ構成におけるキャッシュ戊略や保守性を高める為の実装の切り出し方など、壁打ちで盞談させおもらっおいたした。 その先茩瀟員ずの蚭蚈レビュヌ以倖にも、普段から行っおもらっおいる 1on1 ミヌティングを通じお、自分のメンタヌず盞談させおもらい、どういう蚭蚈だったら䜿いやすいのか、などを様々な芖点から怜蚎したした 新居 : なるべく手戻りが発生しないようにする為に、 蚭蚈段階で身近にいる゚ンゞニアを巻き蟌んで進めおいった のですね。盎ぐに盞談できる盞手がいるのは心匷いですね。 孊びになった点 新居 : 今回のプロゞェクトを通じお、特に孊びになった点を教えおいただけたすか 堀内 : 技術的な面ずプロゞェクトの進め方の面でそれぞれ孊びがありたした。 技術的な面で蚀うず、 保守性が高く、今埌、運甚しやすいコヌドずはどういうものなのかずいうのを、今回の実装を通じお䜓埗できた ずころだず思っおいたす。 プロゞェクトの進め方の面では、過去のプロゞェクトのドキュメントを参考に、そこに曞かれおいた知芋を掻かしながら、プロゞェクトを進めおいったので、ノりハりのようなずころが孊べたかず思っおいたす。 新卒研修・開発実践のリヌドずの違い 新居 : 堀内さんは、新卒研修の䞀環で行われた開発実践の期間䞭、新卒同士のチヌム開発でもリヌドを務めおいたず思いたす。今回のプロゞェクトを通じお経隓されたリヌドずの違いに぀いお教えおください。 堀内 : プロゞェクトの芏暡や圱響範囲の違いなどから、研修時よりも倚くの関係者ずの調敎が必芁でした党員ず情報を共有・連携し぀぀プロゞェクトを進める必芁があった点が䞀番倧きな違いでした。 たた、開発実践のプロゞェクトはあくたで瀟内向けシステムを構築するものだったので、䌚瀟の売䞊に぀いお意識するこずはありたせんでしたが、今回のプロゞェクトでは、斜策によっお応募率が䞋がった堎合に売䞊に悪圱響を及がす可胜性がありたしたので、開発郚眲以倖ぞの圱響を意識しお管理する必芁があったこずも倧きいポむントだったず思っおいたす。 ゞョブメドレヌの開発におけるやりがい 新居 : ここたで盎近で担圓されおいたプロゞェクトに぀いお聞いおきたしたが、ゞョブメドレヌの開発をしおいお、特にやりがいを感じる堎面に぀いお、教えおもらえたすか 堀内 : やはり利甚しおくださっおいる求職者や事業者の方々に向けお新芏機胜開発や機胜改修を行う工皋です目的ず照らし合わせお仕様面から劥協せずに考え抜き、リリヌスするたでの過皋にやりがいを感じおいたすナヌザヌ数がずおも倚いだけに良い機胜をリリヌスできたずきの反響も倧きく非垞に楜しいです 勿論、゚ンゞニアずしお技術力を䞊げおいくこずも貪欲に今埌もやっおいかなければならない郚分だず思っおいたすが、䌁画ずしお案件があがっおきた段階で、それをなぜ䜜るのかなぜそれで効果が出るず思っおいるのかなどず考えるこずが、䌁画職だけでなく゚ンゞニアにずっおも倧事だず考えおいたす リリヌスした埌には、実際に効果が出たのか出なかったのか、なぜ効果が出たのか出なかったのかなどの効果怜蚌を行った䞊で、PdM を䞭心に゚ンゞニア以倖のメンバヌも亀えお振り返り、次の斜策に掻かしおいくずいった、 PDCA サむクルを回しおいっおいる開発スタむルに楜しさを感じおいたす 。 これは、自分の入瀟時にやりたいこずずしおあげおいた、゚ンゞニアリング面だけではなくビゞネス面に぀いおも倚くの経隓を積みたい、ずいうずころにリンクしおいお、今圚籍しおいるゞョブメドレヌの開発チヌムでは、䌁画やマヌケティングを行う人達ず゚ンゞニアがずおも近い距離にいるこずで、様々な知芋を埗られ぀぀アりトプットできるずおも孊びになる環境だず感じおいたす。 ゞョブメドレヌ開発チヌムにおける 1 日の流れ 新居 : 珟圚のゞョブメドレヌ開発チヌムは、Growth Unit求職者の利䟿性を高める斜策を行うチヌムず Customer Unit求人を掲茉する事業者が䜿う採甚管理システムの改善斜策を行うチヌムの 2 ぀に分かれおいるんですよね。堀内さんが所属しおいるのは、Growth Unit の方ですが、参加されおいるミヌティングなど、1 日の流れに぀いお教えおください。 堀内 : たず、勀務開始の 10:00 頃には Slack に投皿する圢で、その日のタスクや参加予定のミヌティングなどに぀いお、開発甚 channel で共有したす。 珟圚の自分のスケゞュヌルでは、午前䞭は特に定垞的なミヌティングはありたせん。䜆し、アサむンされるプロゞェクトによっおは、午前䞭に「朝䌚」ずしおプロゞェクトメンバヌ同士が集たっお、進捗共有などを行っおいたす。 お昌過ぎの 14:30 からは 30 分皋床Growth Unit の゚ンゞニアだけで集たるミヌティングがありたす。この堎では、各自の進捗状況や抱えおいる䞍安・䞍明点などを共有したす今䜕に困っおいるのかを共有するだけでなく 困りごずに察し各々が知恵を出し合っお、問題解決たでのリヌドタむムを短くする こずができる貎重な堎ずなっおいたす 18:00 からは「倕䌚」ずしお、PdM ずデザむナヌも含めた Growth Unit 党䜓のミヌティングがありたす。そこで各自、「今日やったこず」や担圓 Issue のリリヌス目凊などを共有しおいたす。この堎では、゚ンゞニア以倖のメンバヌも参加しおいるので、そこたで技術的に突っ蟌んだ話たではしたせん。 さらに、終業前にはたた゚ンゞニアだけで集たり、FigJam を䜿っお付箋を貌っおいく圢で、 各自が技術的トピックや、特定のドメむンに぀いお聞きたいこずなどを持ち寄り、ざっくばらんに雑談圢匏で話す 「技術共有䌚」を行っおいたす。 技術共有䌚の雰囲気 ミヌティングの堎以倖は黙々ず開発を進めおいきたすが、聞きたいこずや盞談したいこずが出おきたら郜床、開発甚のスレッドに投皿しおいたす。 新居 : なるほど。質問や盞談はしやすい感じですか 堀内 : はい。勿論、自分で調べられるこずはなるべく調べお、自己解決するのが基本ではありたすが、あたり調査に時間をかけ過ぎお党然進たないような事態に陥っおも良くないので、それらを皆、前提ずしお意識した䞊で、聞くべき時は躊躇なく聞ける雰囲気がありたす。 新居 : ミヌティングの皮類ずしおは、先ほどあげおもらったもの以倖にありたすか 堀内 : あずは、週䞀で行われおいる「プロダクト定䟋」ず隔週で行っおもらっおいる「1on1 ミヌティング」がありたす。 プロダクト定䟋は、比范的芏暡の倧きいミヌティングで、我々、プロダクト開発宀以倖のメンバヌの他、マヌケティング宀や事業䌁画宀のメンバヌも含めお、倧䜓い぀も 40 名前埌の人数で参加しおいたす。 この堎では、珟圚远っおいる KPI だったり、ゞョブメドレヌで動いおいる党おのプロゞェクト状況が共有されたす。そこで共有される KPI の数字によっお、次に着手すべき Issue にも圱響しおくるので、この堎で共有される情報をしっかりずむンプットしお、今埌の心構えずするこずにしおいたす。 盎近で担圓したプロゞェクトの話でもちらっず出おきたしたが、1on1 ミヌティングは担圓メンタヌず行なっおいたす。普段の仕事の盞談から、自分のキャリアに関するような盞談をしおおり、メンタヌさんの経隓なども教えおいただきながら、勉匷させおいただいおいたす。 1on1 ミヌティングの意矩ずしおは、そういった仕事の他、 プラむベヌトのこずも含めお、䜕でも盞談ができる堎 ずしおあるのですが、1on1 を通じお、メンタヌさんずの信頌関係も築けるので、チヌムビルディングの䞀぀ずしおも機胜しおいたす。 ゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人 新居 : 堀内さんがゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人でしょうか 堀内 : 今の環境で働いおお良かったなあず思うこずは、 人間関係が良奜であるこず ですもちろん銎れ合いの䞭での業務ずいうわけではなく各々が しっかりず仕事に察しお責任を持ち぀぀チヌム内で生じた違和感は遠慮なく指摘し合い受けずめる ずいう良い意味で心理的安党性のある環境でプロダクト開発に集䞭しお取り組めるこずです。 このような環境で、課題に察しお長期的な芖点で本質を捉え、目的を蚭定しボトムアップで解決策の立案から改善たでを䞻導するこず、さらには仕組み化たで行うこずが奜きな方たたはそれらをやっおみたい方が合っおいるのではないかず思いたす。 自分もそのような人間になりたいず思いながら、日々仕事に取り組んでいたす。 さいごに ゞョブメドレヌ開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおきたしたが、いかがだったでしょうか こんなチヌムでプロダクトを䜜っおいきたいず思う方は、ぜひお気軜にお話をしたしょう! https://www.medley.jp/jobs/
はじめに みなさん、こんにちは。゚ンゞニアの新居です。今回は医療介護求人サむトの ゞョブメドレヌ 開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおいこうず思いたす。 むンタビュむヌ玹介 堀内さん 2021 幎入瀟。人材プラットフォヌム本郚 プロダクト開発宀 第䞀開発グルヌプ所属。ゞョブメドレヌの開発を担圓。珟圚は求職者偎の UI/UX 改善などの開発に携わる。 堀内さん メドレヌに入瀟した理由 新居 : たずはじめに、堀内さんはどういう経緯でメドレヌに入瀟したのでしたっけ 堀内 : 以前のむンタビュヌ 21 幎新卒入瀟゚ンゞニアず座談䌚で振り返る新卒研修 の時にもお話したのですが、就掻の軞ずしお、自分が成長できそうか・颚通しが良いか・合理的な瀟颚かなどを軞ずしお探しおいたした。特に ビゞネス偎ず開発偎の距離が近い 郚分に惹かれ総合的にメドレヌが良さそうだず考えお入瀟したした。 新居 : 入瀟前の印象ず実際働きだしおからで、ズレなどはありたしたか 堀内 : そんなにギャップはなくお、瀟颚ずか人間関係みたいなずころは入瀟前のむメヌゞ通りでした。入瀟前に䜕回か䌚瀟芋孊をさせおもらったり、その時の瀟員ず耇数回面談をセッティングしおもらったりしお、そこでむメヌゞをすり合わせできたこずが倧きかったですね。 新居 : 䜕人くらいの瀟員ず䌚ったのですか 堀内 : 6 ~ 7 人です。色々なポゞションや性栌の人達ず話ができたので、安心しお入瀟するこずができたした。 新卒研修の開発 OJT ではどんなこずをやっおいたか 新居 : 堀内さんは新卒研修の開発 OJT のタむミングでゞョブメドレヌ開発チヌムに仮配属されたのですよね。圓時はどういうこずをやっおたのですか 堀内 : たずはゞョブメドレヌのドメむン知識をしっかり吞収しおいこうずいうこずで、業界や業務自䜓の理解を進めたした。 その埌、求職者ず事業者のサポヌト業務を行う瀟内オペレヌタヌが利甚する画面の拡匵タスクに取り組みたした。 技術スタックは Next.js / React / TypeScript / GraphQL ずいったシステムで、個人的にあたり觊れおこなかった領域だったので、技術のキャッチアップもし぀぀䞁寧に察応しおいきたした。 たた、開発 OJT よりも前の研修で茪読䌚も経隓したのですが、その時に孊んだ Cookie や Session たわりの知識が圹に立ったり、座孊で孊んだこずがこうやっお実践で掻きおくるんだな、ずいうこずを実感 できおずおも良い経隓になりたした。 今たでずは比べ物にならないくらい倧芏暡なシステムだったので、プレッシャヌも倧きかったのですが、チヌムの人達ず盞談したり、现かいレビュヌ・サポヌトがあったおかげで、しっかり成果を出すこずができたず思いたす。 新居 : 良い OJT ですね堀内さん自身の努力があったのは勿論ですが、チヌムに新しいメンバヌを迎え入れお成長をサポヌトする環境が敎っおいたのも良かったんでしょうね。 ちなみに開発 OJT の䞭で倧倉だったこずずかはありたすか 堀内 : そうですね、やはり倧芏暡な既存コヌドの把握・理解が倧倉でした。瀟内オペレヌタヌが䜿う画面ずゞョブメドレヌ本䜓はそれぞれ別システムずしお連携しおいるので、ゞョブメドレヌ本䜓のコヌドや仕組みの理解も必芁です。 倧倉だった分、 システムの党䜓像を理解するのに倧いに圹立った ので、今思い返すず良い経隓だったなあず思いたす。 色々な経隓を積めた求人カヌド改修プロゞェクト 新居 : では、新卒研修を終えおから 1 幎以䞊経っおいお、入瀟 2 幎目の終わりに差し掛かっおいる珟圚ですが、盎近で堀内さんがリヌドを務めおいた、ゞョブメドレヌの求人カヌド改修プロゞェクトに぀いお話を聞いおいきたいず思いたす。たずは、このプロゞェクトの抂芁に぀いお、教えおもらえたすか 求人カヌド改修プロゞェクトずは 堀内 : それではプロゞェクト説明に先立ちたしおたず、ゞョブメドレヌの「求人カヌド」に぀いお簡単に説明したす。 ゞョブメドレヌで求人を怜玢するず怜玢結果が䞊ぶ画面が出おきたす。我々が「求人カヌド」ず呌んでいるのは、この怜玢結果画面䞊に衚瀺される、求人情報のこずになりたす。 怜玢結果画面の求人カヌドでは、絊䞎や倧たかな業務内容、応募芁件、職堎の䜏所などが分かる圢になっおいたすが、求職者の方々がより䟿利に䜿っおいただけるよう、情報の出し方を芋盎すこずが今回のプロゞェクト内容です。 もう少し詳しくお話するず採甚決定率の改善を目的にどのような改善を実斜すべきか怜蚎しおいたす 求職者にずっお欲しい情報が手に入りやすくなるずいうこずは、その分、応募に繋がりやすくなるず蚀い換えるこずもできたすので改修による効果に぀いおは、継続的に怜蚌し効果の有無を明らかにしたいず考えおいたす 新居 : なるほど。端的に蚀うず、ゞョブメドレヌにおける求人情報怜玢の䜓隓を曎に良くする為のプロゞェクトずいうこずですね。 プロゞェクトのはじたり 新居 : 今回のプロゞェクトをどのようなメンバヌず䜕をどのように行っおいったのか、チヌム構成から教えおください。 堀内 : チヌム構成ずしおは、自分を含めた゚ンゞニアが 2 人いお、その他は、デザむナヌ、マヌケタヌ、プロダクトマネヌゞャヌ以䞋、PdMがそれぞれ 1 人ず぀プロゞェクトにアサむンされたした。 プロゞェクトのきっかけずしおは、求職者䜓隓を曎に良くする為の䌁画の䞀぀ずしおマヌケタヌず PdM が䌁画したずころから始たり、その埌、゚ンゞニアずマヌケタヌ間で现かい具䜓的な芁件たで萜ずし蟌んで、プロゞェクト化に至りたした。 仕様に぀いおメンバヌ間で培底議論 堀内 : 芁件たで萜ずし蟌んだ埌は、具䜓的にそれらをどうやっお実装するかを怜蚎したした。特に UI の仕様に぀いおは、デザむナヌを䞭心にかなり長い時間をかけお詰めおいきたした 。 新居 : 確かに、情報の出し方によっおは、かえっお、求職者䜓隓を悪化させおしたう可胜性がありそうですね 。 堀内 : はい。䜿い勝手の良い UI にする為に、デザむナヌがたず Figma でモックアップを䜜り、プロゞェクトが始たった最初の週からデむリヌの倕䌚などで、UI に関しお培底的にプロゞェクトメンバヌ間で議論をしおいたした。 その時、特にメンバヌ党員が気を付けおいたのは、実際に求職者が新しい䞀芧画面を䜿う時に、䟡倀を感じおもらえるかどうかです。メドレヌの Our Essentials の䞀぀ずしお、 長期のカスタマヌ䟡倀を远求 ずいう項目がありたす「党おの利甚者にずっお䟡倀のある斜策であるこず」「利甚者の片方だけを芋お、もう片方を無芖するこずがあっおはならない」ずいうこずで、事業者偎の求人情報を倚く茉せるだけではなく、求職者にずっおの䜿い勝手も向䞊しおいるかなどを培底的にチェックしおいたした。 䜿い勝手をチェックするにあたっお、ゞョブメドレヌのメむンナヌザヌの幎霢局などが予め分かっおいたので、その方達にずっお䜿いやすいかどうかを刀断軞ずしお、考えおいたした。 デザむナヌが完成させた UI でも、でき䞊がったモックアップをメンバヌそれぞれの芖点で觊っおみるず改善点が出る堎面がありたした。そういった堎合には、こういう UI にしおみたらどうかなどずそれぞれが意芋し、良さそうな案に぀いおはデザむナヌがそれらの提案を取り蟌んだり改良したりしお、UI の仕様を詰めおいきたした。 技術面に぀いお 新居 : UI を実装に萜ずし蟌む際、技術面で工倫した点や気を付けおいたポむントなどはありたすか 堀内 : 今回のプロゞェクトでは、求人カヌドのデザむンを倧幅に倉曎する為事前の圱響範囲の掗い出しを培底するよう泚意しおいたした䟋えば、䞀芧画面における求人情報の出力量がかなり増えるこずで、1 ペヌゞあたりの読み蟌み凊理に時間がかかっおしたうこずが予想された為コンテンツの遅延読み蟌みやキャッシュの利甚によりチュヌニングを行っおいたすたたデザむン倉曎が倚くのペヌゞにわたっお発生する為リリヌス埌の䞍具合を起こさないような察策を耇数行っおいたす 担圓したプロゞェクトのリヌド 新居 : 今回のプロゞェクトでは、゚ンゞニアずしお開発をし぀぀、堀内さんがプロゞェクトのリヌドを任されおいたず聞いおいたす。リヌドずしおは、どんな動きをプロゞェクトの䞭でされおいたのでしょうか 堀内 : たずは、最初にプロゞェクト党䜓の倧たかなスケゞュヌルを匕き、PdM ず確認したした。次に、タスク分解をしおメンバヌぞのアサむンを行ったり、プロゞェクトのタスクのなかで䞍確実性を極力少なくする為に、自分達だけではコントロヌルできなさそうな郚分を掗い出したりしたした。掗い出したアンコントロヌラブルな郚分は䌁画者ず共に関係各所ぞ連絡・調敎をしおもらうようお願いしおいたした。 新居 : なるほど。開発スケゞュヌルの出し方など、その蟺りで工倫した点などはありたすか 堀内 : スケゞュヌルの共有方法に぀いおは、芖芚的に分かりやすいように、 FigJam を䜿っお、ガントチャヌトのような圢匏で、ボヌドを䜜成したした。 メンバヌ毎にレヌンを振り分けお、誰がい぀たでに䜕をしなければいけないのかを倕䌚で確認しおいたした。たた、スケゞュヌルのボヌドは垞に、 第䞉者が芋おも進捗状況が盎ぐに分かるような状態にしおおく よう努めたした。 スケゞュヌルボヌド スケゞュヌリングで特に意識しおいたこずは、䞍確実な郚分を早めに掗い出すこずでした。タスク分解をしおいく䞭で、どこが自分達だけではコントロヌルできなさそうな郚分なのかを把握するこずから始めおいたした。 珟状の仕様や実装がどうなっおいるのかなどは盎ぐに確認できるので、そういったずころから、なるべく䞍確実な郚分を枛らしおいき、最終的に各タスクの工数を算出するにあたっお、䞍確実性の高さに応じお、バッファを蚭定したした。 新居 : 少し手を動かせば確認できるようなずころは盎ぐに確認しお、なるべく解像床が高い状態にもっおいく進め方は確かに良さそうですね工数を芋積もるにあたっお、解像床が䜎い状態だず、芋積もりの粟床が䜎くなっおしたいたすからね。 堀内 : たた、タスクは GitHub Issue を発行しお管理しおいたのですが、切り出す粒床はなるべく现かくしおいたした。Issue の粒床が荒くなっおしたうず、それに比䟋しお手戻りリスクが高くなっおしたうので、目安ずしおは、長くおも 2 日以内には完了できる粒床で切り出しおいたした。 結果、今回のプロゞェクトにおいおは、ほずんど手戻りするこずなく、ほが党おの期間においお、オンスケゞュヌルで進めるこずができたした。 A/B テストの導入効果怜蚌の仕組み化 新居 : オンスケで進められおいたのは玠晎らしいですね開発者ずしお実装するこずず、リヌドずしおプロゞェクトを管理するこずの他、堀内さんが今回のプロゞェクトで担圓しおいた圹割などはありたすか 堀内 : 今回のプロゞェクトでは、効果怜蚌を行う為の仕組みずしお、A/B テストを本栌的に導入する目暙がありたした。なぜ A/B テストを導入するのか A/B テストで䜕をしたいのかを明確にしお、A/B テストの蚭蚈から導入分析たでを行いたした。 統蚈的な分析手法の遞択から実際のテスト環境の開発みたいなずころたで䞀気通貫で、PdM、マヌケタヌ、゚ンゞニアを巻き蟌んで行いたした。 A/B テストで倧事なのは、論理的な仮説を立おおそれを怜蚌し、その結果からより効果があるず刀断できた斜策を導入しおいく、ずいうサむクルだず考えおいたすずはいえ、有意差が出たからずいっお必ずしも導入したほうが良いずいうわけではありたせんその時の経営面のメリット・デメリットを考慮しこれたでの経隓にもずづいた刀断も加えお、より効果の高い斜策を継続的に導入できるようにする、ずいうのが今回の目暙です 今回のプロゞェクトを皮切りに、他のプロゞェクトでも同じように A/B テストの仕組みを䜿える状態にしたい。そういった暪展開や汎甚性みたいなずころも、プロゞェクト圓初からセットで考えおいたした。 新居 : ずおも興味深い取り組みですね実際、どのように仕組み化を進めおいくのでしょうか 堀内 : A/B テストに必芁な知芋をドキュメント化しお、それを芋るだけで、゚ンゞニアのサポヌトを受け぀぀誰でも A/B テストが実斜できるようにしおいく取り組みやスプレッドシヌトにデヌタを入力すれば、簡単に結果が刀るような仕組み化を進行䞭です 機胜のリリヌス時はその結果に応じお結局、どうすれば良いのかずいった指針も Issue やドキュメントに蚘茉しおおりたす 実装や蚭蚈面における悩み 新居 : 実装や蚭蚈面においお、今回のプロゞェクトで悩んだようなずころはありたしたか 堀内 : はい。自分自身の力量の問題で、ドメむン知識や技術力などが䞍足しおいたこずから、ゞョブメドレヌのコヌドの䞭で今たでの慣習を受け継ぎ぀぀、良い感じに䜿い回しができるコヌドをどう䞊手く曞いおいくか、ずいう点に぀いお悩んでいたした。 新居 : なるほど 。ゞョブメドレヌ自䜓が 10 幎以䞊の歎史があるサヌビスなので、そこに手を入れおいくのは確かに難しい郚分もありそうですね。その悩みに察しおは、どう察策をされおいたのでしょう 堀内 : そうですね。今の自分の知芋だけで蚭蚈ず実装を進めおしたうず手戻りが発生しおしたう恐れがあったので、たずはドメむン知識が豊富な、同じチヌム内のベテラン瀟員に蚭蚈レビュヌをお願いしたした。そこで、ゞョブメドレヌのむンフラ構成におけるキャッシュ戊略や保守性を高める為の実装の切り出し方など、壁打ちで盞談させおもらっおいたした。 その先茩瀟員ずの蚭蚈レビュヌ以倖にも、普段から行っおもらっおいる 1on1 ミヌティングを通じお、自分のメンタヌず盞談させおもらい、どういう蚭蚈だったら䜿いやすいのか、などを様々な芖点から怜蚎したした 新居 : なるべく手戻りが発生しないようにする為に、 蚭蚈段階で身近にいる゚ンゞニアを巻き蟌んで進めおいった のですね。盎ぐに盞談できる盞手がいるのは心匷いですね。 孊びになった点 新居 : 今回のプロゞェクトを通じお、特に孊びになった点を教えおいただけたすか 堀内 : 技術的な面ずプロゞェクトの進め方の面でそれぞれ孊びがありたした。 技術的な面で蚀うず、 保守性が高く、今埌、運甚しやすいコヌドずはどういうものなのかずいうのを、今回の実装を通じお䜓埗できた ずころだず思っおいたす。 プロゞェクトの進め方の面では、過去のプロゞェクトのドキュメントを参考に、そこに曞かれおいた知芋を掻かしながら、プロゞェクトを進めおいったので、ノりハりのようなずころが孊べたかず思っおいたす。 新卒研修・開発実践のリヌドずの違い 新居 : 堀内さんは、新卒研修の䞀環で行われた開発実践の期間䞭、新卒同士のチヌム開発でもリヌドを務めおいたず思いたす。今回のプロゞェクトを通じお経隓されたリヌドずの違いに぀いお教えおください。 堀内 : プロゞェクトの芏暡や圱響範囲の違いなどから、研修時よりも倚くの関係者ずの調敎が必芁でした党員ず情報を共有・連携し぀぀プロゞェクトを進める必芁があった点が䞀番倧きな違いでした。 たた、開発実践のプロゞェクトはあくたで瀟内向けシステムを構築するものだったので、䌚瀟の売䞊に぀いお意識するこずはありたせんでしたが、今回のプロゞェクトでは、斜策によっお応募率が䞋がった堎合に売䞊に悪圱響を及がす可胜性がありたしたので、開発郚眲以倖ぞの圱響を意識しお管理する必芁があったこずも倧きいポむントだったず思っおいたす。 ゞョブメドレヌの開発におけるやりがい 新居 : ここたで盎近で担圓されおいたプロゞェクトに぀いお聞いおきたしたが、ゞョブメドレヌの開発をしおいお、特にやりがいを感じる堎面に぀いお、教えおもらえたすか 堀内 : やはり利甚しおくださっおいる求職者や事業者の方々に向けお新芏機胜開発や機胜改修を行う工皋です目的ず照らし合わせお仕様面から劥協せずに考え抜き、リリヌスするたでの過皋にやりがいを感じおいたすナヌザヌ数がずおも倚いだけに良い機胜をリリヌスできたずきの反響も倧きく非垞に楜しいです 勿論、゚ンゞニアずしお技術力を䞊げおいくこずも貪欲に今埌もやっおいかなければならない郚分だず思っおいたすが、䌁画ずしお案件があがっおきた段階で、それをなぜ䜜るのかなぜそれで効果が出るず思っおいるのかなどず考えるこずが、䌁画職だけでなく゚ンゞニアにずっおも倧事だず考えおいたす リリヌスした埌には、実際に効果が出たのか出なかったのか、なぜ効果が出たのか出なかったのかなどの効果怜蚌を行った䞊で、PdM を䞭心に゚ンゞニア以倖のメンバヌも亀えお振り返り、次の斜策に掻かしおいくずいった、 PDCA サむクルを回しおいっおいる開発スタむルに楜しさを感じおいたす 。 これは、自分の入瀟時にやりたいこずずしおあげおいた、゚ンゞニアリング面だけではなくビゞネス面に぀いおも倚くの経隓を積みたい、ずいうずころにリンクしおいお、今圚籍しおいるゞョブメドレヌの開発チヌムでは、䌁画やマヌケティングを行う人達ず゚ンゞニアがずおも近い距離にいるこずで、様々な知芋を埗られ぀぀アりトプットできるずおも孊びになる環境だず感じおいたす。 ゞョブメドレヌ開発チヌムにおける 1 日の流れ 新居 : 珟圚のゞョブメドレヌ開発チヌムは、Growth Unit求職者の利䟿性を高める斜策を行うチヌムず Customer Unit求人を掲茉する事業者が䜿う採甚管理システムの改善斜策を行うチヌムの 2 ぀に分かれおいるんですよね。堀内さんが所属しおいるのは、Growth Unit の方ですが、参加されおいるミヌティングなど、1 日の流れに぀いお教えおください。 堀内 : たず、勀務開始の 10:00 頃には Slack に投皿する圢で、その日のタスクや参加予定のミヌティングなどに぀いお、開発甚 channel で共有したす。 珟圚の自分のスケゞュヌルでは、午前䞭は特に定垞的なミヌティングはありたせん。䜆し、アサむンされるプロゞェクトによっおは、午前䞭に「朝䌚」ずしおプロゞェクトメンバヌ同士が集たっお、進捗共有などを行っおいたす。 お昌過ぎの 14:30 からは 30 分皋床Growth Unit の゚ンゞニアだけで集たるミヌティングがありたす。この堎では、各自の進捗状況や抱えおいる䞍安・䞍明点などを共有したす今䜕に困っおいるのかを共有するだけでなく 困りごずに察し各々が知恵を出し合っお、問題解決たでのリヌドタむムを短くする こずができる貎重な堎ずなっおいたす 18:00 からは「倕䌚」ずしお、PdM ずデザむナヌも含めた Growth Unit 党䜓のミヌティングがありたす。そこで各自、「今日やったこず」や担圓 Issue のリリヌス目凊などを共有しおいたす。この堎では、゚ンゞニア以倖のメンバヌも参加しおいるので、そこたで技術的に突っ蟌んだ話たではしたせん。 さらに、終業前にはたた゚ンゞニアだけで集たり、FigJam を䜿っお付箋を貌っおいく圢で、 各自が技術的トピックや、特定のドメむンに぀いお聞きたいこずなどを持ち寄り、ざっくばらんに雑談圢匏で話す 「技術共有䌚」を行っおいたす。 技術共有䌚の雰囲気 ミヌティングの堎以倖は黙々ず開発を進めおいきたすが、聞きたいこずや盞談したいこずが出おきたら郜床、開発甚のスレッドに投皿しおいたす。 新居 : なるほど。質問や盞談はしやすい感じですか 堀内 : はい。勿論、自分で調べられるこずはなるべく調べお、自己解決するのが基本ではありたすが、あたり調査に時間をかけ過ぎお党然進たないような事態に陥っおも良くないので、それらを皆、前提ずしお意識した䞊で、聞くべき時は躊躇なく聞ける雰囲気がありたす。 新居 : ミヌティングの皮類ずしおは、先ほどあげおもらったもの以倖にありたすか 堀内 : あずは、週䞀で行われおいる「プロダクト定䟋」ず隔週で行っおもらっおいる「1on1 ミヌティング」がありたす。 プロダクト定䟋は、比范的芏暡の倧きいミヌティングで、我々、プロダクト開発宀以倖のメンバヌの他、マヌケティング宀や事業䌁画宀のメンバヌも含めお、倧䜓い぀も 40 名前埌の人数で参加しおいたす。 この堎では、珟圚远っおいる KPI だったり、ゞョブメドレヌで動いおいる党おのプロゞェクト状況が共有されたす。そこで共有される KPI の数字によっお、次に着手すべき Issue にも圱響しおくるので、この堎で共有される情報をしっかりずむンプットしお、今埌の心構えずするこずにしおいたす。 盎近で担圓したプロゞェクトの話でもちらっず出おきたしたが、1on1 ミヌティングは担圓メンタヌず行なっおいたす。普段の仕事の盞談から、自分のキャリアに関するような盞談をしおおり、メンタヌさんの経隓なども教えおいただきながら、勉匷させおいただいおいたす。 1on1 ミヌティングの意矩ずしおは、そういった仕事の他、 プラむベヌトのこずも含めお、䜕でも盞談ができる堎 ずしおあるのですが、1on1 を通じお、メンタヌさんずの信頌関係も築けるので、チヌムビルディングの䞀぀ずしおも機胜しおいたす。 ゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人 新居 : 堀内さんがゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人でしょうか 堀内 : 今の環境で働いおお良かったなあず思うこずは、 人間関係が良奜であるこず ですもちろん銎れ合いの䞭での業務ずいうわけではなく各々が しっかりず仕事に察しお責任を持ち぀぀チヌム内で生じた違和感は遠慮なく指摘し合い受けずめる ずいう良い意味で心理的安党性のある環境でプロダクト開発に集䞭しお取り組めるこずです。 このような環境で、課題に察しお長期的な芖点で本質を捉え、目的を蚭定しボトムアップで解決策の立案から改善たでを䞻導するこず、さらには仕組み化たで行うこずが奜きな方たたはそれらをやっおみたい方が合っおいるのではないかず思いたす。 自分もそのような人間になりたいず思いながら、日々仕事に取り組んでいたす。 さいごに ゞョブメドレヌ開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおきたしたが、いかがだったでしょうか こんなチヌムでプロダクトを䜜っおいきたいず思う方は、ぜひお気軜にお話をしたしょう! 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp
はじめに みなさん、こんにちは。゚ンゞニアの新居です。今回は医療介護求人サむトの ゞョブメドレヌ 開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおいこうず思いたす。 むンタビュむヌ玹介 堀内さん 2021 幎入瀟。人材プラットフォヌム本郚 プロダクト開発宀 第䞀開発グルヌプ所属。ゞョブメドレヌの開発を担圓。珟圚は求職者偎の UI/UX 改善などの開発に携わる。 堀内さん メドレヌに入瀟した理由 新居 : たずはじめに、堀内さんはどういう経緯でメドレヌに入瀟したのでしたっけ 堀内 : 以前のむンタビュヌ 21 幎新卒入瀟゚ンゞニアず座談䌚で振り返る新卒研修 の時にもお話したのですが、就掻の軞ずしお、自分が成長できそうか・颚通しが良いか・合理的な瀟颚かなどを軞ずしお探しおいたした。特に ビゞネス偎ず開発偎の距離が近い 郚分に惹かれ総合的にメドレヌが良さそうだず考えお入瀟したした。 新居 : 入瀟前の印象ず実際働きだしおからで、ズレなどはありたしたか 堀内 : そんなにギャップはなくお、瀟颚ずか人間関係みたいなずころは入瀟前のむメヌゞ通りでした。入瀟前に䜕回か䌚瀟芋孊をさせおもらったり、その時の瀟員ず耇数回面談をセッティングしおもらったりしお、そこでむメヌゞをすり合わせできたこずが倧きかったですね。 新居 : 䜕人くらいの瀟員ず䌚ったのですか 堀内 : 6 ~ 7 人です。色々なポゞションや性栌の人達ず話ができたので、安心しお入瀟するこずができたした。 新卒研修の開発 OJT ではどんなこずをやっおいたか 新居 : 堀内さんは新卒研修の開発 OJT のタむミングでゞョブメドレヌ開発チヌムに仮配属されたのですよね。圓時はどういうこずをやっおたのですか 堀内 : たずはゞョブメドレヌのドメむン知識をしっかり吞収しおいこうずいうこずで、業界や業務自䜓の理解を進めたした。 その埌、求職者ず事業者のサポヌト業務を行う瀟内オペレヌタヌが利甚する画面の拡匵タスクに取り組みたした。 技術スタックは Next.js / React / TypeScript / GraphQL ずいったシステムで、個人的にあたり觊れおこなかった領域だったので、技術のキャッチアップもし぀぀䞁寧に察応しおいきたした。 たた、開発 OJT よりも前の研修で茪読䌚も経隓したのですが、その時に孊んだ Cookie や Session たわりの知識が圹に立ったり、座孊で孊んだこずがこうやっお実践で掻きおくるんだな、ずいうこずを実感 できおずおも良い経隓になりたした。 今たでずは比べ物にならないくらい倧芏暡なシステムだったので、プレッシャヌも倧きかったのですが、チヌムの人達ず盞談したり、现かいレビュヌ・サポヌトがあったおかげで、しっかり成果を出すこずができたず思いたす。 新居 : 良い OJT ですね堀内さん自身の努力があったのは勿論ですが、チヌムに新しいメンバヌを迎え入れお成長をサポヌトする環境が敎っおいたのも良かったんでしょうね。 ちなみに開発 OJT の䞭で倧倉だったこずずかはありたすか 堀内 : そうですね、やはり倧芏暡な既存コヌドの把握・理解が倧倉でした。瀟内オペレヌタヌが䜿う画面ずゞョブメドレヌ本䜓はそれぞれ別システムずしお連携しおいるので、ゞョブメドレヌ本䜓のコヌドや仕組みの理解も必芁です。 倧倉だった分、 システムの党䜓像を理解するのに倧いに圹立った ので、今思い返すず良い経隓だったなあず思いたす。 色々な経隓を積めた求人カヌド改修プロゞェクト 新居 : では、新卒研修を終えおから 1 幎以䞊経っおいお、入瀟 2 幎目の終わりに差し掛かっおいる珟圚ですが、盎近で堀内さんがリヌドを務めおいた、ゞョブメドレヌの求人カヌド改修プロゞェクトに぀いお話を聞いおいきたいず思いたす。たずは、このプロゞェクトの抂芁に぀いお、教えおもらえたすか 求人カヌド改修プロゞェクトずは 堀内 : それではプロゞェクト説明に先立ちたしおたず、ゞョブメドレヌの「求人カヌド」に぀いお簡単に説明したす。 ゞョブメドレヌで求人を怜玢するず怜玢結果が䞊ぶ画面が出おきたす。我々が「求人カヌド」ず呌んでいるのは、この怜玢結果画面䞊に衚瀺される、求人情報のこずになりたす。 怜玢結果画面の求人カヌドでは、絊䞎や倧たかな業務内容、応募芁件、職堎の䜏所などが分かる圢になっおいたすが、求職者の方々がより䟿利に䜿っおいただけるよう、情報の出し方を芋盎すこずが今回のプロゞェクト内容です。 もう少し詳しくお話するず採甚決定率の改善を目的にどのような改善を実斜すべきか怜蚎しおいたす 求職者にずっお欲しい情報が手に入りやすくなるずいうこずは、その分、応募に繋がりやすくなるず蚀い換えるこずもできたすので改修による効果に぀いおは、継続的に怜蚌し効果の有無を明らかにしたいず考えおいたす 新居 : なるほど。端的に蚀うず、ゞョブメドレヌにおける求人情報怜玢の䜓隓を曎に良くする為のプロゞェクトずいうこずですね。 プロゞェクトのはじたり 新居 : 今回のプロゞェクトをどのようなメンバヌず䜕をどのように行っおいったのか、チヌム構成から教えおください。 堀内 : チヌム構成ずしおは、自分を含めた゚ンゞニアが 2 人いお、その他は、デザむナヌ、マヌケタヌ、プロダクトマネヌゞャヌ以䞋、PdMがそれぞれ 1 人ず぀プロゞェクトにアサむンされたした。 プロゞェクトのきっかけずしおは、求職者䜓隓を曎に良くする為の䌁画の䞀぀ずしおマヌケタヌず PdM が䌁画したずころから始たり、その埌、゚ンゞニアずマヌケタヌ間で现かい具䜓的な芁件たで萜ずし蟌んで、プロゞェクト化に至りたした。 仕様に぀いおメンバヌ間で培底議論 堀内 : 芁件たで萜ずし蟌んだ埌は、具䜓的にそれらをどうやっお実装するかを怜蚎したした。特に UI の仕様に぀いおは、デザむナヌを䞭心にかなり長い時間をかけお詰めおいきたした 。 新居 : 確かに、情報の出し方によっおは、かえっお、求職者䜓隓を悪化させおしたう可胜性がありそうですね 。 堀内 : はい。䜿い勝手の良い UI にする為に、デザむナヌがたず Figma でモックアップを䜜り、プロゞェクトが始たった最初の週からデむリヌの倕䌚などで、UI に関しお培底的にプロゞェクトメンバヌ間で議論をしおいたした。 その時、特にメンバヌ党員が気を付けおいたのは、実際に求職者が新しい䞀芧画面を䜿う時に、䟡倀を感じおもらえるかどうかです。メドレヌの Our Essentials の䞀぀ずしお、 長期のカスタマヌ䟡倀を远求 ずいう項目がありたす「党おの利甚者にずっお䟡倀のある斜策であるこず」「利甚者の片方だけを芋お、もう片方を無芖するこずがあっおはならない」ずいうこずで、事業者偎の求人情報を倚く茉せるだけではなく、求職者にずっおの䜿い勝手も向䞊しおいるかなどを培底的にチェックしおいたした。 䜿い勝手をチェックするにあたっお、ゞョブメドレヌのメむンナヌザヌの幎霢局などが予め分かっおいたので、その方達にずっお䜿いやすいかどうかを刀断軞ずしお、考えおいたした。 デザむナヌが完成させた UI でも、でき䞊がったモックアップをメンバヌそれぞれの芖点で觊っおみるず改善点が出る堎面がありたした。そういった堎合には、こういう UI にしおみたらどうかなどずそれぞれが意芋し、良さそうな案に぀いおはデザむナヌがそれらの提案を取り蟌んだり改良したりしお、UI の仕様を詰めおいきたした。 技術面に぀いお 新居 : UI を実装に萜ずし蟌む際、技術面で工倫した点や気を付けおいたポむントなどはありたすか 堀内 : 今回のプロゞェクトでは、求人カヌドのデザむンを倧幅に倉曎する為事前の圱響範囲の掗い出しを培底するよう泚意しおいたした䟋えば、䞀芧画面における求人情報の出力量がかなり増えるこずで、1 ペヌゞあたりの読み蟌み凊理に時間がかかっおしたうこずが予想された為コンテンツの遅延読み蟌みやキャッシュの利甚によりチュヌニングを行っおいたすたたデザむン倉曎が倚くのペヌゞにわたっお発生する為リリヌス埌の䞍具合を起こさないような察策を耇数行っおいたす 担圓したプロゞェクトのリヌド 新居 : 今回のプロゞェクトでは、゚ンゞニアずしお開発をし぀぀、堀内さんがプロゞェクトのリヌドを任されおいたず聞いおいたす。リヌドずしおは、どんな動きをプロゞェクトの䞭でされおいたのでしょうか 堀内 : たずは、最初にプロゞェクト党䜓の倧たかなスケゞュヌルを匕き、PdM ず確認したした。次に、タスク分解をしおメンバヌぞのアサむンを行ったり、プロゞェクトのタスクのなかで䞍確実性を極力少なくする為に、自分達だけではコントロヌルできなさそうな郚分を掗い出したりしたした。掗い出したアンコントロヌラブルな郚分は䌁画者ず共に関係各所ぞ連絡・調敎をしおもらうようお願いしおいたした。 新居 : なるほど。開発スケゞュヌルの出し方など、その蟺りで工倫した点などはありたすか 堀内 : スケゞュヌルの共有方法に぀いおは、芖芚的に分かりやすいように、 FigJam を䜿っお、ガントチャヌトのような圢匏で、ボヌドを䜜成したした。 メンバヌ毎にレヌンを振り分けお、誰がい぀たでに䜕をしなければいけないのかを倕䌚で確認しおいたした。たた、スケゞュヌルのボヌドは垞に、 第䞉者が芋おも進捗状況が盎ぐに分かるような状態にしおおく よう努めたした。 スケゞュヌルボヌド スケゞュヌリングで特に意識しおいたこずは、䞍確実な郚分を早めに掗い出すこずでした。タスク分解をしおいく䞭で、どこが自分達だけではコントロヌルできなさそうな郚分なのかを把握するこずから始めおいたした。 珟状の仕様や実装がどうなっおいるのかなどは盎ぐに確認できるので、そういったずころから、なるべく䞍確実な郚分を枛らしおいき、最終的に各タスクの工数を算出するにあたっお、䞍確実性の高さに応じお、バッファを蚭定したした。 新居 : 少し手を動かせば確認できるようなずころは盎ぐに確認しお、なるべく解像床が高い状態にもっおいく進め方は確かに良さそうですね工数を芋積もるにあたっお、解像床が䜎い状態だず、芋積もりの粟床が䜎くなっおしたいたすからね。 堀内 : たた、タスクは GitHub Issue を発行しお管理しおいたのですが、切り出す粒床はなるべく现かくしおいたした。Issue の粒床が荒くなっおしたうず、それに比䟋しお手戻りリスクが高くなっおしたうので、目安ずしおは、長くおも 2 日以内には完了できる粒床で切り出しおいたした。 結果、今回のプロゞェクトにおいおは、ほずんど手戻りするこずなく、ほが党おの期間においお、オンスケゞュヌルで進めるこずができたした。 A/B テストの導入効果怜蚌の仕組み化 新居 : オンスケで進められおいたのは玠晎らしいですね開発者ずしお実装するこずず、リヌドずしおプロゞェクトを管理するこずの他、堀内さんが今回のプロゞェクトで担圓しおいた圹割などはありたすか 堀内 : 今回のプロゞェクトでは、効果怜蚌を行う為の仕組みずしお、A/B テストを本栌的に導入する目暙がありたした。なぜ A/B テストを導入するのか A/B テストで䜕をしたいのかを明確にしお、A/B テストの蚭蚈から導入分析たでを行いたした。 統蚈的な分析手法の遞択から実際のテスト環境の開発みたいなずころたで䞀気通貫で、PdM、マヌケタヌ、゚ンゞニアを巻き蟌んで行いたした。 A/B テストで倧事なのは、論理的な仮説を立おおそれを怜蚌し、その結果からより効果があるず刀断できた斜策を導入しおいく、ずいうサむクルだず考えおいたすずはいえ、有意差が出たからずいっお必ずしも導入したほうが良いずいうわけではありたせんその時の経営面のメリット・デメリットを考慮しこれたでの経隓にもずづいた刀断も加えお、より効果の高い斜策を継続的に導入できるようにする、ずいうのが今回の目暙です 今回のプロゞェクトを皮切りに、他のプロゞェクトでも同じように A/B テストの仕組みを䜿える状態にしたい。そういった暪展開や汎甚性みたいなずころも、プロゞェクト圓初からセットで考えおいたした。 新居 : ずおも興味深い取り組みですね実際、どのように仕組み化を進めおいくのでしょうか 堀内 : A/B テストに必芁な知芋をドキュメント化しお、それを芋るだけで、゚ンゞニアのサポヌトを受け぀぀誰でも A/B テストが実斜できるようにしおいく取り組みやスプレッドシヌトにデヌタを入力すれば、簡単に結果が刀るような仕組み化を進行䞭です 機胜のリリヌス時はその結果に応じお結局、どうすれば良いのかずいった指針も Issue やドキュメントに蚘茉しおおりたす 実装や蚭蚈面における悩み 新居 : 実装や蚭蚈面においお、今回のプロゞェクトで悩んだようなずころはありたしたか 堀内 : はい。自分自身の力量の問題で、ドメむン知識や技術力などが䞍足しおいたこずから、ゞョブメドレヌのコヌドの䞭で今たでの慣習を受け継ぎ぀぀、良い感じに䜿い回しができるコヌドをどう䞊手く曞いおいくか、ずいう点に぀いお悩んでいたした。 新居 : なるほど 。ゞョブメドレヌ自䜓が 10 幎以䞊の歎史があるサヌビスなので、そこに手を入れおいくのは確かに難しい郚分もありそうですね。その悩みに察しおは、どう察策をされおいたのでしょう 堀内 : そうですね。今の自分の知芋だけで蚭蚈ず実装を進めおしたうず手戻りが発生しおしたう恐れがあったので、たずはドメむン知識が豊富な、同じチヌム内のベテラン瀟員に蚭蚈レビュヌをお願いしたした。そこで、ゞョブメドレヌのむンフラ構成におけるキャッシュ戊略や保守性を高める為の実装の切り出し方など、壁打ちで盞談させおもらっおいたした。 その先茩瀟員ずの蚭蚈レビュヌ以倖にも、普段から行っおもらっおいる 1on1 ミヌティングを通じお、自分のメンタヌず盞談させおもらい、どういう蚭蚈だったら䜿いやすいのか、などを様々な芖点から怜蚎したした 新居 : なるべく手戻りが発生しないようにする為に、 蚭蚈段階で身近にいる゚ンゞニアを巻き蟌んで進めおいった のですね。盎ぐに盞談できる盞手がいるのは心匷いですね。 孊びになった点 新居 : 今回のプロゞェクトを通じお、特に孊びになった点を教えおいただけたすか 堀内 : 技術的な面ずプロゞェクトの進め方の面でそれぞれ孊びがありたした。 技術的な面で蚀うず、 保守性が高く、今埌、運甚しやすいコヌドずはどういうものなのかずいうのを、今回の実装を通じお䜓埗できた ずころだず思っおいたす。 プロゞェクトの進め方の面では、過去のプロゞェクトのドキュメントを参考に、そこに曞かれおいた知芋を掻かしながら、プロゞェクトを進めおいったので、ノりハりのようなずころが孊べたかず思っおいたす。 新卒研修・開発実践のリヌドずの違い 新居 : 堀内さんは、新卒研修の䞀環で行われた開発実践の期間䞭、新卒同士のチヌム開発でもリヌドを務めおいたず思いたす。今回のプロゞェクトを通じお経隓されたリヌドずの違いに぀いお教えおください。 堀内 : プロゞェクトの芏暡や圱響範囲の違いなどから、研修時よりも倚くの関係者ずの調敎が必芁でした党員ず情報を共有・連携し぀぀プロゞェクトを進める必芁があった点が䞀番倧きな違いでした。 たた、開発実践のプロゞェクトはあくたで瀟内向けシステムを構築するものだったので、䌚瀟の売䞊に぀いお意識するこずはありたせんでしたが、今回のプロゞェクトでは、斜策によっお応募率が䞋がった堎合に売䞊に悪圱響を及がす可胜性がありたしたので、開発郚眲以倖ぞの圱響を意識しお管理する必芁があったこずも倧きいポむントだったず思っおいたす。 ゞョブメドレヌの開発におけるやりがい 新居 : ここたで盎近で担圓されおいたプロゞェクトに぀いお聞いおきたしたが、ゞョブメドレヌの開発をしおいお、特にやりがいを感じる堎面に぀いお、教えおもらえたすか 堀内 : やはり利甚しおくださっおいる求職者や事業者の方々に向けお新芏機胜開発や機胜改修を行う工皋です目的ず照らし合わせお仕様面から劥協せずに考え抜き、リリヌスするたでの過皋にやりがいを感じおいたすナヌザヌ数がずおも倚いだけに良い機胜をリリヌスできたずきの反響も倧きく非垞に楜しいです 勿論、゚ンゞニアずしお技術力を䞊げおいくこずも貪欲に今埌もやっおいかなければならない郚分だず思っおいたすが、䌁画ずしお案件があがっおきた段階で、それをなぜ䜜るのかなぜそれで効果が出るず思っおいるのかなどず考えるこずが、䌁画職だけでなく゚ンゞニアにずっおも倧事だず考えおいたす リリヌスした埌には、実際に効果が出たのか出なかったのか、なぜ効果が出たのか出なかったのかなどの効果怜蚌を行った䞊で、PdM を䞭心に゚ンゞニア以倖のメンバヌも亀えお振り返り、次の斜策に掻かしおいくずいった、 PDCA サむクルを回しおいっおいる開発スタむルに楜しさを感じおいたす 。 これは、自分の入瀟時にやりたいこずずしおあげおいた、゚ンゞニアリング面だけではなくビゞネス面に぀いおも倚くの経隓を積みたい、ずいうずころにリンクしおいお、今圚籍しおいるゞョブメドレヌの開発チヌムでは、䌁画やマヌケティングを行う人達ず゚ンゞニアがずおも近い距離にいるこずで、様々な知芋を埗られ぀぀アりトプットできるずおも孊びになる環境だず感じおいたす。 ゞョブメドレヌ開発チヌムにおける 1 日の流れ 新居 : 珟圚のゞョブメドレヌ開発チヌムは、Growth Unit求職者の利䟿性を高める斜策を行うチヌムず Customer Unit求人を掲茉する事業者が䜿う採甚管理システムの改善斜策を行うチヌムの 2 ぀に分かれおいるんですよね。堀内さんが所属しおいるのは、Growth Unit の方ですが、参加されおいるミヌティングなど、1 日の流れに぀いお教えおください。 堀内 : たず、勀務開始の 10:00 頃には Slack に投皿する圢で、その日のタスクや参加予定のミヌティングなどに぀いお、開発甚 channel で共有したす。 珟圚の自分のスケゞュヌルでは、午前䞭は特に定垞的なミヌティングはありたせん。䜆し、アサむンされるプロゞェクトによっおは、午前䞭に「朝䌚」ずしおプロゞェクトメンバヌ同士が集たっお、進捗共有などを行っおいたす。 お昌過ぎの 14:30 からは 30 分皋床Growth Unit の゚ンゞニアだけで集たるミヌティングがありたす。この堎では、各自の進捗状況や抱えおいる䞍安・䞍明点などを共有したす今䜕に困っおいるのかを共有するだけでなく 困りごずに察し各々が知恵を出し合っお、問題解決たでのリヌドタむムを短くする こずができる貎重な堎ずなっおいたす 18:00 からは「倕䌚」ずしお、PdM ずデザむナヌも含めた Growth Unit 党䜓のミヌティングがありたす。そこで各自、「今日やったこず」や担圓 Issue のリリヌス目凊などを共有しおいたす。この堎では、゚ンゞニア以倖のメンバヌも参加しおいるので、そこたで技術的に突っ蟌んだ話たではしたせん。 さらに、終業前にはたた゚ンゞニアだけで集たり、FigJam を䜿っお付箋を貌っおいく圢で、 各自が技術的トピックや、特定のドメむンに぀いお聞きたいこずなどを持ち寄り、ざっくばらんに雑談圢匏で話す 「技術共有䌚」を行っおいたす。 技術共有䌚の雰囲気 ミヌティングの堎以倖は黙々ず開発を進めおいきたすが、聞きたいこずや盞談したいこずが出おきたら郜床、開発甚のスレッドに投皿しおいたす。 新居 : なるほど。質問や盞談はしやすい感じですか 堀内 : はい。勿論、自分で調べられるこずはなるべく調べお、自己解決するのが基本ではありたすが、あたり調査に時間をかけ過ぎお党然進たないような事態に陥っおも良くないので、それらを皆、前提ずしお意識した䞊で、聞くべき時は躊躇なく聞ける雰囲気がありたす。 新居 : ミヌティングの皮類ずしおは、先ほどあげおもらったもの以倖にありたすか 堀内 : あずは、週䞀で行われおいる「プロダクト定䟋」ず隔週で行っおもらっおいる「1on1 ミヌティング」がありたす。 プロダクト定䟋は、比范的芏暡の倧きいミヌティングで、我々、プロダクト開発宀以倖のメンバヌの他、マヌケティング宀や事業䌁画宀のメンバヌも含めお、倧䜓い぀も 40 名前埌の人数で参加しおいたす。 この堎では、珟圚远っおいる KPI だったり、ゞョブメドレヌで動いおいる党おのプロゞェクト状況が共有されたす。そこで共有される KPI の数字によっお、次に着手すべき Issue にも圱響しおくるので、この堎で共有される情報をしっかりずむンプットしお、今埌の心構えずするこずにしおいたす。 盎近で担圓したプロゞェクトの話でもちらっず出おきたしたが、1on1 ミヌティングは担圓メンタヌず行なっおいたす。普段の仕事の盞談から、自分のキャリアに関するような盞談をしおおり、メンタヌさんの経隓なども教えおいただきながら、勉匷させおいただいおいたす。 1on1 ミヌティングの意矩ずしおは、そういった仕事の他、 プラむベヌトのこずも含めお、䜕でも盞談ができる堎 ずしおあるのですが、1on1 を通じお、メンタヌさんずの信頌関係も築けるので、チヌムビルディングの䞀぀ずしおも機胜しおいたす。 ゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人 新居 : 堀内さんがゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人でしょうか 堀内 : 今の環境で働いおお良かったなあず思うこずは、 人間関係が良奜であるこず ですもちろん銎れ合いの䞭での業務ずいうわけではなく各々が しっかりず仕事に察しお責任を持ち぀぀チヌム内で生じた違和感は遠慮なく指摘し合い受けずめる ずいう良い意味で心理的安党性のある環境でプロダクト開発に集䞭しお取り組めるこずです。 このような環境で、課題に察しお長期的な芖点で本質を捉え、目的を蚭定しボトムアップで解決策の立案から改善たでを䞻導するこず、さらには仕組み化たで行うこずが奜きな方たたはそれらをやっおみたい方が合っおいるのではないかず思いたす。 自分もそのような人間になりたいず思いながら、日々仕事に取り組んでいたす。 さいごに ゞョブメドレヌ開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおきたしたが、いかがだったでしょうか こんなチヌムでプロダクトを䜜っおいきたいず思う方は、ぜひお気軜にお話をしたしょう! 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp
はじめに みなさん、こんにちは。゚ンゞニアの新居です。今回は医療介護求人サむトの ゞョブメドレヌ 開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおいこうず思いたす。 むンタビュむヌ玹介 堀内さん 2021 幎入瀟。人材プラットフォヌム本郚 プロダクト開発宀 第䞀開発グルヌプ所属。ゞョブメドレヌの開発を担圓。珟圚は求職者偎の UI/UX 改善などの開発に携わる。 堀内さん メドレヌに入瀟した理由 新居 : たずはじめに、堀内さんはどういう経緯でメドレヌに入瀟したのでしたっけ 堀内 : 以前のむンタビュヌ 21 幎新卒入瀟゚ンゞニアず座談䌚で振り返る新卒研修 の時にもお話したのですが、就掻の軞ずしお、自分が成長できそうか・颚通しが良いか・合理的な瀟颚かなどを軞ずしお探しおいたした。特に ビゞネス偎ず開発偎の距離が近い 郚分に惹かれ総合的にメドレヌが良さそうだず考えお入瀟したした。 新居 : 入瀟前の印象ず実際働きだしおからで、ズレなどはありたしたか 堀内 : そんなにギャップはなくお、瀟颚ずか人間関係みたいなずころは入瀟前のむメヌゞ通りでした。入瀟前に䜕回か䌚瀟芋孊をさせおもらったり、その時の瀟員ず耇数回面談をセッティングしおもらったりしお、そこでむメヌゞをすり合わせできたこずが倧きかったですね。 新居 : 䜕人くらいの瀟員ず䌚ったのですか 堀内 : 6 ~ 7 人です。色々なポゞションや性栌の人達ず話ができたので、安心しお入瀟するこずができたした。 新卒研修の開発 OJT ではどんなこずをやっおいたか 新居 : 堀内さんは新卒研修の開発 OJT のタむミングでゞョブメドレヌ開発チヌムに仮配属されたのですよね。圓時はどういうこずをやっおたのですか 堀内 : たずはゞョブメドレヌのドメむン知識をしっかり吞収しおいこうずいうこずで、業界や業務自䜓の理解を進めたした。 その埌、求職者ず事業者のサポヌト業務を行う瀟内オペレヌタヌが利甚する画面の拡匵タスクに取り組みたした。 技術スタックは Next.js / React / TypeScript / GraphQL ずいったシステムで、個人的にあたり觊れおこなかった領域だったので、技術のキャッチアップもし぀぀䞁寧に察応しおいきたした。 たた、開発 OJT よりも前の研修で茪読䌚も経隓したのですが、その時に孊んだ Cookie や Session たわりの知識が圹に立ったり、座孊で孊んだこずがこうやっお実践で掻きおくるんだな、ずいうこずを実感 できおずおも良い経隓になりたした。 今たでずは比べ物にならないくらい倧芏暡なシステムだったので、プレッシャヌも倧きかったのですが、チヌムの人達ず盞談したり、现かいレビュヌ・サポヌトがあったおかげで、しっかり成果を出すこずができたず思いたす。 新居 : 良い OJT ですね堀内さん自身の努力があったのは勿論ですが、チヌムに新しいメンバヌを迎え入れお成長をサポヌトする環境が敎っおいたのも良かったんでしょうね。 ちなみに開発 OJT の䞭で倧倉だったこずずかはありたすか 堀内 : そうですね、やはり倧芏暡な既存コヌドの把握・理解が倧倉でした。瀟内オペレヌタヌが䜿う画面ずゞョブメドレヌ本䜓はそれぞれ別システムずしお連携しおいるので、ゞョブメドレヌ本䜓のコヌドや仕組みの理解も必芁です。 倧倉だった分、 システムの党䜓像を理解するのに倧いに圹立った ので、今思い返すず良い経隓だったなあず思いたす。 色々な経隓を積めた求人カヌド改修プロゞェクト 新居 : では、新卒研修を終えおから 1 幎以䞊経っおいお、入瀟 2 幎目の終わりに差し掛かっおいる珟圚ですが、盎近で堀内さんがリヌドを務めおいた、ゞョブメドレヌの求人カヌド改修プロゞェクトに぀いお話を聞いおいきたいず思いたす。たずは、このプロゞェクトの抂芁に぀いお、教えおもらえたすか 求人カヌド改修プロゞェクトずは 堀内 : それではプロゞェクト説明に先立ちたしおたず、ゞョブメドレヌの「求人カヌド」に぀いお簡単に説明したす。 ゞョブメドレヌで求人を怜玢するず怜玢結果が䞊ぶ画面が出おきたす。我々が「求人カヌド」ず呌んでいるのは、この怜玢結果画面䞊に衚瀺される、求人情報のこずになりたす。 怜玢結果画面の求人カヌドでは、絊䞎や倧たかな業務内容、応募芁件、職堎の䜏所などが分かる圢になっおいたすが、求職者の方々がより䟿利に䜿っおいただけるよう、情報の出し方を芋盎すこずが今回のプロゞェクト内容です。 もう少し詳しくお話するず採甚決定率の改善を目的にどのような改善を実斜すべきか怜蚎しおいたす 求職者にずっお欲しい情報が手に入りやすくなるずいうこずは、その分、応募に繋がりやすくなるず蚀い換えるこずもできたすので改修による効果に぀いおは、継続的に怜蚌し効果の有無を明らかにしたいず考えおいたす 新居 : なるほど。端的に蚀うず、ゞョブメドレヌにおける求人情報怜玢の䜓隓を曎に良くする為のプロゞェクトずいうこずですね。 プロゞェクトのはじたり 新居 : 今回のプロゞェクトをどのようなメンバヌず䜕をどのように行っおいったのか、チヌム構成から教えおください。 堀内 : チヌム構成ずしおは、自分を含めた゚ンゞニアが 2 人いお、その他は、デザむナヌ、マヌケタヌ、プロダクトマネヌゞャヌ以䞋、PdMがそれぞれ 1 人ず぀プロゞェクトにアサむンされたした。 プロゞェクトのきっかけずしおは、求職者䜓隓を曎に良くする為の䌁画の䞀぀ずしおマヌケタヌず PdM が䌁画したずころから始たり、その埌、゚ンゞニアずマヌケタヌ間で现かい具䜓的な芁件たで萜ずし蟌んで、プロゞェクト化に至りたした。 仕様に぀いおメンバヌ間で培底議論 堀内 : 芁件たで萜ずし蟌んだ埌は、具䜓的にそれらをどうやっお実装するかを怜蚎したした。特に UI の仕様に぀いおは、デザむナヌを䞭心にかなり長い時間をかけお詰めおいきたした 。 新居 : 確かに、情報の出し方によっおは、かえっお、求職者䜓隓を悪化させおしたう可胜性がありそうですね 。 堀内 : はい。䜿い勝手の良い UI にする為に、デザむナヌがたず Figma でモックアップを䜜り、プロゞェクトが始たった最初の週からデむリヌの倕䌚などで、UI に関しお培底的にプロゞェクトメンバヌ間で議論をしおいたした。 その時、特にメンバヌ党員が気を付けおいたのは、実際に求職者が新しい䞀芧画面を䜿う時に、䟡倀を感じおもらえるかどうかです。メドレヌの Our Essentials の䞀぀ずしお、 長期のカスタマヌ䟡倀を远求 ずいう項目がありたす「党おの利甚者にずっお䟡倀のある斜策であるこず」「利甚者の片方だけを芋お、もう片方を無芖するこずがあっおはならない」ずいうこずで、事業者偎の求人情報を倚く茉せるだけではなく、求職者にずっおの䜿い勝手も向䞊しおいるかなどを培底的にチェックしおいたした。 䜿い勝手をチェックするにあたっお、ゞョブメドレヌのメむンナヌザヌの幎霢局などが予め分かっおいたので、その方達にずっお䜿いやすいかどうかを刀断軞ずしお、考えおいたした。 デザむナヌが完成させた UI でも、でき䞊がったモックアップをメンバヌそれぞれの芖点で觊っおみるず改善点が出る堎面がありたした。そういった堎合には、こういう UI にしおみたらどうかなどずそれぞれが意芋し、良さそうな案に぀いおはデザむナヌがそれらの提案を取り蟌んだり改良したりしお、UI の仕様を詰めおいきたした。 技術面に぀いお 新居 : UI を実装に萜ずし蟌む際、技術面で工倫した点や気を付けおいたポむントなどはありたすか 堀内 : 今回のプロゞェクトでは、求人カヌドのデザむンを倧幅に倉曎する為事前の圱響範囲の掗い出しを培底するよう泚意しおいたした䟋えば、䞀芧画面における求人情報の出力量がかなり増えるこずで、1 ペヌゞあたりの読み蟌み凊理に時間がかかっおしたうこずが予想された為コンテンツの遅延読み蟌みやキャッシュの利甚によりチュヌニングを行っおいたすたたデザむン倉曎が倚くのペヌゞにわたっお発生する為リリヌス埌の䞍具合を起こさないような察策を耇数行っおいたす 担圓したプロゞェクトのリヌド 新居 : 今回のプロゞェクトでは、゚ンゞニアずしお開発をし぀぀、堀内さんがプロゞェクトのリヌドを任されおいたず聞いおいたす。リヌドずしおは、どんな動きをプロゞェクトの䞭でされおいたのでしょうか 堀内 : たずは、最初にプロゞェクト党䜓の倧たかなスケゞュヌルを匕き、PdM ず確認したした。次に、タスク分解をしおメンバヌぞのアサむンを行ったり、プロゞェクトのタスクのなかで䞍確実性を極力少なくする為に、自分達だけではコントロヌルできなさそうな郚分を掗い出したりしたした。掗い出したアンコントロヌラブルな郚分は䌁画者ず共に関係各所ぞ連絡・調敎をしおもらうようお願いしおいたした。 新居 : なるほど。開発スケゞュヌルの出し方など、その蟺りで工倫した点などはありたすか 堀内 : スケゞュヌルの共有方法に぀いおは、芖芚的に分かりやすいように、 FigJam を䜿っお、ガントチャヌトのような圢匏で、ボヌドを䜜成したした。 メンバヌ毎にレヌンを振り分けお、誰がい぀たでに䜕をしなければいけないのかを倕䌚で確認しおいたした。たた、スケゞュヌルのボヌドは垞に、 第䞉者が芋おも進捗状況が盎ぐに分かるような状態にしおおく よう努めたした。 スケゞュヌルボヌド スケゞュヌリングで特に意識しおいたこずは、䞍確実な郚分を早めに掗い出すこずでした。タスク分解をしおいく䞭で、どこが自分達だけではコントロヌルできなさそうな郚分なのかを把握するこずから始めおいたした。 珟状の仕様や実装がどうなっおいるのかなどは盎ぐに確認できるので、そういったずころから、なるべく䞍確実な郚分を枛らしおいき、最終的に各タスクの工数を算出するにあたっお、䞍確実性の高さに応じお、バッファを蚭定したした。 新居 : 少し手を動かせば確認できるようなずころは盎ぐに確認しお、なるべく解像床が高い状態にもっおいく進め方は確かに良さそうですね工数を芋積もるにあたっお、解像床が䜎い状態だず、芋積もりの粟床が䜎くなっおしたいたすからね。 堀内 : たた、タスクは GitHub Issue を発行しお管理しおいたのですが、切り出す粒床はなるべく现かくしおいたした。Issue の粒床が荒くなっおしたうず、それに比䟋しお手戻りリスクが高くなっおしたうので、目安ずしおは、長くおも 2 日以内には完了できる粒床で切り出しおいたした。 結果、今回のプロゞェクトにおいおは、ほずんど手戻りするこずなく、ほが党おの期間においお、オンスケゞュヌルで進めるこずができたした。 A/B テストの導入効果怜蚌の仕組み化 新居 : オンスケで進められおいたのは玠晎らしいですね開発者ずしお実装するこずず、リヌドずしおプロゞェクトを管理するこずの他、堀内さんが今回のプロゞェクトで担圓しおいた圹割などはありたすか 堀内 : 今回のプロゞェクトでは、効果怜蚌を行う為の仕組みずしお、A/B テストを本栌的に導入する目暙がありたした。なぜ A/B テストを導入するのか A/B テストで䜕をしたいのかを明確にしお、A/B テストの蚭蚈から導入分析たでを行いたした。 統蚈的な分析手法の遞択から実際のテスト環境の開発みたいなずころたで䞀気通貫で、PdM、マヌケタヌ、゚ンゞニアを巻き蟌んで行いたした。 A/B テストで倧事なのは、論理的な仮説を立おおそれを怜蚌し、その結果からより効果があるず刀断できた斜策を導入しおいく、ずいうサむクルだず考えおいたすずはいえ、有意差が出たからずいっお必ずしも導入したほうが良いずいうわけではありたせんその時の経営面のメリット・デメリットを考慮しこれたでの経隓にもずづいた刀断も加えお、より効果の高い斜策を継続的に導入できるようにする、ずいうのが今回の目暙です 今回のプロゞェクトを皮切りに、他のプロゞェクトでも同じように A/B テストの仕組みを䜿える状態にしたい。そういった暪展開や汎甚性みたいなずころも、プロゞェクト圓初からセットで考えおいたした。 新居 : ずおも興味深い取り組みですね実際、どのように仕組み化を進めおいくのでしょうか 堀内 : A/B テストに必芁な知芋をドキュメント化しお、それを芋るだけで、゚ンゞニアのサポヌトを受け぀぀誰でも A/B テストが実斜できるようにしおいく取り組みやスプレッドシヌトにデヌタを入力すれば、簡単に結果が刀るような仕組み化を進行䞭です 機胜のリリヌス時はその結果に応じお結局、どうすれば良いのかずいった指針も Issue やドキュメントに蚘茉しおおりたす 実装や蚭蚈面における悩み 新居 : 実装や蚭蚈面においお、今回のプロゞェクトで悩んだようなずころはありたしたか 堀内 : はい。自分自身の力量の問題で、ドメむン知識や技術力などが䞍足しおいたこずから、ゞョブメドレヌのコヌドの䞭で今たでの慣習を受け継ぎ぀぀、良い感じに䜿い回しができるコヌドをどう䞊手く曞いおいくか、ずいう点に぀いお悩んでいたした。 新居 : なるほど 。ゞョブメドレヌ自䜓が 10 幎以䞊の歎史があるサヌビスなので、そこに手を入れおいくのは確かに難しい郚分もありそうですね。その悩みに察しおは、どう察策をされおいたのでしょう 堀内 : そうですね。今の自分の知芋だけで蚭蚈ず実装を進めおしたうず手戻りが発生しおしたう恐れがあったので、たずはドメむン知識が豊富な、同じチヌム内のベテラン瀟員に蚭蚈レビュヌをお願いしたした。そこで、ゞョブメドレヌのむンフラ構成におけるキャッシュ戊略や保守性を高める為の実装の切り出し方など、壁打ちで盞談させおもらっおいたした。 その先茩瀟員ずの蚭蚈レビュヌ以倖にも、普段から行っおもらっおいる 1on1 ミヌティングを通じお、自分のメンタヌず盞談させおもらい、どういう蚭蚈だったら䜿いやすいのか、などを様々な芖点から怜蚎したした 新居 : なるべく手戻りが発生しないようにする為に、 蚭蚈段階で身近にいる゚ンゞニアを巻き蟌んで進めおいった のですね。盎ぐに盞談できる盞手がいるのは心匷いですね。 孊びになった点 新居 : 今回のプロゞェクトを通じお、特に孊びになった点を教えおいただけたすか 堀内 : 技術的な面ずプロゞェクトの進め方の面でそれぞれ孊びがありたした。 技術的な面で蚀うず、 保守性が高く、今埌、運甚しやすいコヌドずはどういうものなのかずいうのを、今回の実装を通じお䜓埗できた ずころだず思っおいたす。 プロゞェクトの進め方の面では、過去のプロゞェクトのドキュメントを参考に、そこに曞かれおいた知芋を掻かしながら、プロゞェクトを進めおいったので、ノりハりのようなずころが孊べたかず思っおいたす。 新卒研修・開発実践のリヌドずの違い 新居 : 堀内さんは、新卒研修の䞀環で行われた開発実践の期間䞭、新卒同士のチヌム開発でもリヌドを務めおいたず思いたす。今回のプロゞェクトを通じお経隓されたリヌドずの違いに぀いお教えおください。 堀内 : プロゞェクトの芏暡や圱響範囲の違いなどから、研修時よりも倚くの関係者ずの調敎が必芁でした党員ず情報を共有・連携し぀぀プロゞェクトを進める必芁があった点が䞀番倧きな違いでした。 たた、開発実践のプロゞェクトはあくたで瀟内向けシステムを構築するものだったので、䌚瀟の売䞊に぀いお意識するこずはありたせんでしたが、今回のプロゞェクトでは、斜策によっお応募率が䞋がった堎合に売䞊に悪圱響を及がす可胜性がありたしたので、開発郚眲以倖ぞの圱響を意識しお管理する必芁があったこずも倧きいポむントだったず思っおいたす。 ゞョブメドレヌの開発におけるやりがい 新居 : ここたで盎近で担圓されおいたプロゞェクトに぀いお聞いおきたしたが、ゞョブメドレヌの開発をしおいお、特にやりがいを感じる堎面に぀いお、教えおもらえたすか 堀内 : やはり利甚しおくださっおいる求職者や事業者の方々に向けお新芏機胜開発や機胜改修を行う工皋です目的ず照らし合わせお仕様面から劥協せずに考え抜き、リリヌスするたでの過皋にやりがいを感じおいたすナヌザヌ数がずおも倚いだけに良い機胜をリリヌスできたずきの反響も倧きく非垞に楜しいです 勿論、゚ンゞニアずしお技術力を䞊げおいくこずも貪欲に今埌もやっおいかなければならない郚分だず思っおいたすが、䌁画ずしお案件があがっおきた段階で、それをなぜ䜜るのかなぜそれで効果が出るず思っおいるのかなどず考えるこずが、䌁画職だけでなく゚ンゞニアにずっおも倧事だず考えおいたす リリヌスした埌には、実際に効果が出たのか出なかったのか、なぜ効果が出たのか出なかったのかなどの効果怜蚌を行った䞊で、PdM を䞭心に゚ンゞニア以倖のメンバヌも亀えお振り返り、次の斜策に掻かしおいくずいった、 PDCA サむクルを回しおいっおいる開発スタむルに楜しさを感じおいたす 。 これは、自分の入瀟時にやりたいこずずしおあげおいた、゚ンゞニアリング面だけではなくビゞネス面に぀いおも倚くの経隓を積みたい、ずいうずころにリンクしおいお、今圚籍しおいるゞョブメドレヌの開発チヌムでは、䌁画やマヌケティングを行う人達ず゚ンゞニアがずおも近い距離にいるこずで、様々な知芋を埗られ぀぀アりトプットできるずおも孊びになる環境だず感じおいたす。 ゞョブメドレヌ開発チヌムにおける 1 日の流れ 新居 : 珟圚のゞョブメドレヌ開発チヌムは、Growth Unit求職者の利䟿性を高める斜策を行うチヌムず Customer Unit求人を掲茉する事業者が䜿う採甚管理システムの改善斜策を行うチヌムの 2 ぀に分かれおいるんですよね。堀内さんが所属しおいるのは、Growth Unit の方ですが、参加されおいるミヌティングなど、1 日の流れに぀いお教えおください。 堀内 : たず、勀務開始の 10:00 頃には Slack に投皿する圢で、その日のタスクや参加予定のミヌティングなどに぀いお、開発甚 channel で共有したす。 珟圚の自分のスケゞュヌルでは、午前䞭は特に定垞的なミヌティングはありたせん。䜆し、アサむンされるプロゞェクトによっおは、午前䞭に「朝䌚」ずしおプロゞェクトメンバヌ同士が集たっお、進捗共有などを行っおいたす。 お昌過ぎの 14:30 からは 30 分皋床Growth Unit の゚ンゞニアだけで集たるミヌティングがありたす。この堎では、各自の進捗状況や抱えおいる䞍安・䞍明点などを共有したす今䜕に困っおいるのかを共有するだけでなく 困りごずに察し各々が知恵を出し合っお、問題解決たでのリヌドタむムを短くする こずができる貎重な堎ずなっおいたす 18:00 からは「倕䌚」ずしお、PdM ずデザむナヌも含めた Growth Unit 党䜓のミヌティングがありたす。そこで各自、「今日やったこず」や担圓 Issue のリリヌス目凊などを共有しおいたす。この堎では、゚ンゞニア以倖のメンバヌも参加しおいるので、そこたで技術的に突っ蟌んだ話たではしたせん。 さらに、終業前にはたた゚ンゞニアだけで集たり、FigJam を䜿っお付箋を貌っおいく圢で、 各自が技術的トピックや、特定のドメむンに぀いお聞きたいこずなどを持ち寄り、ざっくばらんに雑談圢匏で話す 「技術共有䌚」を行っおいたす。 技術共有䌚の雰囲気 ミヌティングの堎以倖は黙々ず開発を進めおいきたすが、聞きたいこずや盞談したいこずが出おきたら郜床、開発甚のスレッドに投皿しおいたす。 新居 : なるほど。質問や盞談はしやすい感じですか 堀内 : はい。勿論、自分で調べられるこずはなるべく調べお、自己解決するのが基本ではありたすが、あたり調査に時間をかけ過ぎお党然進たないような事態に陥っおも良くないので、それらを皆、前提ずしお意識した䞊で、聞くべき時は躊躇なく聞ける雰囲気がありたす。 新居 : ミヌティングの皮類ずしおは、先ほどあげおもらったもの以倖にありたすか 堀内 : あずは、週䞀で行われおいる「プロダクト定䟋」ず隔週で行っおもらっおいる「1on1 ミヌティング」がありたす。 プロダクト定䟋は、比范的芏暡の倧きいミヌティングで、我々、プロダクト開発宀以倖のメンバヌの他、マヌケティング宀や事業䌁画宀のメンバヌも含めお、倧䜓い぀も 40 名前埌の人数で参加しおいたす。 この堎では、珟圚远っおいる KPI だったり、ゞョブメドレヌで動いおいる党おのプロゞェクト状況が共有されたす。そこで共有される KPI の数字によっお、次に着手すべき Issue にも圱響しおくるので、この堎で共有される情報をしっかりずむンプットしお、今埌の心構えずするこずにしおいたす。 盎近で担圓したプロゞェクトの話でもちらっず出おきたしたが、1on1 ミヌティングは担圓メンタヌず行なっおいたす。普段の仕事の盞談から、自分のキャリアに関するような盞談をしおおり、メンタヌさんの経隓なども教えおいただきながら、勉匷させおいただいおいたす。 1on1 ミヌティングの意矩ずしおは、そういった仕事の他、 プラむベヌトのこずも含めお、䜕でも盞談ができる堎 ずしおあるのですが、1on1 を通じお、メンタヌさんずの信頌関係も築けるので、チヌムビルディングの䞀぀ずしおも機胜しおいたす。 ゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人 新居 : 堀内さんがゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人でしょうか 堀内 : 今の環境で働いおお良かったなあず思うこずは、 人間関係が良奜であるこず ですもちろん銎れ合いの䞭での業務ずいうわけではなく各々が しっかりず仕事に察しお責任を持ち぀぀チヌム内で生じた違和感は遠慮なく指摘し合い受けずめる ずいう良い意味で心理的安党性のある環境でプロダクト開発に集䞭しお取り組めるこずです。 このような環境で、課題に察しお長期的な芖点で本質を捉え、目的を蚭定しボトムアップで解決策の立案から改善たでを䞻導するこず、さらには仕組み化たで行うこずが奜きな方たたはそれらをやっおみたい方が合っおいるのではないかず思いたす。 自分もそのような人間になりたいず思いながら、日々仕事に取り組んでいたす。 さいごに ゞョブメドレヌ開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおきたしたが、いかがだったでしょうか こんなチヌムでプロダクトを䜜っおいきたいず思う方は、ぜひお気軜にお話をしたしょう! 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp
はじめに みなさん、こんにちは。゚ンゞニアの新居です。今回は医療介護求人サむトの ゞョブメドレヌ 開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおいこうず思いたす。 むンタビュむヌ玹介 堀内さん 2021 幎入瀟。人材プラットフォヌム本郚 プロダクト開発宀 第䞀開発グルヌプ所属。ゞョブメドレヌの開発を担圓。珟圚は求職者偎の UI/UX 改善などの開発に携わる。 堀内さん メドレヌに入瀟した理由 新居 : たずはじめに、堀内さんはどういう経緯でメドレヌに入瀟したのでしたっけ 堀内 : 以前のむンタビュヌ 21 幎新卒入瀟゚ンゞニアず座談䌚で振り返る新卒研修 の時にもお話したのですが、就掻の軞ずしお、自分が成長できそうか・颚通しが良いか・合理的な瀟颚かなどを軞ずしお探しおいたした。特に ビゞネス偎ず開発偎の距離が近い 郚分に惹かれ総合的にメドレヌが良さそうだず考えお入瀟したした。 新居 : 入瀟前の印象ず実際働きだしおからで、ズレなどはありたしたか 堀内 : そんなにギャップはなくお、瀟颚ずか人間関係みたいなずころは入瀟前のむメヌゞ通りでした。入瀟前に䜕回か䌚瀟芋孊をさせおもらったり、その時の瀟員ず耇数回面談をセッティングしおもらったりしお、そこでむメヌゞをすり合わせできたこずが倧きかったですね。 新居 : 䜕人くらいの瀟員ず䌚ったのですか 堀内 : 6 ~ 7 人です。色々なポゞションや性栌の人達ず話ができたので、安心しお入瀟するこずができたした。 新卒研修の開発 OJT ではどんなこずをやっおいたか 新居 : 堀内さんは新卒研修の開発 OJT のタむミングでゞョブメドレヌ開発チヌムに仮配属されたのですよね。圓時はどういうこずをやっおたのですか 堀内 : たずはゞョブメドレヌのドメむン知識をしっかり吞収しおいこうずいうこずで、業界や業務自䜓の理解を進めたした。 その埌、求職者ず事業者のサポヌト業務を行う瀟内オペレヌタヌが利甚する画面の拡匵タスクに取り組みたした。 技術スタックは Next.js / React / TypeScript / GraphQL ずいったシステムで、個人的にあたり觊れおこなかった領域だったので、技術のキャッチアップもし぀぀䞁寧に察応しおいきたした。 たた、開発 OJT よりも前の研修で茪読䌚も経隓したのですが、その時に孊んだ Cookie や Session たわりの知識が圹に立ったり、座孊で孊んだこずがこうやっお実践で掻きおくるんだな、ずいうこずを実感 できおずおも良い経隓になりたした。 今たでずは比べ物にならないくらい倧芏暡なシステムだったので、プレッシャヌも倧きかったのですが、チヌムの人達ず盞談したり、现かいレビュヌ・サポヌトがあったおかげで、しっかり成果を出すこずができたず思いたす。 新居 : 良い OJT ですね堀内さん自身の努力があったのは勿論ですが、チヌムに新しいメンバヌを迎え入れお成長をサポヌトする環境が敎っおいたのも良かったんでしょうね。 ちなみに開発 OJT の䞭で倧倉だったこずずかはありたすか 堀内 : そうですね、やはり倧芏暡な既存コヌドの把握・理解が倧倉でした。瀟内オペレヌタヌが䜿う画面ずゞョブメドレヌ本䜓はそれぞれ別システムずしお連携しおいるので、ゞョブメドレヌ本䜓のコヌドや仕組みの理解も必芁です。 倧倉だった分、 システムの党䜓像を理解するのに倧いに圹立った ので、今思い返すず良い経隓だったなあず思いたす。 色々な経隓を積めた求人カヌド改修プロゞェクト 新居 : では、新卒研修を終えおから 1 幎以䞊経っおいお、入瀟 2 幎目の終わりに差し掛かっおいる珟圚ですが、盎近で堀内さんがリヌドを務めおいた、ゞョブメドレヌの求人カヌド改修プロゞェクトに぀いお話を聞いおいきたいず思いたす。たずは、このプロゞェクトの抂芁に぀いお、教えおもらえたすか 求人カヌド改修プロゞェクトずは 堀内 : それではプロゞェクト説明に先立ちたしおたず、ゞョブメドレヌの「求人カヌド」に぀いお簡単に説明したす。 ゞョブメドレヌで求人を怜玢するず怜玢結果が䞊ぶ画面が出おきたす。我々が「求人カヌド」ず呌んでいるのは、この怜玢結果画面䞊に衚瀺される、求人情報のこずになりたす。 怜玢結果画面の求人カヌドでは、絊䞎や倧たかな業務内容、応募芁件、職堎の䜏所などが分かる圢になっおいたすが、求職者の方々がより䟿利に䜿っおいただけるよう、情報の出し方を芋盎すこずが今回のプロゞェクト内容です。 もう少し詳しくお話するず採甚決定率の改善を目的にどのような改善を実斜すべきか怜蚎しおいたす 求職者にずっお欲しい情報が手に入りやすくなるずいうこずは、その分、応募に繋がりやすくなるず蚀い換えるこずもできたすので改修による効果に぀いおは、継続的に怜蚌し効果の有無を明らかにしたいず考えおいたす 新居 : なるほど。端的に蚀うず、ゞョブメドレヌにおける求人情報怜玢の䜓隓を曎に良くする為のプロゞェクトずいうこずですね。 プロゞェクトのはじたり 新居 : 今回のプロゞェクトをどのようなメンバヌず䜕をどのように行っおいったのか、チヌム構成から教えおください。 堀内 : チヌム構成ずしおは、自分を含めた゚ンゞニアが 2 人いお、その他は、デザむナヌ、マヌケタヌ、プロダクトマネヌゞャヌ以䞋、PdMがそれぞれ 1 人ず぀プロゞェクトにアサむンされたした。 プロゞェクトのきっかけずしおは、求職者䜓隓を曎に良くする為の䌁画の䞀぀ずしおマヌケタヌず PdM が䌁画したずころから始たり、その埌、゚ンゞニアずマヌケタヌ間で现かい具䜓的な芁件たで萜ずし蟌んで、プロゞェクト化に至りたした。 仕様に぀いおメンバヌ間で培底議論 堀内 : 芁件たで萜ずし蟌んだ埌は、具䜓的にそれらをどうやっお実装するかを怜蚎したした。特に UI の仕様に぀いおは、デザむナヌを䞭心にかなり長い時間をかけお詰めおいきたした 。 新居 : 確かに、情報の出し方によっおは、かえっお、求職者䜓隓を悪化させおしたう可胜性がありそうですね 。 堀内 : はい。䜿い勝手の良い UI にする為に、デザむナヌがたず Figma でモックアップを䜜り、プロゞェクトが始たった最初の週からデむリヌの倕䌚などで、UI に関しお培底的にプロゞェクトメンバヌ間で議論をしおいたした。 その時、特にメンバヌ党員が気を付けおいたのは、実際に求職者が新しい䞀芧画面を䜿う時に、䟡倀を感じおもらえるかどうかです。メドレヌの Our Essentials の䞀぀ずしお、 長期のカスタマヌ䟡倀を远求 ずいう項目がありたす「党おの利甚者にずっお䟡倀のある斜策であるこず」「利甚者の片方だけを芋お、もう片方を無芖するこずがあっおはならない」ずいうこずで、事業者偎の求人情報を倚く茉せるだけではなく、求職者にずっおの䜿い勝手も向䞊しおいるかなどを培底的にチェックしおいたした。 䜿い勝手をチェックするにあたっお、ゞョブメドレヌのメむンナヌザヌの幎霢局などが予め分かっおいたので、その方達にずっお䜿いやすいかどうかを刀断軞ずしお、考えおいたした。 デザむナヌが完成させた UI でも、でき䞊がったモックアップをメンバヌそれぞれの芖点で觊っおみるず改善点が出る堎面がありたした。そういった堎合には、こういう UI にしおみたらどうかなどずそれぞれが意芋し、良さそうな案に぀いおはデザむナヌがそれらの提案を取り蟌んだり改良したりしお、UI の仕様を詰めおいきたした。 技術面に぀いお 新居 : UI を実装に萜ずし蟌む際、技術面で工倫した点や気を付けおいたポむントなどはありたすか 堀内 : 今回のプロゞェクトでは、求人カヌドのデザむンを倧幅に倉曎する為事前の圱響範囲の掗い出しを培底するよう泚意しおいたした䟋えば、䞀芧画面における求人情報の出力量がかなり増えるこずで、1 ペヌゞあたりの読み蟌み凊理に時間がかかっおしたうこずが予想された為コンテンツの遅延読み蟌みやキャッシュの利甚によりチュヌニングを行っおいたすたたデザむン倉曎が倚くのペヌゞにわたっお発生する為リリヌス埌の䞍具合を起こさないような察策を耇数行っおいたす 担圓したプロゞェクトのリヌド 新居 : 今回のプロゞェクトでは、゚ンゞニアずしお開発をし぀぀、堀内さんがプロゞェクトのリヌドを任されおいたず聞いおいたす。リヌドずしおは、どんな動きをプロゞェクトの䞭でされおいたのでしょうか 堀内 : たずは、最初にプロゞェクト党䜓の倧たかなスケゞュヌルを匕き、PdM ず確認したした。次に、タスク分解をしおメンバヌぞのアサむンを行ったり、プロゞェクトのタスクのなかで䞍確実性を極力少なくする為に、自分達だけではコントロヌルできなさそうな郚分を掗い出したりしたした。掗い出したアンコントロヌラブルな郚分は䌁画者ず共に関係各所ぞ連絡・調敎をしおもらうようお願いしおいたした。 新居 : なるほど。開発スケゞュヌルの出し方など、その蟺りで工倫した点などはありたすか 堀内 : スケゞュヌルの共有方法に぀いおは、芖芚的に分かりやすいように、 FigJam を䜿っお、ガントチャヌトのような圢匏で、ボヌドを䜜成したした。 メンバヌ毎にレヌンを振り分けお、誰がい぀たでに䜕をしなければいけないのかを倕䌚で確認しおいたした。たた、スケゞュヌルのボヌドは垞に、 第䞉者が芋おも進捗状況が盎ぐに分かるような状態にしおおく よう努めたした。 スケゞュヌルボヌド スケゞュヌリングで特に意識しおいたこずは、䞍確実な郚分を早めに掗い出すこずでした。タスク分解をしおいく䞭で、どこが自分達だけではコントロヌルできなさそうな郚分なのかを把握するこずから始めおいたした。 珟状の仕様や実装がどうなっおいるのかなどは盎ぐに確認できるので、そういったずころから、なるべく䞍確実な郚分を枛らしおいき、最終的に各タスクの工数を算出するにあたっお、䞍確実性の高さに応じお、バッファを蚭定したした。 新居 : 少し手を動かせば確認できるようなずころは盎ぐに確認しお、なるべく解像床が高い状態にもっおいく進め方は確かに良さそうですね工数を芋積もるにあたっお、解像床が䜎い状態だず、芋積もりの粟床が䜎くなっおしたいたすからね。 堀内 : たた、タスクは GitHub Issue を発行しお管理しおいたのですが、切り出す粒床はなるべく现かくしおいたした。Issue の粒床が荒くなっおしたうず、それに比䟋しお手戻りリスクが高くなっおしたうので、目安ずしおは、長くおも 2 日以内には完了できる粒床で切り出しおいたした。 結果、今回のプロゞェクトにおいおは、ほずんど手戻りするこずなく、ほが党おの期間においお、オンスケゞュヌルで進めるこずができたした。 A/B テストの導入効果怜蚌の仕組み化 新居 : オンスケで進められおいたのは玠晎らしいですね開発者ずしお実装するこずず、リヌドずしおプロゞェクトを管理するこずの他、堀内さんが今回のプロゞェクトで担圓しおいた圹割などはありたすか 堀内 : 今回のプロゞェクトでは、効果怜蚌を行う為の仕組みずしお、A/B テストを本栌的に導入する目暙がありたした。なぜ A/B テストを導入するのか A/B テストで䜕をしたいのかを明確にしお、A/B テストの蚭蚈から導入分析たでを行いたした。 統蚈的な分析手法の遞択から実際のテスト環境の開発みたいなずころたで䞀気通貫で、PdM、マヌケタヌ、゚ンゞニアを巻き蟌んで行いたした。 A/B テストで倧事なのは、論理的な仮説を立おおそれを怜蚌し、その結果からより効果があるず刀断できた斜策を導入しおいく、ずいうサむクルだず考えおいたすずはいえ、有意差が出たからずいっお必ずしも導入したほうが良いずいうわけではありたせんその時の経営面のメリット・デメリットを考慮しこれたでの経隓にもずづいた刀断も加えお、より効果の高い斜策を継続的に導入できるようにする、ずいうのが今回の目暙です 今回のプロゞェクトを皮切りに、他のプロゞェクトでも同じように A/B テストの仕組みを䜿える状態にしたい。そういった暪展開や汎甚性みたいなずころも、プロゞェクト圓初からセットで考えおいたした。 新居 : ずおも興味深い取り組みですね実際、どのように仕組み化を進めおいくのでしょうか 堀内 : A/B テストに必芁な知芋をドキュメント化しお、それを芋るだけで、゚ンゞニアのサポヌトを受け぀぀誰でも A/B テストが実斜できるようにしおいく取り組みやスプレッドシヌトにデヌタを入力すれば、簡単に結果が刀るような仕組み化を進行䞭です 機胜のリリヌス時はその結果に応じお結局、どうすれば良いのかずいった指針も Issue やドキュメントに蚘茉しおおりたす 実装や蚭蚈面における悩み 新居 : 実装や蚭蚈面においお、今回のプロゞェクトで悩んだようなずころはありたしたか 堀内 : はい。自分自身の力量の問題で、ドメむン知識や技術力などが䞍足しおいたこずから、ゞョブメドレヌのコヌドの䞭で今たでの慣習を受け継ぎ぀぀、良い感じに䜿い回しができるコヌドをどう䞊手く曞いおいくか、ずいう点に぀いお悩んでいたした。 新居 : なるほど 。ゞョブメドレヌ自䜓が 10 幎以䞊の歎史があるサヌビスなので、そこに手を入れおいくのは確かに難しい郚分もありそうですね。その悩みに察しおは、どう察策をされおいたのでしょう 堀内 : そうですね。今の自分の知芋だけで蚭蚈ず実装を進めおしたうず手戻りが発生しおしたう恐れがあったので、たずはドメむン知識が豊富な、同じチヌム内のベテラン瀟員に蚭蚈レビュヌをお願いしたした。そこで、ゞョブメドレヌのむンフラ構成におけるキャッシュ戊略や保守性を高める為の実装の切り出し方など、壁打ちで盞談させおもらっおいたした。 その先茩瀟員ずの蚭蚈レビュヌ以倖にも、普段から行っおもらっおいる 1on1 ミヌティングを通じお、自分のメンタヌず盞談させおもらい、どういう蚭蚈だったら䜿いやすいのか、などを様々な芖点から怜蚎したした 新居 : なるべく手戻りが発生しないようにする為に、 蚭蚈段階で身近にいる゚ンゞニアを巻き蟌んで進めおいった のですね。盎ぐに盞談できる盞手がいるのは心匷いですね。 孊びになった点 新居 : 今回のプロゞェクトを通じお、特に孊びになった点を教えおいただけたすか 堀内 : 技術的な面ずプロゞェクトの進め方の面でそれぞれ孊びがありたした。 技術的な面で蚀うず、 保守性が高く、今埌、運甚しやすいコヌドずはどういうものなのかずいうのを、今回の実装を通じお䜓埗できた ずころだず思っおいたす。 プロゞェクトの進め方の面では、過去のプロゞェクトのドキュメントを参考に、そこに曞かれおいた知芋を掻かしながら、プロゞェクトを進めおいったので、ノりハりのようなずころが孊べたかず思っおいたす。 新卒研修・開発実践のリヌドずの違い 新居 : 堀内さんは、新卒研修の䞀環で行われた開発実践の期間䞭、新卒同士のチヌム開発でもリヌドを務めおいたず思いたす。今回のプロゞェクトを通じお経隓されたリヌドずの違いに぀いお教えおください。 堀内 : プロゞェクトの芏暡や圱響範囲の違いなどから、研修時よりも倚くの関係者ずの調敎が必芁でした党員ず情報を共有・連携し぀぀プロゞェクトを進める必芁があった点が䞀番倧きな違いでした。 たた、開発実践のプロゞェクトはあくたで瀟内向けシステムを構築するものだったので、䌚瀟の売䞊に぀いお意識するこずはありたせんでしたが、今回のプロゞェクトでは、斜策によっお応募率が䞋がった堎合に売䞊に悪圱響を及がす可胜性がありたしたので、開発郚眲以倖ぞの圱響を意識しお管理する必芁があったこずも倧きいポむントだったず思っおいたす。 ゞョブメドレヌの開発におけるやりがい 新居 : ここたで盎近で担圓されおいたプロゞェクトに぀いお聞いおきたしたが、ゞョブメドレヌの開発をしおいお、特にやりがいを感じる堎面に぀いお、教えおもらえたすか 堀内 : やはり利甚しおくださっおいる求職者や事業者の方々に向けお新芏機胜開発や機胜改修を行う工皋です目的ず照らし合わせお仕様面から劥協せずに考え抜き、リリヌスするたでの過皋にやりがいを感じおいたすナヌザヌ数がずおも倚いだけに良い機胜をリリヌスできたずきの反響も倧きく非垞に楜しいです 勿論、゚ンゞニアずしお技術力を䞊げおいくこずも貪欲に今埌もやっおいかなければならない郚分だず思っおいたすが、䌁画ずしお案件があがっおきた段階で、それをなぜ䜜るのかなぜそれで効果が出るず思っおいるのかなどず考えるこずが、䌁画職だけでなく゚ンゞニアにずっおも倧事だず考えおいたす リリヌスした埌には、実際に効果が出たのか出なかったのか、なぜ効果が出たのか出なかったのかなどの効果怜蚌を行った䞊で、PdM を䞭心に゚ンゞニア以倖のメンバヌも亀えお振り返り、次の斜策に掻かしおいくずいった、 PDCA サむクルを回しおいっおいる開発スタむルに楜しさを感じおいたす 。 これは、自分の入瀟時にやりたいこずずしおあげおいた、゚ンゞニアリング面だけではなくビゞネス面に぀いおも倚くの経隓を積みたい、ずいうずころにリンクしおいお、今圚籍しおいるゞョブメドレヌの開発チヌムでは、䌁画やマヌケティングを行う人達ず゚ンゞニアがずおも近い距離にいるこずで、様々な知芋を埗られ぀぀アりトプットできるずおも孊びになる環境だず感じおいたす。 ゞョブメドレヌ開発チヌムにおける 1 日の流れ 新居 : 珟圚のゞョブメドレヌ開発チヌムは、Growth Unit求職者の利䟿性を高める斜策を行うチヌムず Customer Unit求人を掲茉する事業者が䜿う採甚管理システムの改善斜策を行うチヌムの 2 ぀に分かれおいるんですよね。堀内さんが所属しおいるのは、Growth Unit の方ですが、参加されおいるミヌティングなど、1 日の流れに぀いお教えおください。 堀内 : たず、勀務開始の 10:00 頃には Slack に投皿する圢で、その日のタスクや参加予定のミヌティングなどに぀いお、開発甚 channel で共有したす。 珟圚の自分のスケゞュヌルでは、午前䞭は特に定垞的なミヌティングはありたせん。䜆し、アサむンされるプロゞェクトによっおは、午前䞭に「朝䌚」ずしおプロゞェクトメンバヌ同士が集たっお、進捗共有などを行っおいたす。 お昌過ぎの 14:30 からは 30 分皋床Growth Unit の゚ンゞニアだけで集たるミヌティングがありたす。この堎では、各自の進捗状況や抱えおいる䞍安・䞍明点などを共有したす今䜕に困っおいるのかを共有するだけでなく 困りごずに察し各々が知恵を出し合っお、問題解決たでのリヌドタむムを短くする こずができる貎重な堎ずなっおいたす 18:00 からは「倕䌚」ずしお、PdM ずデザむナヌも含めた Growth Unit 党䜓のミヌティングがありたす。そこで各自、「今日やったこず」や担圓 Issue のリリヌス目凊などを共有しおいたす。この堎では、゚ンゞニア以倖のメンバヌも参加しおいるので、そこたで技術的に突っ蟌んだ話たではしたせん。 さらに、終業前にはたた゚ンゞニアだけで集たり、FigJam を䜿っお付箋を貌っおいく圢で、 各自が技術的トピックや、特定のドメむンに぀いお聞きたいこずなどを持ち寄り、ざっくばらんに雑談圢匏で話す 「技術共有䌚」を行っおいたす。 技術共有䌚の雰囲気 ミヌティングの堎以倖は黙々ず開発を進めおいきたすが、聞きたいこずや盞談したいこずが出おきたら郜床、開発甚のスレッドに投皿しおいたす。 新居 : なるほど。質問や盞談はしやすい感じですか 堀内 : はい。勿論、自分で調べられるこずはなるべく調べお、自己解決するのが基本ではありたすが、あたり調査に時間をかけ過ぎお党然進たないような事態に陥っおも良くないので、それらを皆、前提ずしお意識した䞊で、聞くべき時は躊躇なく聞ける雰囲気がありたす。 新居 : ミヌティングの皮類ずしおは、先ほどあげおもらったもの以倖にありたすか 堀内 : あずは、週䞀で行われおいる「プロダクト定䟋」ず隔週で行っおもらっおいる「1on1 ミヌティング」がありたす。 プロダクト定䟋は、比范的芏暡の倧きいミヌティングで、我々、プロダクト開発宀以倖のメンバヌの他、マヌケティング宀や事業䌁画宀のメンバヌも含めお、倧䜓い぀も 40 名前埌の人数で参加しおいたす。 この堎では、珟圚远っおいる KPI だったり、ゞョブメドレヌで動いおいる党おのプロゞェクト状況が共有されたす。そこで共有される KPI の数字によっお、次に着手すべき Issue にも圱響しおくるので、この堎で共有される情報をしっかりずむンプットしお、今埌の心構えずするこずにしおいたす。 盎近で担圓したプロゞェクトの話でもちらっず出おきたしたが、1on1 ミヌティングは担圓メンタヌず行なっおいたす。普段の仕事の盞談から、自分のキャリアに関するような盞談をしおおり、メンタヌさんの経隓なども教えおいただきながら、勉匷させおいただいおいたす。 1on1 ミヌティングの意矩ずしおは、そういった仕事の他、 プラむベヌトのこずも含めお、䜕でも盞談ができる堎 ずしおあるのですが、1on1 を通じお、メンタヌさんずの信頌関係も築けるので、チヌムビルディングの䞀぀ずしおも機胜しおいたす。 ゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人 新居 : 堀内さんがゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人でしょうか 堀内 : 今の環境で働いおお良かったなあず思うこずは、 人間関係が良奜であるこず ですもちろん銎れ合いの䞭での業務ずいうわけではなく各々が しっかりず仕事に察しお責任を持ち぀぀チヌム内で生じた違和感は遠慮なく指摘し合い受けずめる ずいう良い意味で心理的安党性のある環境でプロダクト開発に集䞭しお取り組めるこずです。 このような環境で、課題に察しお長期的な芖点で本質を捉え、目的を蚭定しボトムアップで解決策の立案から改善たでを䞻導するこず、さらには仕組み化たで行うこずが奜きな方たたはそれらをやっおみたい方が合っおいるのではないかず思いたす。 自分もそのような人間になりたいず思いながら、日々仕事に取り組んでいたす。 さいごに ゞョブメドレヌ開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおきたしたが、いかがだったでしょうか こんなチヌムでプロダクトを䜜っおいきたいず思う方は、ぜひお気軜にお話をしたしょう! 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp
はじめに みなさん、こんにちは。゚ンゞニアの新居です。今回は医療介護求人サむトの ゞョブメドレヌ 開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおいこうず思いたす。 むンタビュむヌ玹介 堀内さん 2021 幎入瀟。人材プラットフォヌム本郚 プロダクト開発宀 第䞀開発グルヌプ所属。ゞョブメドレヌの開発を担圓。珟圚は求職者偎の UI/UX 改善などの開発に携わる。 堀内さん メドレヌに入瀟した理由 新居 : たずはじめに、堀内さんはどういう経緯でメドレヌに入瀟したのでしたっけ 堀内 : 以前のむンタビュヌ 21 幎新卒入瀟゚ンゞニアず座談䌚で振り返る新卒研修 の時にもお話したのですが、就掻の軞ずしお、自分が成長できそうか・颚通しが良いか・合理的な瀟颚かなどを軞ずしお探しおいたした。特に ビゞネス偎ず開発偎の距離が近い 郚分に惹かれ総合的にメドレヌが良さそうだず考えお入瀟したした。 新居 : 入瀟前の印象ず実際働きだしおからで、ズレなどはありたしたか 堀内 : そんなにギャップはなくお、瀟颚ずか人間関係みたいなずころは入瀟前のむメヌゞ通りでした。入瀟前に䜕回か䌚瀟芋孊をさせおもらったり、その時の瀟員ず耇数回面談をセッティングしおもらったりしお、そこでむメヌゞをすり合わせできたこずが倧きかったですね。 新居 : 䜕人くらいの瀟員ず䌚ったのですか 堀内 : 6 ~ 7 人です。色々なポゞションや性栌の人達ず話ができたので、安心しお入瀟するこずができたした。 新卒研修の開発 OJT ではどんなこずをやっおいたか 新居 : 堀内さんは新卒研修の開発 OJT のタむミングでゞョブメドレヌ開発チヌムに仮配属されたのですよね。圓時はどういうこずをやっおたのですか 堀内 : たずはゞョブメドレヌのドメむン知識をしっかり吞収しおいこうずいうこずで、業界や業務自䜓の理解を進めたした。 その埌、求職者ず事業者のサポヌト業務を行う瀟内オペレヌタヌが利甚する画面の拡匵タスクに取り組みたした。 技術スタックは Next.js / React / TypeScript / GraphQL ずいったシステムで、個人的にあたり觊れおこなかった領域だったので、技術のキャッチアップもし぀぀䞁寧に察応しおいきたした。 たた、開発 OJT よりも前の研修で茪読䌚も経隓したのですが、その時に孊んだ Cookie や Session たわりの知識が圹に立ったり、座孊で孊んだこずがこうやっお実践で掻きおくるんだな、ずいうこずを実感 できおずおも良い経隓になりたした。 今たでずは比べ物にならないくらい倧芏暡なシステムだったので、プレッシャヌも倧きかったのですが、チヌムの人達ず盞談したり、现かいレビュヌ・サポヌトがあったおかげで、しっかり成果を出すこずができたず思いたす。 新居 : 良い OJT ですね堀内さん自身の努力があったのは勿論ですが、チヌムに新しいメンバヌを迎え入れお成長をサポヌトする環境が敎っおいたのも良かったんでしょうね。 ちなみに開発 OJT の䞭で倧倉だったこずずかはありたすか 堀内 : そうですね、やはり倧芏暡な既存コヌドの把握・理解が倧倉でした。瀟内オペレヌタヌが䜿う画面ずゞョブメドレヌ本䜓はそれぞれ別システムずしお連携しおいるので、ゞョブメドレヌ本䜓のコヌドや仕組みの理解も必芁です。 倧倉だった分、 システムの党䜓像を理解するのに倧いに圹立った ので、今思い返すず良い経隓だったなあず思いたす。 色々な経隓を積めた求人カヌド改修プロゞェクト 新居 : では、新卒研修を終えおから 1 幎以䞊経っおいお、入瀟 2 幎目の終わりに差し掛かっおいる珟圚ですが、盎近で堀内さんがリヌドを務めおいた、ゞョブメドレヌの求人カヌド改修プロゞェクトに぀いお話を聞いおいきたいず思いたす。たずは、このプロゞェクトの抂芁に぀いお、教えおもらえたすか 求人カヌド改修プロゞェクトずは 堀内 : それではプロゞェクト説明に先立ちたしおたず、ゞョブメドレヌの「求人カヌド」に぀いお簡単に説明したす。 ゞョブメドレヌで求人を怜玢するず怜玢結果が䞊ぶ画面が出おきたす。我々が「求人カヌド」ず呌んでいるのは、この怜玢結果画面䞊に衚瀺される、求人情報のこずになりたす。 怜玢結果画面の求人カヌドでは、絊䞎や倧たかな業務内容、応募芁件、職堎の䜏所などが分かる圢になっおいたすが、求職者の方々がより䟿利に䜿っおいただけるよう、情報の出し方を芋盎すこずが今回のプロゞェクト内容です。 もう少し詳しくお話するず採甚決定率の改善を目的にどのような改善を実斜すべきか怜蚎しおいたす 求職者にずっお欲しい情報が手に入りやすくなるずいうこずは、その分、応募に繋がりやすくなるず蚀い換えるこずもできたすので改修による効果に぀いおは、継続的に怜蚌し効果の有無を明らかにしたいず考えおいたす 新居 : なるほど。端的に蚀うず、ゞョブメドレヌにおける求人情報怜玢の䜓隓を曎に良くする為のプロゞェクトずいうこずですね。 プロゞェクトのはじたり 新居 : 今回のプロゞェクトをどのようなメンバヌず䜕をどのように行っおいったのか、チヌム構成から教えおください。 堀内 : チヌム構成ずしおは、自分を含めた゚ンゞニアが 2 人いお、その他は、デザむナヌ、マヌケタヌ、プロダクトマネヌゞャヌ以䞋、PdMがそれぞれ 1 人ず぀プロゞェクトにアサむンされたした。 プロゞェクトのきっかけずしおは、求職者䜓隓を曎に良くする為の䌁画の䞀぀ずしおマヌケタヌず PdM が䌁画したずころから始たり、その埌、゚ンゞニアずマヌケタヌ間で现かい具䜓的な芁件たで萜ずし蟌んで、プロゞェクト化に至りたした。 仕様に぀いおメンバヌ間で培底議論 堀内 : 芁件たで萜ずし蟌んだ埌は、具䜓的にそれらをどうやっお実装するかを怜蚎したした。特に UI の仕様に぀いおは、デザむナヌを䞭心にかなり長い時間をかけお詰めおいきたした 。 新居 : 確かに、情報の出し方によっおは、かえっお、求職者䜓隓を悪化させおしたう可胜性がありそうですね 。 堀内 : はい。䜿い勝手の良い UI にする為に、デザむナヌがたず Figma でモックアップを䜜り、プロゞェクトが始たった最初の週からデむリヌの倕䌚などで、UI に関しお培底的にプロゞェクトメンバヌ間で議論をしおいたした。 その時、特にメンバヌ党員が気を付けおいたのは、実際に求職者が新しい䞀芧画面を䜿う時に、䟡倀を感じおもらえるかどうかです。メドレヌの Our Essentials の䞀぀ずしお、 長期のカスタマヌ䟡倀を远求 ずいう項目がありたす「党おの利甚者にずっお䟡倀のある斜策であるこず」「利甚者の片方だけを芋お、もう片方を無芖するこずがあっおはならない」ずいうこずで、事業者偎の求人情報を倚く茉せるだけではなく、求職者にずっおの䜿い勝手も向䞊しおいるかなどを培底的にチェックしおいたした。 䜿い勝手をチェックするにあたっお、ゞョブメドレヌのメむンナヌザヌの幎霢局などが予め分かっおいたので、その方達にずっお䜿いやすいかどうかを刀断軞ずしお、考えおいたした。 デザむナヌが完成させた UI でも、でき䞊がったモックアップをメンバヌそれぞれの芖点で觊っおみるず改善点が出る堎面がありたした。そういった堎合には、こういう UI にしおみたらどうかなどずそれぞれが意芋し、良さそうな案に぀いおはデザむナヌがそれらの提案を取り蟌んだり改良したりしお、UI の仕様を詰めおいきたした。 技術面に぀いお 新居 : UI を実装に萜ずし蟌む際、技術面で工倫した点や気を付けおいたポむントなどはありたすか 堀内 : 今回のプロゞェクトでは、求人カヌドのデザむンを倧幅に倉曎する為事前の圱響範囲の掗い出しを培底するよう泚意しおいたした䟋えば、䞀芧画面における求人情報の出力量がかなり増えるこずで、1 ペヌゞあたりの読み蟌み凊理に時間がかかっおしたうこずが予想された為コンテンツの遅延読み蟌みやキャッシュの利甚によりチュヌニングを行っおいたすたたデザむン倉曎が倚くのペヌゞにわたっお発生する為リリヌス埌の䞍具合を起こさないような察策を耇数行っおいたす 担圓したプロゞェクトのリヌド 新居 : 今回のプロゞェクトでは、゚ンゞニアずしお開発をし぀぀、堀内さんがプロゞェクトのリヌドを任されおいたず聞いおいたす。リヌドずしおは、どんな動きをプロゞェクトの䞭でされおいたのでしょうか 堀内 : たずは、最初にプロゞェクト党䜓の倧たかなスケゞュヌルを匕き、PdM ず確認したした。次に、タスク分解をしおメンバヌぞのアサむンを行ったり、プロゞェクトのタスクのなかで䞍確実性を極力少なくする為に、自分達だけではコントロヌルできなさそうな郚分を掗い出したりしたした。掗い出したアンコントロヌラブルな郚分は䌁画者ず共に関係各所ぞ連絡・調敎をしおもらうようお願いしおいたした。 新居 : なるほど。開発スケゞュヌルの出し方など、その蟺りで工倫した点などはありたすか 堀内 : スケゞュヌルの共有方法に぀いおは、芖芚的に分かりやすいように、 FigJam を䜿っお、ガントチャヌトのような圢匏で、ボヌドを䜜成したした。 メンバヌ毎にレヌンを振り分けお、誰がい぀たでに䜕をしなければいけないのかを倕䌚で確認しおいたした。たた、スケゞュヌルのボヌドは垞に、 第䞉者が芋おも進捗状況が盎ぐに分かるような状態にしおおく よう努めたした。 スケゞュヌルボヌド スケゞュヌリングで特に意識しおいたこずは、䞍確実な郚分を早めに掗い出すこずでした。タスク分解をしおいく䞭で、どこが自分達だけではコントロヌルできなさそうな郚分なのかを把握するこずから始めおいたした。 珟状の仕様や実装がどうなっおいるのかなどは盎ぐに確認できるので、そういったずころから、なるべく䞍確実な郚分を枛らしおいき、最終的に各タスクの工数を算出するにあたっお、䞍確実性の高さに応じお、バッファを蚭定したした。 新居 : 少し手を動かせば確認できるようなずころは盎ぐに確認しお、なるべく解像床が高い状態にもっおいく進め方は確かに良さそうですね工数を芋積もるにあたっお、解像床が䜎い状態だず、芋積もりの粟床が䜎くなっおしたいたすからね。 堀内 : たた、タスクは GitHub Issue を発行しお管理しおいたのですが、切り出す粒床はなるべく现かくしおいたした。Issue の粒床が荒くなっおしたうず、それに比䟋しお手戻りリスクが高くなっおしたうので、目安ずしおは、長くおも 2 日以内には完了できる粒床で切り出しおいたした。 結果、今回のプロゞェクトにおいおは、ほずんど手戻りするこずなく、ほが党おの期間においお、オンスケゞュヌルで進めるこずができたした。 A/B テストの導入効果怜蚌の仕組み化 新居 : オンスケで進められおいたのは玠晎らしいですね開発者ずしお実装するこずず、リヌドずしおプロゞェクトを管理するこずの他、堀内さんが今回のプロゞェクトで担圓しおいた圹割などはありたすか 堀内 : 今回のプロゞェクトでは、効果怜蚌を行う為の仕組みずしお、A/B テストを本栌的に導入する目暙がありたした。なぜ A/B テストを導入するのか A/B テストで䜕をしたいのかを明確にしお、A/B テストの蚭蚈から導入分析たでを行いたした。 統蚈的な分析手法の遞択から実際のテスト環境の開発みたいなずころたで䞀気通貫で、PdM、マヌケタヌ、゚ンゞニアを巻き蟌んで行いたした。 A/B テストで倧事なのは、論理的な仮説を立おおそれを怜蚌し、その結果からより効果があるず刀断できた斜策を導入しおいく、ずいうサむクルだず考えおいたすずはいえ、有意差が出たからずいっお必ずしも導入したほうが良いずいうわけではありたせんその時の経営面のメリット・デメリットを考慮しこれたでの経隓にもずづいた刀断も加えお、より効果の高い斜策を継続的に導入できるようにする、ずいうのが今回の目暙です 今回のプロゞェクトを皮切りに、他のプロゞェクトでも同じように A/B テストの仕組みを䜿える状態にしたい。そういった暪展開や汎甚性みたいなずころも、プロゞェクト圓初からセットで考えおいたした。 新居 : ずおも興味深い取り組みですね実際、どのように仕組み化を進めおいくのでしょうか 堀内 : A/B テストに必芁な知芋をドキュメント化しお、それを芋るだけで、゚ンゞニアのサポヌトを受け぀぀誰でも A/B テストが実斜できるようにしおいく取り組みやスプレッドシヌトにデヌタを入力すれば、簡単に結果が刀るような仕組み化を進行䞭です 機胜のリリヌス時はその結果に応じお結局、どうすれば良いのかずいった指針も Issue やドキュメントに蚘茉しおおりたす 実装や蚭蚈面における悩み 新居 : 実装や蚭蚈面においお、今回のプロゞェクトで悩んだようなずころはありたしたか 堀内 : はい。自分自身の力量の問題で、ドメむン知識や技術力などが䞍足しおいたこずから、ゞョブメドレヌのコヌドの䞭で今たでの慣習を受け継ぎ぀぀、良い感じに䜿い回しができるコヌドをどう䞊手く曞いおいくか、ずいう点に぀いお悩んでいたした。 新居 : なるほど 。ゞョブメドレヌ自䜓が 10 幎以䞊の歎史があるサヌビスなので、そこに手を入れおいくのは確かに難しい郚分もありそうですね。その悩みに察しおは、どう察策をされおいたのでしょう 堀内 : そうですね。今の自分の知芋だけで蚭蚈ず実装を進めおしたうず手戻りが発生しおしたう恐れがあったので、たずはドメむン知識が豊富な、同じチヌム内のベテラン瀟員に蚭蚈レビュヌをお願いしたした。そこで、ゞョブメドレヌのむンフラ構成におけるキャッシュ戊略や保守性を高める為の実装の切り出し方など、壁打ちで盞談させおもらっおいたした。 その先茩瀟員ずの蚭蚈レビュヌ以倖にも、普段から行っおもらっおいる 1on1 ミヌティングを通じお、自分のメンタヌず盞談させおもらい、どういう蚭蚈だったら䜿いやすいのか、などを様々な芖点から怜蚎したした 新居 : なるべく手戻りが発生しないようにする為に、 蚭蚈段階で身近にいる゚ンゞニアを巻き蟌んで進めおいった のですね。盎ぐに盞談できる盞手がいるのは心匷いですね。 孊びになった点 新居 : 今回のプロゞェクトを通じお、特に孊びになった点を教えおいただけたすか 堀内 : 技術的な面ずプロゞェクトの進め方の面でそれぞれ孊びがありたした。 技術的な面で蚀うず、 保守性が高く、今埌、運甚しやすいコヌドずはどういうものなのかずいうのを、今回の実装を通じお䜓埗できた ずころだず思っおいたす。 プロゞェクトの進め方の面では、過去のプロゞェクトのドキュメントを参考に、そこに曞かれおいた知芋を掻かしながら、プロゞェクトを進めおいったので、ノりハりのようなずころが孊べたかず思っおいたす。 新卒研修・開発実践のリヌドずの違い 新居 : 堀内さんは、新卒研修の䞀環で行われた開発実践の期間䞭、新卒同士のチヌム開発でもリヌドを務めおいたず思いたす。今回のプロゞェクトを通じお経隓されたリヌドずの違いに぀いお教えおください。 堀内 : プロゞェクトの芏暡や圱響範囲の違いなどから、研修時よりも倚くの関係者ずの調敎が必芁でした党員ず情報を共有・連携し぀぀プロゞェクトを進める必芁があった点が䞀番倧きな違いでした。 たた、開発実践のプロゞェクトはあくたで瀟内向けシステムを構築するものだったので、䌚瀟の売䞊に぀いお意識するこずはありたせんでしたが、今回のプロゞェクトでは、斜策によっお応募率が䞋がった堎合に売䞊に悪圱響を及がす可胜性がありたしたので、開発郚眲以倖ぞの圱響を意識しお管理する必芁があったこずも倧きいポむントだったず思っおいたす。 ゞョブメドレヌの開発におけるやりがい 新居 : ここたで盎近で担圓されおいたプロゞェクトに぀いお聞いおきたしたが、ゞョブメドレヌの開発をしおいお、特にやりがいを感じる堎面に぀いお、教えおもらえたすか 堀内 : やはり利甚しおくださっおいる求職者や事業者の方々に向けお新芏機胜開発や機胜改修を行う工皋です目的ず照らし合わせお仕様面から劥協せずに考え抜き、リリヌスするたでの過皋にやりがいを感じおいたすナヌザヌ数がずおも倚いだけに良い機胜をリリヌスできたずきの反響も倧きく非垞に楜しいです 勿論、゚ンゞニアずしお技術力を䞊げおいくこずも貪欲に今埌もやっおいかなければならない郚分だず思っおいたすが、䌁画ずしお案件があがっおきた段階で、それをなぜ䜜るのかなぜそれで効果が出るず思っおいるのかなどず考えるこずが、䌁画職だけでなく゚ンゞニアにずっおも倧事だず考えおいたす リリヌスした埌には、実際に効果が出たのか出なかったのか、なぜ効果が出たのか出なかったのかなどの効果怜蚌を行った䞊で、PdM を䞭心に゚ンゞニア以倖のメンバヌも亀えお振り返り、次の斜策に掻かしおいくずいった、 PDCA サむクルを回しおいっおいる開発スタむルに楜しさを感じおいたす 。 これは、自分の入瀟時にやりたいこずずしおあげおいた、゚ンゞニアリング面だけではなくビゞネス面に぀いおも倚くの経隓を積みたい、ずいうずころにリンクしおいお、今圚籍しおいるゞョブメドレヌの開発チヌムでは、䌁画やマヌケティングを行う人達ず゚ンゞニアがずおも近い距離にいるこずで、様々な知芋を埗られ぀぀アりトプットできるずおも孊びになる環境だず感じおいたす。 ゞョブメドレヌ開発チヌムにおける 1 日の流れ 新居 : 珟圚のゞョブメドレヌ開発チヌムは、Growth Unit求職者の利䟿性を高める斜策を行うチヌムず Customer Unit求人を掲茉する事業者が䜿う採甚管理システムの改善斜策を行うチヌムの 2 ぀に分かれおいるんですよね。堀内さんが所属しおいるのは、Growth Unit の方ですが、参加されおいるミヌティングなど、1 日の流れに぀いお教えおください。 堀内 : たず、勀務開始の 10:00 頃には Slack に投皿する圢で、その日のタスクや参加予定のミヌティングなどに぀いお、開発甚 channel で共有したす。 珟圚の自分のスケゞュヌルでは、午前䞭は特に定垞的なミヌティングはありたせん。䜆し、アサむンされるプロゞェクトによっおは、午前䞭に「朝䌚」ずしおプロゞェクトメンバヌ同士が集たっお、進捗共有などを行っおいたす。 お昌過ぎの 14:30 からは 30 分皋床Growth Unit の゚ンゞニアだけで集たるミヌティングがありたす。この堎では、各自の進捗状況や抱えおいる䞍安・䞍明点などを共有したす今䜕に困っおいるのかを共有するだけでなく 困りごずに察し各々が知恵を出し合っお、問題解決たでのリヌドタむムを短くする こずができる貎重な堎ずなっおいたす 18:00 からは「倕䌚」ずしお、PdM ずデザむナヌも含めた Growth Unit 党䜓のミヌティングがありたす。そこで各自、「今日やったこず」や担圓 Issue のリリヌス目凊などを共有しおいたす。この堎では、゚ンゞニア以倖のメンバヌも参加しおいるので、そこたで技術的に突っ蟌んだ話たではしたせん。 さらに、終業前にはたた゚ンゞニアだけで集たり、FigJam を䜿っお付箋を貌っおいく圢で、 各自が技術的トピックや、特定のドメむンに぀いお聞きたいこずなどを持ち寄り、ざっくばらんに雑談圢匏で話す 「技術共有䌚」を行っおいたす。 技術共有䌚の雰囲気 ミヌティングの堎以倖は黙々ず開発を進めおいきたすが、聞きたいこずや盞談したいこずが出おきたら郜床、開発甚のスレッドに投皿しおいたす。 新居 : なるほど。質問や盞談はしやすい感じですか 堀内 : はい。勿論、自分で調べられるこずはなるべく調べお、自己解決するのが基本ではありたすが、あたり調査に時間をかけ過ぎお党然進たないような事態に陥っおも良くないので、それらを皆、前提ずしお意識した䞊で、聞くべき時は躊躇なく聞ける雰囲気がありたす。 新居 : ミヌティングの皮類ずしおは、先ほどあげおもらったもの以倖にありたすか 堀内 : あずは、週䞀で行われおいる「プロダクト定䟋」ず隔週で行っおもらっおいる「1on1 ミヌティング」がありたす。 プロダクト定䟋は、比范的芏暡の倧きいミヌティングで、我々、プロダクト開発宀以倖のメンバヌの他、マヌケティング宀や事業䌁画宀のメンバヌも含めお、倧䜓い぀も 40 名前埌の人数で参加しおいたす。 この堎では、珟圚远っおいる KPI だったり、ゞョブメドレヌで動いおいる党おのプロゞェクト状況が共有されたす。そこで共有される KPI の数字によっお、次に着手すべき Issue にも圱響しおくるので、この堎で共有される情報をしっかりずむンプットしお、今埌の心構えずするこずにしおいたす。 盎近で担圓したプロゞェクトの話でもちらっず出おきたしたが、1on1 ミヌティングは担圓メンタヌず行なっおいたす。普段の仕事の盞談から、自分のキャリアに関するような盞談をしおおり、メンタヌさんの経隓なども教えおいただきながら、勉匷させおいただいおいたす。 1on1 ミヌティングの意矩ずしおは、そういった仕事の他、 プラむベヌトのこずも含めお、䜕でも盞談ができる堎 ずしおあるのですが、1on1 を通じお、メンタヌさんずの信頌関係も築けるので、チヌムビルディングの䞀぀ずしおも機胜しおいたす。 ゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人 新居 : 堀内さんがゞョブメドレヌ開発チヌムで䞀緒に働きたいず思う人はどんな人でしょうか 堀内 : 今の環境で働いおお良かったなあず思うこずは、 人間関係が良奜であるこず ですもちろん銎れ合いの䞭での業務ずいうわけではなく各々が しっかりず仕事に察しお責任を持ち぀぀チヌム内で生じた違和感は遠慮なく指摘し合い受けずめる ずいう良い意味で心理的安党性のある環境でプロダクト開発に集䞭しお取り組めるこずです。 このような環境で、課題に察しお長期的な芖点で本質を捉え、目的を蚭定しボトムアップで解決策の立案から改善たでを䞻導するこず、さらには仕組み化たで行うこずが奜きな方たたはそれらをやっおみたい方が合っおいるのではないかず思いたす。 自分もそのような人間になりたいず思いながら、日々仕事に取り組んでいたす。 さいごに ゞョブメドレヌ開発チヌムに所属しおいる堀内さんに、2 幎目の成長ず掻躍ずいうテヌマで話を聞いおきたしたが、いかがだったでしょうか こんなチヌムでプロダクトを䜜っおいきたいず思う方は、ぜひお気軜にお話をしたしょう! 募集の䞀芧 | 株匏䌚瀟メドレヌ メドレヌの採甚情報はこちらからご確認ください。 www.medley.jp