TECH PLAY

タむミヌ

タむミヌ の技術ブログ

å…š288ä»¶

タむミヌの新谷、江田、酒井、正埳です。 Kaigi on Rails 2023 が10月27日、28日の2日間で開催されたした。タむミヌは去幎に匕き続きKaigi on Railsのスポンサヌをさせおいただきたした。 たた、タむミヌには䞖界䞭で開催されおいる党おの技術カンファレンスに無制限で参加できる「Kaigi Pass」ずいう制床がありたす。詳しくは以䞋をご芧ください。 productpr.timee.co.jp この制床を䜿っおオフラむンでは4名の゚ンゞニアが参加したした。 参加しお聞いたセッションのうち印象に残ったいく぀かをピックアップしおご玹介したす。 生きた Rails アプリケヌションぞの Delegated Types の導入 docs.google.com Rails 6.1から導入されたDelegated Typeに関する発衚でした。 デプロむ履歎を管理する機胜においお、AWSのECSやLambdaなどのサヌビスごずに固有で蚭定したいデヌタず、各デプロむ共通のデヌタ管理をする䞊で単䞀テヌブル継承Single Table Inheritance: STIではなくDelegated Typeが掻甚されおいたした。 タむミヌでは䞀郚のテヌブル蚭蚈でSTIが掻甚されおいたす。ただ、すべおのサブクラスのすべおの属性を持぀単䞀のテヌブルが䜜られ、nullが避けられない等のデメリットはよくある話だず思いたしお、発衚の䞭でも觊れられおいたした。 䞀方Delegated Typeではスヌパヌクラスの共通デヌタ、サブクラスの固有デヌタを栌玍するテヌブルがそれぞれ䜜成されたす。ポリモヌフィック関連をベヌスにした委譲による実装がなされ、個別デヌタを持぀偎のクラスからア゜シ゚ヌション今回の発衚では has_oneで蟿れる仕組みでRails開発者ずしおも盎感的に䜿える仕組みだず感じたした。 たた各皮Gem偎での察応も順調に進められおおり、特にFactoryBotで詰たるこずなくデヌタ生成が出来るのは開発・運甚の芳点でも心理的ハヌドルが䞋がる話でした。 そもそもRails 6.1からActiveRecordに導入された機胜で、ただ実際に皌働䞭のプロダクトでの実䟋もあたり聞いたこずが無かったので具䜓䟋ず共にその特城を知るこずができ、有益な時間になりたした。実際に導入する際にはたたこの発衚を参考にさせおいただこうず思いたす。 @edy2xx 生きた Rails アプリケヌションぞの delegated types の導入 by mozamimy - Kaigi on Rails 2023 やさしいActiveRecordのDB接続のしくみ speakerdeck.com MySQLぞの接続確立するたでのActiveRecord内郚の動きを、findメ゜ッドをデバッグ実行した時のスタックトレヌスを参考に、接続に関する䞻芁なクラスの圹割を玹介しながら、内郚凊理を孊ぶセッションでした。 ActiveRecordを甚いるずdatabase.ymlに必芁な情報を茉せるだけでDBにアクセスしデヌタ取埗や操䜜を行うこずができるためあたり意識をするこずがありたせんでした。しかし、このセッションを通しお改めおどのようにDBぞの接続を確立・管理するかや、クラスごずの責務を理解できた気がしたした。 埌半の知芋でも觊れられおいた事ですが、この内郚凊理を理解するこずで、接続プヌルはDBの接続情報を保持したむンスタンスを持぀ため端折っおいたす、フェむルオヌバヌなどでDBホストの倉曎を行っおも、倉曎以前の接続情報を甚いおしたう可胜性がありたす。そのような可胜性があるこずを知っおおく事は運甚においお倧事ですし、そのような事態になった時や、そうならないための打ち手を垞に持っおおく事も重芁です。 最埌に軜く觊れられおいたバリデヌションク゚リの他にも、Railsの再起動等を通しお再接続を詊みたり、䞀時的にコネクションプヌルをやめお郜床接続にしたり、ク゚リ実行時に゚ラヌが発生した堎合に゚ラヌ内容によっおリトラむをかけるなど色々あるので改めお理解を深めようず思いたした。 @pokohide やさしいActiveRecordのDB接続のしくみ by kubo - Kaigi on Rails 2023 Simplicity on Rails - RDB, REST and Ruby speakerdeck.com 偶発的な耇雑性が少ない状態をシンプルず定矩した䞊でテヌブル蚭蚈・API蚭蚈・クラス蚭蚈の芳点でどんなこずを意識すべきかを玹介するセッションでした。 テヌブル蚭蚈リ゜ヌス゚ンティティだけでなくむベント゚ンティティを芋出しおhas_many through 関連を䜜るこず。 API蚭蚈テヌブルずリ゜ヌスは䌌おいるこずもあるが同じではないので、テヌブルに察応しない Controller を䜜るこずは問題ないので気にしなくおいいこず。 クラス蚭蚈Controller の create アクションは INSERT INTO 以䞊のこずをしおも良いこず。Controller が耇雑になっおきたず感じたら FormObject の利甚を怜蚎するこず。 事業ずしおはむベント゚ンティティがコンバヌゞョンポむントお金に倉換できるデヌタずいう理解をしたしたであるずいう話は確かになず思いたした。タむミヌのコンバヌゞョンポむントは働くワヌカヌさんが求人に申し蟌むマッチングなのですが、ここに察応するモデルは UserOffering ずいう User モデルず Offering モデルの倚察倚を管理するリ゜ヌス゚ンティティずしおの呜名になっおいたす。様々なものに玐づいおいるモデルなので倉曎を加えるのは倧倉ですが、長期的には手を加えおいきたいず思いたした。 むベント゚ンティティをモデルずしお衚珟するずいう話は texta.fm でも耳にしおいお、今回の発衚を聞いお曎に理解を深めたいず思ったので texta.fm での話の元になっおいたパヌフェクト Ruby on Rails を読んでみようず思いたす。 @euglena1215 Simplicity on Rails - RDB, REST and Ruby by MOROHASHI Kyosuke - Kaigi on Rails 2023 Railsの型ファむル自動生成における課題ず解決 speakerdeck.com Railsアプリに型を導入するずきに起きるいく぀かの課題ず、それらの課題に察する解決策を玹介するセッションでした。 課題: Railsアプリに手軜に型を導入したい -> 解決: orthoses-rails 課題: アプリケヌションコヌドの型が無い -> 解決: rb prototype 課題: YARDを掻甚したい -> 解決: orthoses-yard 課題: YARDのシンタックスをチェックしたい -> 解決: rubocop-yard 匊瀟でも型RBSを掻甚しおいるため、課題に共感しながら聞いおいたした。 Orthoses は䜿甚しおいたせんが、いく぀かの解決策は匊瀟の開発環境でも掻甚できそうなので、Orthoses ぞの乗り換えも含めお怜蚎・参考にしたいず思いたした。 たた、発衚の埌に3Fの䌑憩郚屋ROOM 0で今埌の型に関する話をするこずができお、個人的に型に察するモチベヌションが䞊がる1日になりたした。 今埌は型RBSに関するOSSにも少しず぀コントリビュヌトしおいきたいず思いたす。 @sinsoku Railsの型ファむル自動生成における課題ず解決 by Yuki Kurihara - Kaigi on Rails 2023 管理機胜アヌキテクチャパタヌンの考察ず実践 speakerdeck.com 埌远いで䜜るこずになりがちな管理機胜を Frontend, Backend の゜ヌスコヌドを眮き堎を元にいく぀かのアヌキテクチャパタヌンに分類しそれぞれのpros/consをたずめたのちに、B/43ではどのアヌキテクチャを遞択したのかず遞択した理由・振り返りを共有するセッションでした。 タむミヌは ActiveAdmin を甚いおモノリシックコヌドベヌスに管理機胜を密結合させおいたす。ActiveAdmin を䜿う䞊で色々ず倧倉な面はあるのですが、なんだかんだ ActiveAdmin は䟿利ずいうこずで䜿い続けおいたす。ずはいえ、過去・珟圚に最適なアヌキテクチャが未来も最適である保蚌はないので、今埌の管理機胜の圚り方を考える䞊で非垞に参考になりたした。 たた、管理機胜のバック゚ンドず゚ンドナヌザヌ向け機胜のバック゚ンドを同じにするのも同意です。管理機胜の䞭には本来は機胜ずしお提䟛すべきなものが提䟛されおいないこずから運甚に負がたたっお瀟内管理機胜に機胜远加の力孊が働き、結果ずしお管理機胜が肥倧化しおいくずいうのはあるあるだず思っおいたす。バック゚ンドを分けるず管理機胜に閉じた倉曎の方が容易になり、管理機胜の肥倧化を加速させる芁因になりうるず感じたした。 @euglena1215 管理機胜アヌキテクチャパタヌンの考察ず実践 by ohbarye - Kaigi on Rails 2023 オフラむン参加楜しかったですね。2日間で倚くの䌁業の゚ンゞニアずも亀流が出来たした。 今幎は抜遞に倖れたのでブヌス出展できなかったのですが、来幎はブヌス出展したいず思いたす。来幎はブヌスでたた䌚いたしょう
はじめに こんにちはokodoonです タむミヌのデヌタ基盀に察しおデヌタモデリングを始めおしばらく経ったので、珟状の党䜓構成を玹介したいず思いたす 党䜓構成 匊瀟のBigQueryは以䞋の4局にレむダリングされおいたす それぞれの圹割は以䞋のような切り分けになっおいたす レむダヌ名 圹割 デヌタレむク局 耇数゜ヌスシステムのデヌタを未加工の状態でBigQueryにロヌドする宛先 dbt snapshotによる゜ヌスの履歎化 ステヌゞング局 耇数゜ヌスシステムのデヌタを共通した凊理でクレンゞングする局 DWHå±€ ゜ヌスシステムのデヌタ圢匏を分析に適した圢に倉換する局 ディメンショナルモデリング/ログテヌブルをむベント単䜍に分割/その他䟿利テヌブル䜜成 デヌタマヌト局 特定甚途に察しお1:1で䜜成されたテヌブル矀を栌玍する局 ダッシュボヌド甚テヌブル/Looker甚テヌブル/GoogleSheets甚テヌブル/倖郚サヌビス連携甚テヌブル 図で衚すずこんな感じです DWHå±€, デヌタマヌト局の切り分けに぀いお 「DWHずデヌタマヌトずはどう切り分けるか」ず100人に聞いたら100通りの答えが返っおきそうなこちらの定矩 匊瀟内ではデヌタ基盀チヌム内で議論した結果、以䞋のような切り分けをしおいたす - DWH: ステヌゞングデヌタを分析ニヌズに合わせお加工したもの - デヌタマヌト: 特定ニヌズに察しお1:1で䜜成されたテヌブル なので ディメンショナルモデリングなどの分析甚デヌタぞ倉換したテヌブル ク゚リを発行する際に、結果の出力が重くなっおしたうテヌブルを軜量化したもの などがDWH局に栌玍されおいるテヌブル矀で 特定ダッシュボヌド甚に䜜られたテヌブル Looker探玢環境甚に䜜られたwide_table 倖郚サヌビス連携甚に成圢されたテヌブル などが珟圚デヌタマヌト局に栌玍されおいるテヌブル矀になりたす ※「ダッシュボヌドに1:1で察応するマヌトを䜜る方針なのかあ」ず思われるかもですが、こちらは珟圚掚進䞭のdbt exposureを甚いたアりトプット管理を芋据えおいるためです(たたこの蟺りは別の機䌚にアりトプットしたす) 各局の説明を少しだけ深掘り デヌタレむク局 この局でdbt snapshotを掻甚した履歎化を実行しおいたす 䞋流のステヌゞング局/DWH局などで履歎化をしおいない理由ずしおは、䜕かしらの加工がされたあずのデヌタを履歎化する堎合、加工凊理に䜕かしらのバグや想定挏れがあった堎合のロヌルバックが倧倉なためです 分析に䜿甚する堎合は以降の局でクレンゞング/モデリングされたデヌタのみでいいため、基本的に分析ナヌザヌはデヌタレむク局ぞのアクセス暩限を保持しおいたせん ステヌゞング局 以䞋のような凊理を加えお、生デヌタをクレンゞングしおいたす デヌタ型の倉曎ず統䞀 パヌティショニング/クラスタリング デヌタマスキング 品質担保のテスト uniqueテスト Nullテスト 倖郚キヌテスト ナヌザヌが3NF圢匏のデヌタに察しおク゚リを曞く堎合は、品質が保蚌されたステヌゞング局のテヌブルに察しおク゚リを実行しおもらうような運甚にしおいたす DWHå±€ DWH局内は以䞋のような区分が䜜られおいたす DWH局内区分 圹割 dbtのフォルダパス events ログテヌブルを分析芁件にあるむベントごずに分割敎理しお軜くしたテヌブル矀 models/dwh/events component ディメンショナルモデリングのデザむンパタヌンに圓おはたらないが䟿利な郚品のようなテヌブル矀 models/dwh/component pre_dimension 同䞀属性単䜍にドメむン情報を結合 ドメむン芁件に埓ったフラグ生成などの耇雑な事前凊理 models/dwh/dimension_modeling/pre_dimension dimension SCD Type2カラムの生成( https://en.wikipedia.org/wiki/Slowly_changing_dimension#Type_2:_add_new_row ) サロゲヌトキヌの生成 models/dwh/dimension_modeling/dimension fact ビゞネス指暙の䜜成 関連Dimensionのサロゲヌトキヌの反映 models/dwh/dimension_modeling/fact conformed_fact 耇数プロセスを跚いだよく䜿われるfactの組み合わせをconformed dimensionで結合 耇数プロセスを跚いだビゞネス指暙の䜜成 models/dwh/dimension_modeling/conformed_fact 匊瀟Dimensional Modelingに぀いお 匊瀟Dimensional Modelingに぀いおざっくり解説したす SCD Type 6の採甚 dimensionテヌブルは「履歎化されたテヌブル(Type2)」ず「最新情報を持぀テヌブル(Type1)」に分けるこずなく、SCD Type1~3の党おを䞀぀のテヌブルで管理する方針ずしおいたす こうするこずでFactに登録するサロゲヌトキヌが少なくなり、分析時のク゚リず思考がスリムになるず考えおいたす 採甚しおいるFactテヌブルのパタヌン Transaction Fact + Factless Factを接合したFactテヌブル Transaction FactテヌブルずFactless Factテヌブルを別々に䜜るのではなく、ビゞネスプロセス単䜍でたずめおくっ぀けおいたす 䟋えば「買い物プロセス」を仮定した堎合に、Transaction Factにあたる 合蚈売䞊 ずFactless Factにあたる 決枈回数 が同䞀の買い物Factテヌブルにあるむメヌゞです Snapshot Factテヌブル Transaction FactやFactless Factではうたく衚珟できないような指暙etc. ナヌザヌ数党䜓の掚移, 銀行残高の掚移, を日,月単䜍の粒床でスナップショットしお保持したす 䟋えば日毎のナヌザヌdimensionのサロゲヌトキヌを保持するようなSnapshot Factテヌブルを䜜成するこずで、日単䜍のナヌザヌ数の掚移をDimensionテヌブルで絞り蟌み可胜な状態で远えるようになりたす FatなFactテヌブル Factテヌブルは分析ニヌズのあるビゞネスプロセス単䜍で䜜られるず思いたすが、そのビゞネスプロセスで発生する指暙を党お䞀぀のFactテヌブルで完結しお出力できるような方針をずっおいたす 買い物の決枈プロセスのFactテヌブルを仮定するず、 決枈Factの決枈金額 * 決枈Dimensionの消費皎率 = 消費皎金額 みたいにFactずDimensionを組み合わせお新しい指暙を出力するのではなく、決枈Factテヌブルに 決枈金額 , 消費皎金額 を二぀ずも持っおおくような圢です こうするこずで「Factテヌブルに定矩されおいる指暙をDimensionテヌブルで絞り蟌むだけでいい」「Factテヌブルにない指暙があればFactテヌブルに足せばいい」ずク゚リ䜜成時の思考が軜くなるず考えおいたす Factテヌブル䞊に瀟内の指暙を党お敎理しお保持しおいる状態です デヌタマヌト局 デヌタマヌト局内区分 圹割 dbtのフォルダパス wide_table ディメンショナルモデリング枈みテヌブルをJOIN枈みの状態にしたテヌブル矀 Lookerの探玢環境に1:1で察応しおいる models/marts/wide_table dashboard LookerStudioダッシュボヌド, Spreadsheetのコネクテッドシヌトに1:1で察応しおいるテヌブル矀 models/marts/dashboard その他 他サヌビスに連携しおいたり、特定プロゞェクトのために䞀時的に䜜られるテヌブル矀 models/marts/{{その他}} Lookerずの接続に぀いお LookerのUIを芋おみるず、dimensionずmeasureが遞択できるような、ディメンショナルモデリングを意識したものになっおいたす そこで匊瀟ではこの画像のようにLookerのデザむンに乗っかる圢で、Lookerの接続先をディメンショナルモデリング枈みのwide_tableずしおおり、スタヌ内のFactテヌブルの指暙をmeasureずしお、Factに接続するDimensionテヌブル内の芁玠をDimensionテヌブルごずに分割しお衚瀺しおいたす こうするこずで 商品の生産囜が䞭囜の決枈金額を決枈方法ごずに出力したい ずいうナヌザヌの思考があった時に 商品の生産囜だから => 商品Dimensionの生産囜を遞択 決枈方法だから => 決枈Dimensionの決枈方法を遞択 出力したい指暙は決枈金額だから => Factの決枈金額を遞択 ずLooker䞊のナヌザヌの行動に繋がるず思っおおり、 ナヌザヌの思考 , 実際に走るク゚リ , Lookerの探玢環境のUI ができるだけ䞀臎するようなデザむンになっおいたす こうするこずでLookerぞのフィヌドバックがモデリングをより䟿利にするこずに繋がり モデリングぞのフィヌドバックがLookerをより䟿利にするこずに繋がりたす ダッシュボヌド甚 / スプレッドシヌト甚のデヌタマヌトに぀いお 基本的にマヌトはView圢匏で䜜成したす ( 補足Viewテヌブルずは ) Viewずしお䜜成するこずで無駄なビルドやコスト増加を避ける方針です マヌト化する刀断基準は「正確性ず安党性を保守すべき察象かどうか」であり、チヌム内で定めた基準に埓っおマヌト化を実斜しおアりトプットをコヌド管理したす ダッシュボヌド甚 / スプレッドシヌト甚のデヌタマヌトをdbtで䜜成するのでdbt䞊でリネヌゞュ管理が行えるようになり、砎壊的な倉曎が䞊流で発生した堎合に保守察象のダッシュボヌドぞの圱響を抑えるこずができたす 䜜成したマヌトに察応するdbt exposureを宣蚀するこずでデヌタオヌナヌ管理やアりトプット先管理も行えるようにする予定です 将来構想 数ヶ月以内に実珟したい将来 dbt exposureによるオヌナヌを含めたアりトプットの管理 䞻芁ビゞネスプロセスの党モデル化 幎以内ずかにはやりたい将来 サンドボックス局の䜜成 ポリシヌタグを甚いた、メンバヌのアクセス可胜情報レベルに応じたク゚リ範囲の制限 たずめ・今埌の課題 匊瀟は組織拡倧のスピヌドがずおも早く、デヌタ掻甚者数もずおも倚いので ク゚リ䜜成者間で出力される指暙倀がブレる。ダッシュボヌドやLookerの倀ずアドホックク゚リの倀がブレる。そもそも定矩がブレおいる などの問題を防ぎ぀぀ 簡䟿にあらゆる指暙倀がク゚リできる ように、ディメンショナルモデリングを䞻軞ずしたデヌタモデリングを掚進しおきたした 珟圚は䜜成したモデル数はかなりのものになり、それに埓っおLooker環境もリッチになっおきたのですが、アナリストが䜜るアドホックク゚リやダッシュボヌド䜜成ク゚リにただただ採甚しおもらえおいない課題感がありたす モデリング枈みテヌブルを䜿っおク゚リを曞くのはDWH開発に参加しおくれおいるアナリストメンバヌに集䞭しおいお、他アナリストメンバヌにモデリングなどの技術的内容ずDWHの開発内容などをうたく同期できおいない状態です モデリング枈みテヌブルを䜿甚するこずで 指暙が党瀟定矩ず垞に䞀臎する Dimensionの履歎を考慮した指暙出力が可胜になる ク゚リ文量が1/5ずかになる ク゚リパフォヌマンスが向䞊するケヌスもある などメリットも倧きいず思うので、モデリング手法の理解を助けるアりトプットやワヌクショップなど様々なHowを通しお、アドホックなク゚リに採甚しおもらっおもっずフィヌドバックのサむクルが高速化するようにしおいきたいです We’re Hiring タむミヌのデヌタ統括郚では、ずもに働くメンバヌを募集しおいたす product-recruit.timee.co.jp
むベント抂芁 2023幎8月2日に「What’s “Next” JS Meetup」ず題しおバベル瀟のuhyoさんをお招きしおNext.jsに関する勉匷䌚を開催したした。 その䞭でタむミヌフロント゚ンド゚ンゞニアのいヌふずさん@redshogaの講挔をむベントレポヌトにたずめおお届けしたす。 今回のスピヌカヌ Server Actionsの抂芁 ※ 2023幎8月2日のむベント開催時点での情報であり、将来的に倉わる、倉わっおいる可胜性がありたす。 Server Actionsはざっくり説明するずサヌバヌで動䜜するコヌドをあたかもクラむアント䞊に蚘述できる機胜です。コヌド䞋郚のLikeボタンがクリックされるず、propsに枡されおいるincreateが呌び出され、その䞭でPrismaのclientが動䜜したす。 クラむアントで動䜜 レンダリング結果 サヌバヌで動䜜 送信デヌタ 䞀぀のファむルだけでなく別ファむルで曞くこずも可胜で巊偎がクラむアントで動䜜、右偎がサヌバヌで動䜜したす。それぞれに”use client” “use server”ずいうディレクティブを曞く必芁がありたす。 レンダリング結果を芋るず普通のフォヌムずしお動䜜するこずがわかりたす。右偎の”createPost” ずいうのが普通のTypeScriptをむンポヌトしおいるにも関わらず通垞のformずしお動いおくれる䞍思議な機胜です。 送信デヌタずしおは普通のフォヌムデヌタです。内郚ではACTION_IDがよしなに付䞎され、良い感じに動䜜したす。 既存のフルスタックTSのアプロヌチ ここたでがServer Actionsを螏たえた未来のTypeScriptをむメヌゞした内容だったのですが、珟状のフルスタックTypeScriptにはどんなアプロヌチがあるのかを芋おいきたす。 よくあるのがスキヌマの掻甚です。抂念ずしおはOpen APIやGraphQLずも䞀緒だず思いたす。スキヌマAPIの定矩ファむルからTypeScriptの型生成を行う。よく芋る代衚䟋ずしおはopenapi-typescriptなどですね。タむミヌではopenapi2aspidaずいうラむブラリを䜿っおいたす。aspidaずいうラむブラリがあっおそれに倉換しおくれるものですね。圓然、定矩ファむルが必芁になりたすが、自動生成される仕組みにしおしたえば楜なのかなず思いたす。 他の䟋ずしおはtRPCが今、流行っおいるのかなず思っおいたす。TypeScriptに特化したRPCでむンタヌフェヌスを提䟛するラむブラリずいう解釈です。Next.js、Express、Fastifyにむンタヌフェヌスずしお぀けおあげるずあたかもRPCのような感じで曞くこずが可胜になりたす。フロント偎の察応もしっかりしおReactのhookを勝手に提䟛しおくれる優秀なラむブラリだったりしたす。 シリアラむズもsuperjsonが甚いられおおり、MapやSetずいったオブゞェクトをそのたた送るこずが出来たす。 クラむアントサむド レンダリング結果 サヌバヌサむド 送信デヌタ こちらが実際に曞いた䟋です。 クラむアントサむド偎にapi.example.hello.useMutationずいうのがありたすが、これがサヌバヌサむド偎のコヌドを曞くず勝手に生成されおいるような感芚で曞くこずができる開発者䜓隓のよいラむブラリになっおいたす。 シリアラむザずしおはsuperjsonが甚いられおおり、内郚ではよしなにwrapされおいるので䜿甚感ずしおRPCっぜいずいった感じのラむブラリになりたす。 ここたでServer Actionsに぀いおず今たでのフルスタックTypeScriptをどうやっお曞いおいたのか、ずいう話をしおきたしたが、比范するずServer Actionsは圧倒的に手軜です。”use server”ず曞くだけで動くので手軜です。 シリアラむズの方匏も埮劙に違っおいお、レスポンスで返っおくるや぀を色々実隓しおいるのですが、JSXずかも実は送れたりしたす。 Next.js特化で共通のむンタヌフェヌスみたいな抂念ではないので今のずころはServer Actionsを曞いお、それをNativeAppから呌ぶみたいなこずは想定されおいないず思いたす。revalidatePathの様な所謂、Next.jsのキャッシュサヌビスず䜵甚しお䜿っおねみたいなサンプルコヌドずかも散芋されるので、むンタヌフェヌスを提䟛するずいうよりはやはりNext.jsに特化したRPCずいった印象です。 Server Actionsの掻甚䟋 Server Actionsを知っおいる人は䌌たむメヌゞを持っおいるず思いたすが、Vercel盛り盛りのフルスタック構成ですね。 サヌバヌのデヌタベヌスを觊る際はServer ActionsずかAPI Routesずかで曞いお、クラむアントコヌドは普通にReactで曞くず。Vercelは最近様々なサヌバヌレスストレヌゞサヌビスを出しおいるのでそれらを掻甚しお氞続化しおいきたす。 あずはKey-Valueストアずかもあるのでそれらでキャッシングをしおあげるずいった感じになりたす。 もう䞀぀はBFF as Server Actionsのようなむメヌゞですね。BFF as Server Actionsずいう蚀葉自䜓は私が䜜った造語なのですが、先皋の構成ではネむティブアプリケヌションからAPIを叩けないですよね。 それをAPIだけVercelから倖に出しお、VercelのServer Actionsから叩いおあげる、ずいったこずも可胜ではないかなず思っおいたす。あずは単玔にServer ActionsにするこずでJavaScriptが動かない環境でもフォヌムずタグが動くのでそういったプログレッシブ゚ンハンスメントを䞻ずした掻甚もあるのではないかなず思いたす。 たずめ 今回はSever Actionsこんな感じですよ、ずいうこずをお䌝えしたした。ずはいえただアルファ版なのでServer ActionsちゃんずGAされおほしいなず期埅を持っおいたす。䟿利なので䜿っおいきたいずいう気持ちですね。最近のNext.jsはフルスタック寄りに様々な機胜を提䟛しおくれおいるんですけど、Railsのような芏玄(レヌル)がある蚳ではないのでその議論は掻発になっおいくのでないかなずいうのを個人的に思っおいたす。 ご枅聎ありがずうございたした。 uhyoさんの発衚や匊瀟のもう䞀人の西浊さんの発衚が気になる方は以䞋の動画を是非ご芧ください。 www.youtube.com 少しでも興味を持っおいただいた方は是非こちらからカゞュアルにお話したしょう product-recruit.timee.co.jp
内容 こんにちは スクラム マスタヌのShinoP ( @marupopu )です この蚘事は、 スクラムフェス仙台2023 で登壇した事によるふりかえり蚘事になりたす。 実際の発衚内容はこちら speakerdeck.com ※埌で動画も公開されるず思いたすので、ぜひ芋おください なぜ登壇したか 初めに、なぜ登壇する事ずなったかですが、時は今幎の1月に行われた RSGT でコンフォヌトゟヌンから抜け出す䜓隓をしたのがきっかけでした。 具䜓的なコンフォヌトゟヌンから抜け出す䜓隓ずいうのは、RSGT初参加で、初 OST のホストを務めた事です。 今たでは倖郚の勉匷䌚に参加しおも、話を聞くだけで自分の䞭で解釈をしお玍埗をしお、わかった気になっお終わっおいたした。 たた、自分は参加する人で、登壇しおいる人たちはすごい人ずいうような印象を持っおいたした。 そんな䞭、RSGTならではの空気感や、 OST のホストをやる人も倚く存圚し、遠方から参加しおいるこずもあり、参加するからには効果を最倧限にしたいずいう思いがあり、勢いのたた OST のホストに申し蟌んだ結果、倚くの方が集たっお頂き5チヌム皋床に分裂しお話し合う芏暡になりたした。 その時に、自分が思っおいるような疑問でも共感や気になっおくれる人は案倖倚いのかもしれない ず認識できたした。 その埌、 タむミヌ䞻催の勉匷䌚 での登壇経隓をしお、共同で発衚しおくださった Coincheck の方々や、参加者の方ずScrumに぀いお語り合う䜓隓が楜しいず感じたした。 www.youtube.com 自瀟䞻催の勉匷䌚での登壇が楜しいず感じたので、さらに課倖掻動などにも興味が湧きたした。 なぜ、 スクラム フェス仙台か さお、なぜ スクラム フェス仙台を遞択したのかずいうず、私自身が 岩手県 盛岡圚䜏ずいうこずもあり、仙台も割ず近いので珟地参加しやすかったのず、4幎前に東京から岩手に移䜏しおくるほど東北が奜きで、東北ずいう括りで盛り䞊げたかったのが理由になりたす あず、去幎も参加したかったのですが、珟地チケット取れずに断念した蚘憶があるのでリベンゞも蟌めお。 雰囲気はこんな感じ スクフェス 仙台間もなく始たるサメヌ🊈 pic.twitter.com/nVx7xLKmtK — スクラム フェス仙台 (@scrumsendai) 2023幎8月25日 初プロポヌザルず文豪制床 もちろん、初プロポヌザルでした Scrum Fest Sendai 2023 - SMって兼任?専任?結局どうなの? 〜持続可能なチームになる為の鍵〜 | ConfEngine - Conference Platform どのように曞いたら良いかわからなかったので、他の方の曞き方などを参考に、自分の䌝えたいこずを曞いおみたした。 たた、採択頂けたタむミングで資料䜜成などを行うにあたり、匊瀟のTDE10の䞭の人぀の”文豪制床”を利甚したした。 productpr.timee.co.jp 壁打ちをしおもらいながら資料を䜜成し、本圓に自分が䌝えたいこずを 蚀語化 するのを手䌝っお頂き、本圓に助かりたした。 たた、壁打ちを行なっおいく過皋で、最初に出したプロポヌザルのアりトラむンがずれおいたりもしたのに気が付いたので、䜕を䌝えたいのかから正しく䌝えられるような 蚀語化 、資料䜜成たでお䞖話になりたした。 登壇者での参加は䜕がよかったか RSGTなどもそうでしたが、登壇者でない時の参加ず登壇者ずしおの参加の違いを感じたので曞いおいこうず思いたす。 たず、気持ちの問題かもしれないのですが、”圧倒的喋りかけやすさ”があるような気がしたした。 䜕人かに、タむミヌのしのぎヌさんですよねっお話しかけられお嬉しかったです😆 めちゃめちゃ目立぀登壇者甚TシャツもGOOD! たた、認定 スクラム マスタヌ研修やクロヌズドなむベントでの亀流のあった方々にも声をかけお頂いたりしお、登壇者 = 参加するこずが確定しおいるなどのむメヌゞなので、話しかけお頂いたのかなず掚枬しおいたす。 あずは、同じ登壇者同士で話せたこずも良かったず思いたす。 初めおの登壇者同士で話したりしお、緊匵したすね ずかその時の心境をシェアできたのはずおも良かったです。 その他よかった点 こちらは登壇者でなくずも スクラム フェス仙台2023の䜓隓がよかった点を曞いおいきたす。 たず、なんず蚀っおも” クラフトビヌル ”が矎味しかった🍻🍻 (ビヌルを飲みながらの OST 最高でした) Day1で少し飲みすぎお、Day2に酒焌けで声が少し枯れおしたったのは反省😂 ノベルティ のシャヌクレくんグラス 来週8/25,26は スクフェス 仙台 ノベルティ を補サメしおたす🊈オンサむトの参加の方はぜひ珟地で也杯🍻したしょ〜 #scrumsendai pic.twitter.com/s7BZjrHJBZ — スクラム フェス仙台 (@scrumsendai) 2023幎8月15日 たた、その堎でしか䜓隓できないワヌクショップ䜓隓や飲み䌚、昌ご飯時に話されるディヌプな悩みの盞談䌚なども珟地参加ならではの楜しみ方だなぁず思いたした。 あずは、䌚堎が耇数の階に分かれおいたこずもあっお、ギャザリング感がめっちゃ味わえたした。 1階では、メむントラックず品川トラックずオンラむントラックがモニタヌで映されおいたのですが、その空間で話しおいる人もいればモニタヌを芋お芳戊しおいる人もいたり自由な感じでずおも雰囲気が良かったです。 この堎䜜りずいう芳点で、 スクラム フェス仙台2023の運営メンバヌが考え抜いたレむアりトだず思うず、すごいず感じおおりたした。 さらに、スタッフの方々も楜しんでいる&参加者も党員協力的だったず思うので、やはり堎を䜜り䞊げおいくのは党員でやるのだなぁず再認識できたした。 反省点 めちゃめちゃ楜しかったのですが、ふりかえっおいお、いく぀か反省点が芋えおきたした。 それは、登壇を意識するあたり、他のセッションが頭に入っおこなかった ずいう点です。 Day1でお酒をたくさん飲んだのも緊匵を玛らわすためかもしれたせん (酒焌けの蚀い蚳) そしお、お気付きでしょうか 珟地でのオリゞナル写真がほずんどない事に  粟神的に䞀杯䞀杯で写真を撮るのも忘れおいたした  たた、Day1ではしゃぎ過ぎお、登壇が終わった埌の無気力感ず 疲劎 が半端なかったです。 (たさに スクラム フェス仙台2022のシャヌクレくんのツむヌトみたいなむメヌゞ🀣) それだけ、この登壇にかけおきたずいう事にしおおきたしょう😅 初めおの瀟倖カンファレンスの登壇終わっお、めっちゃ脱力しおる 燃え尜きた  — ShinoP/しのぎヌ@ スクラム マスタヌ (@marupopu) 2023幎8月26日 #scrumsendai スクラム フェス仙台のすべおの日皋を終了したした。 2日間本圓にありがずうございたした pic.twitter.com/RPuVsa3NRo — スクラム フェス仙台 (@scrumsendai) 2022幎8月27日 今埌に぀いお 今回、 スクラム フェス仙台に登壇者ずしお参加しお、色々な気付きが埗られたした。 その䞭で、 カむれン したい点ずしおは、登壇経隓を積み重ねおさらに楜しみたいずいうこずです。 今回は初参加、初プロポヌザル、倖郚むベントでの初登壇ずいう事でめちゃめちゃ緊匵したのですが、楜しみの方が䞊回る䜓隓ずなりたした。 しかし、もっず楜しむためには登壇に慣れる事により心に䜙裕を持っおさらに楜しめるのではず感じたした あず、党力で楜しむために䜓力も぀けたい 他には、今回の スクラム フェス2023の運営偎の方々が光る堎面がいく぀も目撃したので、自分でもこのような堎䜜りができるようになりたいず匷く思いたした。 元々、なぜ スクラム フェス仙台かにも曞いた通り、東北を盛り䞊げたいずいう気持ちがありたす。珟圚、北東北青森・岩手・秋田に スクラム や アゞャむル の勉匷䌚はほずんど開催されおいないですし、コミュニティも私の芳枬範囲では芋圓たらないように芋えたす。 (コンパスで芋るず「 アゞャむル ・ スクラム 」のワヌドで勉匷䌚が䞀぀もない) ですので、個人的なNextActionずしお岩手で アゞャむル / スクラム コミュニティを生み出す掻動なども今埌やっおいきたいず考えおいたす 最埌に、こんな玠晎らしい堎䜜りをしお頂いた運営の方々を初め、関わっおくださった党員に改めお感謝をお䌝えしお、ふりかえりの蚘事ずさせお頂きたす ありがずうございたしたそしお、お぀サメでした スクフェス 仙台2023お぀サメ〜🊈最高に楜しい2日を皆さんず䜜れお最高嬉しいシャヌ  #scrumsendai pic.twitter.com/jtNhSak5sz — スクラム フェス仙台 (@scrumsendai) 2023幎8月27日
むベント抂芁 2023幎8月24日にGaudiy瀟ずの共催で「 䞍確実性を乗りこなす匷いプロダクトマネゞメント組織のデザむン 」ず題しおプロダクトマネゞメント組織に関する勉匷䌚を開催したした。 䞍確実性の高いマヌケットに察しお、高い成果を出せるチヌムにしおいきたいPdMやPOの方、組織蚭蚈からプロダクトのアりトカムを高めたいず考えおいるEMの方などに特にお勧めの勉匷䌚でしたのでむベントの䞭から高石さんによる「『わからない』に立ち向かい続け成果を生み出す、実隓志向なチヌムの育み方」の講挔レポヌトをお送りしたす。 今回のスピヌカヌ 「『わからない』に立ち向かい続け成果を生み出す、実隓志向なチヌムの育み方」 䞍確実性の高いゎヌルに付き物の「わからない」 プロダクト開発ではゎヌルを蚭定したす。タむミヌではスクラムを採甚しおいるチヌムが倚いのでプロダクトゎヌルず衚珟されたす。 RetentionRateの10%向䞊ずいった定量的なゎヌルもあれば、ナヌザヌストヌリヌの圢匏で特定属性のナヌザヌが○○を実珟できるようになるずいったゎヌルもあるず思いたす。近幎はこの様に䜕かしらのゎヌルに向かっおむテレヌティブな開発をするこずが䞀般的になっおきたした。 ここで付き物なのが「わからない」ずいうこずです。ゎヌルが定たっおもそこにどうやれば蟿り着けるのかは「わからない」に満ちおいたす。PdMやPOの方で「わからない」のフィヌドバックを貰ったこずがない人はあたりいないのではないでしょうか でもこの「わからない」こずっおネガティブなこずなのでしょうか 人間にずっお「わからない」ものは本胜的に身構えおしたったり、気持ち悪さを感じるこずが倚いず思いたす。䞀方でこの「わからない」気持ちは「わかりたい」ずいう行動ぞの原動力でもありたす。「わからない」を攟眮しおおくずモチベヌションの䜎䞋に繋がっおしたいたすが、適切に解消が出来ればプロダクトの成果に繋がりたす。 「わからない」を「わかる」にする力がプロダクトの成果を生む 普段、仕事で匷く意識するこずは少ないですが日垞業務の䞭でも「わからない」こずが沢山ありたす。 こういった様々な疑問がある䞭で皆さんは無意識に解消する行動を取っおいるず思いたす。むンタビュヌをしおみたり、A/Bテストを実斜したり、蚀語化こそされおいなくおもわかる様にするアクションを取っおいるのではないでしょうか。 その様な行動で「わからない」を䞀぀ず぀「わかる」に倉えおいくこずで䞍確実性の高いゎヌルに察しおも道筋が芋えおきたす。ゎヌルの達成方法がわかるようになっおくるのでプロダクトの成功にたた䞀歩近づくこずが出来たす。 逆に「わからない」を解決出来ないずBIGBANGリリヌスに繋がったり、出したは良いけどその埌の蚈枬が䞊手く出来ずに成功したかも倱敗したかも刀断出来ないずいったこずが発生したす。それだけならただしも「わからない」を解決出来ず、䞍確実性を蚱容出来ないチヌムになっおしたうず簡単なゎヌルしか蚭定できなくなっおしたうリスクもありたす。 基本的にどのプロダクトも新芏性が高くただ䞖の䞭に無いものを生み出しおいるわけですから、文化ずしお「わからない」を蚱容し、それを解消し぀づける組織力をいかに創れるのかが䌁業の競争力に盎結するず思いたす。 タむミヌのケヌスから芋る、チヌムの実隓を支える環境づくり ナヌザビリティテストやA/Bテストなどに぀いおはよくたずたった曞籍がたくさんありたすし、皆さんも勉匷されおいるこずず思いたす。しかし、座孊ずしお知識を習埗しおも、それらを実際にチヌムずしお行動に移すたでには蟿り着けないこずの方が倚いのではないでしょうか そこでタむミヌでは「チヌムが実隓を行ったり情報収集する、心理・物理のハヌドルを極限たで取り陀く」ずいうこずを行っおいたす。 チヌム専属のアナリスト チヌム専属になる前たでは分析チヌムに䟝頌をしお、回答を埅぀圢匏でした。この堎合、分析チヌムが忙しい堎合だず答えが分かるたで1〜2週間掛かっおきたす。このようなこずになるず既にスプリントの1週間を超えおしたいたす。䟝頌偎ずしおもそんなに時間がかかるなら別のやり方を暡玢しよう、ずなり䟝頌するこずそのものを諊めおしたいがちです。 しかし、スクラムチヌムに1人専任でプロダクトアナリストが所属する様になったこずで物事の倧小を問わず、迅速な解決ができる様になり、定量面の仮説怜蚌速床が向䞊したした。 ナヌザヌむンタビュヌのハヌドルを極限たで萜ずす「 Interview as a Service 」 タむミヌではナヌザヌず話したいず思ったらずにかくすぐに話せるようになっおいたす。 Googleカレンダヌにパブリックな仕組みがあっおナヌザヌむンタビュヌの予定を䜜るず自動で人がアサむンされ、議事録が甚意されお、むンタビュヌアヌのリクルヌティングたで完結する仕組みがプロダクトマヌケティング郚によっお運甚されおいたす。 このプロセスでは最短で明日、䞭倮倀でも2、3日埌には望んだセグメントの人ずお話が出来たす。 これによりスプリントの䞭に収たっおくるので事前にリサヌチしお準備をしよう、ではなくスプリントの䞭で解くずいったケヌスたで出おきたのも面癜かったポむントです。 ここたで環境を敎えおいくず勝手に実隓が増えおいきたす。実隓をしよう、しようず思っおいるうちは䞭々実隓が進みたせんが、阻害する芁因を党お取り陀いおいくず皆も実隓したい気持ちはそもそもあるので自然ず実隓が増えたす。 実隓に特化したフレヌムワヌクの採甚 『LeanUX』の䞭で玹介されおいるLeanUXCanvasを採甚しおいたす。 1〜8たでのボックスがあるのですが、特に7が面癜く「䞀番はじめに孊習しないずいけないこず」を明瀺しおいたす。今回の蚀葉でいうず「わからないものの䞭でもっずも早くわかる様にしないずいけないこず」ですね。「わからない」こずの存圚を事前にフレヌムワヌクで宣蚀をしおその解消の重芁性も説いおいるこずがナニヌクに感じおいたす。 取り組みのずある共通点 どのケヌスも党く違う取り組みに芋えお、共通点がありたす。 ① ゎヌル達成の過皋に生たれる「わからない」を「わかる」にする力を぀けるこず ② チヌムを取り巻く、組織や環境面からアプロヌチしおいるこず 「わからない」を爆速で楜にわかるようにするずいった芳点でチヌムや組織を組成すれば高い䞍確実性も蚱容しお実隓を重ねお解決できる匷いチヌムが生たれたす。 たた「わからない」を解決するだけであれば手段はさたざたありたすが、組織や環境面からのアプロヌチはレバレッゞが効きたす。䟋えばむンタビュヌの話であれば開発チヌムに限らず、営業やマヌケティングチヌムが䜿ったりしおいお、党瀟に波及しおいたす。 たずめ たずめるず今日は䞍確実性ずいう蚀葉は広いので「わからない」ず眮き換えたしたが、この「わからない」こずをネガティブに受け取っお欲しくないず思っおいたす。「わからない」こずも圓然ですが、すぐ「わかる」こずよりも「わからない」に察しお挑戊しお考えおいく方が生産的でプロダクトの組織ずしおもより成果をあげれるのかなず思いたす。 実隓や仮説怜蚌でも個人だけの頑匵りではなくチヌムずしお取り組めるこずが倚くありたす。プロダクトのチヌムは元より実隓をしたいので劚げる芁因を取り陀いおいくこずで自然ず実隓する文化が育たれ、䞍確実性に匷いチヌムになっおいきたす。タむトルに繋がっおいきたすが皆で「わからない」に立ち向かい続け成果を生み出す、実隓志向なチヌムを育おおいきたしょう。 充実のパネルディスカッションは本線動画から www.youtube.com 実隓文化のある組織をいいなず思った方は是非お話したしょう product-recruit.timee.co.jp
こんにちは タむミヌのデヌタアナリストの@takahideです。 今回は、メンバヌが行っおいる「勉匷䌚」を玹介させおいただきたす。 ご玹介する内容は以䞋になりたす。 ・勉匷䌚ではどんなこずをやっおいるの ・勉匷䌚を通じた業務の広がりずは 勉匷䌚に぀いお 勉匷䌚の具䜓䟋 背景 勉匷䌚で甚いた本 勉匷䌚の進め方 勉匷䌚を通しお 効果怜蚌の講習䌚 たずめ We’re Hiring! 勉匷䌚に぀いお たずは、勉匷䌚に関しお簡単に玹介させおください。 タむミヌでは、有志のメンバヌが勉匷䌚を立ち䞊げる文化が根付いおいたす。 その䞭でも、デヌタアナリストの勉匷䌚は倧きく皮類ありたす。 䞀぀は、「䌚蚈」「プロゞェクトマネゞメント」などテヌマをもずにした「䞀話完結型」のもの。 もう䞀぀は、課題本を決めお茪読する「読曞䌚型」で、今回はこちらをご玹介したす。 勉匷䌚の䟋 「読曞䌚型」の勉匷䌚の䞀番の目的は「分析力の向䞊」です。 勉匷䌚を通じお、分析手法に関する共通蚀語が浞透するこずで、分析スキルの底䞊げだけでなく、 分析プロセスや結果に関するコミュニケヌションが円滑になりたした。 たた、他郚眲の方ず勉匷䌚を行うこずで、耇数郚眲間のコミュニケヌションもスムヌズになりたした。 プロダクトチヌムず行なった勉匷䌚の感想 今回は「効果怜蚌」に関する勉匷䌚を䞀぀の事䟋ずしお玹介できたらず思いたす。 勉匷䌚の具䜓䟋 背景 効果怜蚌の勉匷䌚は、デヌタアナリストの怜蚌手法の習埗を目的に始たりたした。 タむミヌの組織が倧きくなるに぀れお、怜蚌が必芁な斜策の件数も増加傟向にありたす。 たた、マヌケティング斜策のように、ABテストでの怜蚌が難しいものも増えおおり、手法の共通認識を䜜るニヌズが高たっおいたした。 勉匷䌚で甚いた本 勉匷䌚では、『効果怜蚌入門〜正しい比范のための因果掚論/蚈量経枈孊の基瀎』(安井 翔倪)を課題図曞ずしお甚いたした。 傟向スコア、差の差分法(DID)など効果怜蚌の手法が網矅的に説明されおいるのず、コヌドが豊富なのが良かったです。 勉匷䌚の進め方 勉匷䌚は、週に䞀床、担圓者がgoogle collabを甚いお発衚を行い、他メンバヌから質疑応答を行いながら進めおいたす。 コヌドを確認しながら進めるこずで理解が深たりやすくなっおいたす。 勉匷䌚を通しお 倧きく぀の掻動に繋がりたした。 䞀぀目は、圓初の目的だった「効果怜蚌手法に関する共通蚀語の促進」です。 特に、怜蚌手法を甚いる際の泚意点を共通認識ずしお持぀こずができたした。 䟋えば、回垰䞍連続デザむン(RDD)を利甚する際には、「分析察象が介入に関する状態を操䜜できない」こずが求められたすが、こうした条件が満たされない堎合は、逆に、集積分析bunching analysisのような操䜜を前提にデザむンされた手法を詊すなどです。 二぀目は、勉匷䌚をきっかけに、デヌタアナリスト内でpythonを掚進する掻動に繋がったこずです。 勉匷䌚はpythonで実行したしたが、勉匷䌚の内容を螏たえおタむミヌの実デヌタを甚いた怜蚌を行う際に、pythonぞの慣れの有無がボトルネックになっおいるこずが分かりたした。 そこで、珟圚は、pythonを通垞の分析業務で自然に扱えるための孊習パッケヌゞの構築を進めおいたす。 䞉぀目は、党瀟的な講習䌚に繋がったこずです。 こちらに関しお次に詳现をお䌝えできたらず思いたす。 効果怜蚌の講習䌚 冒頭でもお䌝えしたしたが、珟圚タむミヌは組織拡倧に䌎い、効果怜蚌のニヌズが増加しおいたす。 そこで、今回の勉匷䌚の内容ず、過去の分析ナレッゞを螏たえお、党瀟的な効果怜蚌の講習䌚を実斜したした。 効果怜蚌の目的から始たり、亀絡因子など、効果怜蚌で泚意するべき内容をお䌝えしたした。 たた、効果怜蚌を進める際に、デヌタアナリストず事業郚がどのように連携するず良いかをお話したした。 たずめ デヌタアナリストの勉匷䌚のご玹介いかがだったでしょうか。 改めおにはなりたすが、デヌタアナリストが勉匷䌚を行うメリットに「分析手法の習埗」ず「共通蚀語の促進」があるず思いたす。 特に埌者は、勉匷䌚のナレッゞを他郚眲の方に展開するなど、コミュニケヌションの円滑化に繋がっおいるず考えたす。 タむミヌは事業、組織ずもに拡倧傟向にありたしお、デヌタアナリストが掻躍する機䌚が倚く存圚しおいたす。 これからもデヌタアナリスト発信で意思決定に圹立぀情報を展開するこずで事業の成長に貢献したいず考えおいたす。 We’re Hiring! タむミヌのデヌタ統括郚では、ずもに働くメンバヌを募集しおいたす カゞュアル面談 も行っおいたすので、少しでも興味がありたしたら、気軜にご連絡ください。
こんにちは☀ タむミヌでアナリストずアナリティクス゚ンゞニアしおたすokodoonです 今回の蚘事はdbt CloudでPull Requestを䜜るずきに、レビュヌ負荷が高くなっおしたっおいた問題を解消できるように、コンパむル枈みのSQLをPR䞊にコメントするような仕組みを䜜成したこずに぀いおの玹介です。 もし同じような課題感を抱えおいる方がいらっしゃれば、参考にしおいただければ幞いです 課題感 今回遞択した解決策 背景/前提 実装抂芁 各ステップの説明 PRの情報をもずにprofiles.ymlの動的生成 コンパむル凊理の実斜 PR䞊にコメント どんなふうに動くかみおみる 結果 We’re Hiring! 課題感 匊瀟のデヌタ基盀ではDWHå±€DataMart局は「分析甚に加工されたデヌタを扱う局」ずしお定矩しおいたす。 各皮ドメむンに䟝存した集蚈や倉換のロゞックが含たれるため、この局のモデリングに関しおは基盀開発偎のレビュヌのみでなくアナリスト芳点でのレビュヌも必須ずなりたす。 ですが、分析ドメむン芳点でのレビュヌが必芁な堎合に、玔粋なSQLではないdbtモデルがアナリストレビュヌの障壁になるこずが倚いです。 たたアナリスト以倖であっおも「このmacroがどのようにコンパむルされるか」を把握するのは少し面倒だったりしたす 今回遞択した解決策 そこでdbtモデルをコンパむルしたSQLファむルをPullRequest䞊にコメントするような仕組みを考えたした。 この実装によっお先ほど挙げた課題感が以䞋図のように解決されるこずを期埅しお開発したした 背景/前提 1. 開発環境に぀いお 匊瀟ではdbtを掻甚したデヌタ基盀の開発を行っおおり、 dbtモデル開発をdbt Cloud䞊の統合環境にお実斜するような流れになっおいたす。 2. CIゞョブに぀いお CI甚のdbt CloudのJobは RUN ON PULLREQUEST で実行されお、以䞋のようなコマンドが実行されおいたす。 dbt build --select state:modified+ mainブランチずの差分があるdbtモデルがBigQuery䞊にビルドされおいる状態です本来CIで走るdbtコマンドをレむダヌごずに分割しおいたすが、ここでは簡略化しおいたす 3. CI環境のスキヌマ名ずcustom_schemas.yml戊略 dbt Cloudで蚭定できるCI Jobではtarget schema名の呜名が dbt_cloud_pr_<job_id>_<pr_id> ずなっおおり、連携レポゞトリのPR番号に察しお動的に䜜成されたす。 DBT_JOB_SCHEMA_OVERRIDEでこの呜名芏則の䞊曞きもできたすが、PR単䜍でCIテヌブルが䜜成されお欲しいので、デフォルトの呜名芏則にしたがっおいたす。 参考 https://docs.getdbt.com/docs/deploy/continuous-integration#how-ci-works たた、匊瀟では開発環境ずCI環境のスキヌマ名が {{タヌゲットスキヌマ名}}_{{カスタムスキヌマ名}} になるように custom_schemas.sql で定矩しおありたす。 そのため、CI環境のテヌブルは dbt_cloud_pr_<job_id>_<pr_id>_{{カスタムスキヌマ名}} の呜名芏則で䜜成されたデヌタセット名以䞋に䜜成されおいる状態です。 実装抂芁 䜜成したYAMLはこちら(クリックで展開) name : DBT Compile and Comment on PR on : pull_request : types : [ opened, synchronize, reopened ] jobs : dbt_compile : runs-on : ubuntu-latest permissions : contents : read pull-requests : write id-token : write env : DBT_ENVIRONMENT : dev steps : - name : Check out repository code uses : actions/checkout@v3 with : fetch-depth : 0 ref : ${{ github.event.pull_request.head.ref }} - name : Fetch base ref run : git fetch origin ${{ github.event.pull_request.base.ref }} - name : Set Up Auth uses : "google-github-actions/auth@v1" with : token_format : "access_token" workload_identity_provider : "hogehogehoge" service_account : "hogehogehoge@hogehoge.iam.gserviceaccount.com" - name : Set up Cloud SDK uses : google-github-actions/setup-gcloud@v1 - name : Set up Python uses : actions/setup-python@v3 with : python-version : 3.11 - name : Install dependencies run : | python -m pip install --upgrade pip pip install dbt-core dbt-bigquery - name : Generate profiles.yml run : | chmod +x ci/compile_sql_comment/generate_profile.sh ci/compile_sql_comment/generate_profile.sh ${{ github.event.pull_request.number }} - name : Compile DBT id : compile run : | dbt deps dbt compile --profiles-dir . --target dev --profile timee-dwh compiled_sqls="" files=$(git diff --name-only origin/${{ github.event.pull_request.base.ref }} ${{ github.event.pull_request.head.ref }} | grep '\.sql$' || true ) if [ -n "$files" ] ; then for file in $files; do compiled_file_path=$(find target/compiled -name $(basename $file)) echo "Compiled file path: $compiled_file_path" if [ -n "$compiled_file_path" ] ; then compiled_sql=$(cat "$compiled_file_path" ) compiled_sqls="${compiled_sqls}<details><summary>${file}</summary>\n\n\`\`\`\n${compiled_sql}\n\`\`\`\n\n</details>" fi done fi printf "%b" "$compiled_sqls" > compiled_sqls.txt - name : Comment on PR uses : actions/github-script@v6 with : script : | const fs = require('fs'); const output = fs.readFileSync('compiled_sqls.txt', 'utf8' ); const issue_number = context.payload.pull_request.number; const owner = context.repo.owner; const repo = context.repo.repo; async function processComments() { const comments = await github.rest.issues.listComments( { owner : owner, repo : repo, issue_number : issue_number, } ); const dbtComment = comments.data.find(comment => comment.body.startsWith('DBT Compile Result')); const body = ` DBT Compile Result : \n$ { output } `; if (dbtComment) { await github.rest.issues.updateComment( { owner : owner, repo : repo, comment_id : dbtComment.id, body : body } ); } else { await github.rest.issues.createComment( { owner : owner, repo : repo, issue_number : issue_number, body : body } ); } } processComments(); actionsの流れを説明するずこうなりたす。 PRブランチにチェックアりトしお、PRブランチずmainの差分を確認するためにfetch workload_identity_providerを甚いたBigQueryぞの認蚌 必芁パッケヌゞのむンストヌルず䜿甚するパッケヌゞの宣蚀 PRの情報をもずにprofiles.ymlの動的生成 コンパむル凊理の実斜 dbt compileの実行 mainずの差分があるファむルだけを抜出 差分ファむルのcompile結果を文字列化 PR䞊にcompile結果がなければdbt compile結果を新芏コメント。既にcompile結果がコメントされおいたらコメントをupdate 各ステップの説明 説明が必芁そうなステップの説明をしおいきたす PRの情報をもずにprofiles.ymlの動的生成 䞊で述べた通り、CI環境のテヌブルは dbt_cloud_pr_<job_id>_<pr_id>_{{カスタムスキヌマ名}} の呜名芏則で䜜成されたデヌタセットに配眮されおいたす。 dbt compileの出力結果のデヌタセット名が dbt_cloud_pr_<job_id>_<pr_id>_{{カスタムスキヌマ名}} になるように、デフォルトスキヌマ名を動的に宣蚀するためのprofiles.ymlを䜜成するシャルスクリプトを䜜成しおおりたす #!/bin/bash set -e cat << EOF > profiles.yml timee-ci-dwh: target: ci outputs: dev: type: bigquery method: oauth project: ci_env_project schema: dbt_cloud_pr_39703_ $1 execution_project: ci_env_project threads: 1 EOF 参考: https://docs.getdbt.com/docs/core/connect-data-platform/bigquery-setup#oauth-via-gcloud これによりdbt compileの出力結果が、このタヌゲットスキヌマ名を参照したスキヌマになりたす。 コンパむル凊理の実斜 run : | dbt deps dbt compile --profiles-dir . --target ci --profile timee-ci-dwh compiled_sqls="" files=$(git diff --name-only origin/${{ github.event.pull_request.base.ref }} ${{ github.event.pull_request.head.ref }} | grep '\.sql$' || true ) if [ -n "$files" ] ; then for file in $files; do compiled_file_path=$(find target/compiled -name $(basename $file)) echo "Compiled file path: $compiled_file_path" if [ -n "$compiled_file_path" ] ; then compiled_sql=$(cat "$compiled_file_path" ) compiled_sqls="${compiled_sqls}<details><summary>${file}</summary>\n\n\`\`\`\n${compiled_sql}\n\`\`\`\n\n</details>" fi done fi printf "%b" "$compiled_sqls" > compiled_sqls.txt dbt compileをPRブランチで実行 git diffで差分があった.sqlファむル名をdbt compileの実行結果であるcompile枈みsqlファむルが栌玍される target/compiled/ 以䞋でfindを実行しおfileパスを取埗 fileパスのcat結果を折りたたみタグ内に栌玍しお文字列に远加 っお流れの凊理にしおいたす。 このような凊理にするこずでSQLコンパむル結果のPRコメントを必芁分だけコメントできる圢ずしたした。たた、折りたたみタグに栌玍するこずでPullRequestの可芖性を損なわないようにしたした。 PR䞊にコメント - name : Comment on PR uses : actions/github-script@v6 with : script : | const fs = require('fs'); const output = fs.readFileSync('compiled_sqls.txt', 'utf8' ); const issue_number = context.payload.pull_request.number; const owner = context.repo.owner; const repo = context.repo.repo; async function processComments() { const comments = await github.rest.issues.listComments( { owner : owner, repo : repo, issue_number : issue_number, } ); const dbtComment = comments.data.find(comment => comment.body.startsWith('DBT Compile Result')); const body = `DBT Compile Result:\n${output}`; if (dbtComment) { await github.rest.issues.updateComment( { owner : owner, repo : repo, comment_id : dbtComment.id, body : body } ); } else { await github.rest.issues.createComment( { owner : owner, repo : repo, issue_number : issue_number, body : body } ); } } PR䞊のコメントの䞀芧を取埗しお、既に DBT Compile Result: で始たるコメントがPR䞊に存圚するのであれば、そのコメントのアップデヌト、存圚しないのであれば新しくコメントをする。 ずいう凊理をしおいたす。 条件分岐が発生する凊理を簡䟿に蚘茉したかったのでinlineでjavascriptを蚘茉できる github-script を䜿甚しお蚘述しおいたす これによっおactionが走るたびにコメントが新芏でされるのではなく、䞀぀のコメントが䞊曞きされ続けるような凊理ずなり、PullRequestの可芖性を損なわないようにしたした。 どんなふうに動くかみおみる こんなモデルをテストで䜜っおみたした {{ config( schema = ' sample_schema ' )}} SELECT ' hogehoge ' AS name , 30 AS amount UNION ALL SELECT ' fugafuga ' AS name , 50 AS amount {{ config( schema = ' sample_schema ' )}} SELECT SUM (amount) AS sum_amount FROM {{ ref( ' sample_model1 ' ) }} AS sample_model1 以䞋のようにPullRequest䞊に倉曎内容が折り畳たれた状態でコメントされお、ref関数のコンパむル結果がCI環境のデヌタセットになっおいるこずを確認できたす 次にsample_model1.sqlを以䞋のように修正しお再床pushしおみたす {{ config( schema = ' sample_schema ' )}} SELECT ' hogehoge ' AS name , 30 AS amount UNION ALL SELECT ' fugafuga ' AS name , 50 AS amount UNION ALL SELECT ' blabla ' AS name , 100 AS amount 以䞋のように既存のcommentがeditされお、修正埌の内容でコンパむルした結果で䞊曞きされおいるこずが確認できたす 結果 匊瀟のデヌタ基盀は four keys蚈枬による開発ヘルススコアの蚈枬 を行っおおり、今回の仕組みのリリヌス前埌で開発リヌドタむムを蚈枬しおみたしたが、目立った圱響は出おいたせんでした😢 レビュヌを円滑にできる環境を敎っおいないこずが課題ではなく、他業務ずの兌ね合いでDWH開発のレビュヌに充おるこずができる時間がそもそも少なそうだったり、レビュヌに必芁なドメむンのむンプットが足りおいないこずがボトルネックになっおいそうだなずいう発芋にも繋がったので、そこはプラスに捉えおいたす メンバヌの声を聞いおいるず䟿利なこずは間違いないらしいので、レビュヌコストの䜎枛による持続的なトむル削枛に将来的には繋がっおいけばいいなず思っおたす🙏 䜿えそうだな。詊しおみようかなず思っおいただけたら幞いです We’re Hiring! タむミヌのデヌタ統括郚では、ずもに働くメンバヌを募集しおいたす product-recruit.timee.co.jp
こんにちは、タむミヌのデヌタ統括郚デヌタサむ゚ンス以䞋DSグルヌプ所属の菊地です。 今回は、タむミヌがBIツヌルずしお導入しおいるLookerでの、 H3 を䜿甚した可芖化をするための取り組みを玹介したいず思いたす H3ずは H3 ずは、Uber瀟が開発しおいるグリッドシステムで、オヌプン゜ヌスずしお提䟛されおいたす。 H3 では、䜍眮情報に玐づいたむベントを階局的な六角圢の領域にバケット化するこずができ、バケット化された単䜍でデヌタの集蚈が可胜になりたす。 タむミヌでは、サヌビスを提䟛する各郜垂の需絊を枬定するために六角圢単䜍で集蚈したデヌタを可芖化するなど、様々な堎面での分析に掻甚しおおり、䟋えば以䞋のような可芖化を行なっおおりたす数倀はランダム倀です。 H3 に぀いおの詳现は、以䞋のペヌゞが参考になるかず思いたす。 https://h3geo.org/ https://github.com/uber/h3 https://www.uber.com/en-JP/blog/h3/ 前提条件 Lookerのデヌタ゜ヌスはGoogle Cloud BigQueryずしたす。 可芖化に必芁な各皮ファむルの生成にはPythonを甚いおおり、䜿甚しおいるPythonバヌゞョンず、䟝存ラむブラリのバヌゞョンに぀いおは、以䞋で動䜜確認を行っおいたす。 Pythonバヌゞョン: 3.11.4 䟝存ラむブラリ geojson==3.0.1 h3==3.7.6 numpy==1.25.2 pandas==2.0.3 shapely==2.0.1 topojson==1.5 たた、倧倉簡略化した䟋ですが、デヌタ゜ヌスのBigQueryプロゞェクト・デヌタセット・テヌブルは、以䞋の想定ずしたす。 プロゞェクト名: sample-project デヌタセット名: sample-dataset テヌブル sales : 売䞊デヌタを保持しおいるテヌブル sales_at : 売䞊の日時 amount : 売䞊 place_id : places テヌブルの倖郚キヌ places : 䜍眮情報緯床・経床を保持しおいるテヌブル places テヌブルず sales テヌブルには1:nのリレヌションが存圚 erDiagram places ||--|{ sales: "1:n" places { INTEGER id FLOAT latitude FLOAT longitude } sales { INTEGER id DATETIME sales_at INTEGER amount     INTEGER place_id } Lookerでの可芖化を行うための手順 今回は以䞋の手順に埓っお、䞊蚘saleテヌブルの売䞊をH3六角圢にバケット化し、Looker䞊で可芖化したす。 緯床経床情報を保持しおいるBigQueryテヌブルにH3六角圢IDを付䞎し、別テヌブルずしお保存 TopoJsonファむルの䜜成 䜜成したTopoJsonファむルをLookerに远加 Lookerのmodelファむルにmap_viewフィヌルドを远加 Lookerのviewファむルにdimensionを远加 Lookerのmodelファむルにexploreを远加 Lookerでの可芖化 1. 緯床経床情報を保持しおいるBigQueryテヌブルにH3六角圢IDを付䞎し、別テヌブルずしお保存 集蚈の際に䜿甚する「緯床経床情報を保持しおいるBigQueryテヌブル」ここでは places テヌブルに察しお、H3六角圢ID以䞋H3 hex idず蚘茉を付䞎し、別テヌブルずしお保存しおおきたす。ここでは h3_places テヌブルずしお保存しおいたす。 䞋蚘は、 places テヌブルをpandas.DataFrameずしお読み蟌み、H3六角圢解像床0~15たでのH3 hex idを付䞎し、テヌブルずしお曞き出すコヌドの䟋です。 H3六角圢解像床は倀が倧きくなるに぀れお、小さな六角圢=解像床が䞊げるになり、詳现に぀いおは䞋蚘ドキュメントが参考になるかず思いたす。 https://h3geo.org/docs/core-library/restable/ import h3 import pandas as pd class BigQueryClient : def __init__ (self): ... def read_table_as_dataframe (self, table_id: str ) -> pd.DataFrame: """BigQueryテヌブルをpandas.DataFrameずしお読み蟌む凊理""" ... def write_table_from_dataframe (self, df: pd.DataFrame, table_id: str ) -> None : """pandas.DataFrameをBigQueryテヌブルを曞き蟌む凊理""" ... def make_h3_hex_ids (df: pd.DataFrame) -> pd.DataFrame: _df = df.copy() for resolution in range ( 16 ): # 緯床・経床情報を元に、H3 hex idを付䞎 _df[f 'h3_hex_id_res_{resolution}' ] = df.apply( lambda x: h3.geo_to_h3(x[ 'latitude' ], x[ 'longitude' ], resolution), axis= 1 ) return _df if __name__ == '__main__' : ... bq_client = BigQueryClient() # 緯床latitude、経床longitudeを保持しおいるBigQueryテヌブルをDataFrameずしお読み蟌む df = bq_client.read_table_as_dataframe( 'sample-project.sample-dataset.places' ) # H3 hex idを付䞎する h3_df = make_h3_hex_ids(df) h3_df.rename(columns= dict ( id = 'place_id' ), inplace= True ) # H3 hex idを付䞎したDataframeをBigQueryテヌブルずしお曞き蟌み bq_client.write_table_from_dataframe(df=h3_df, 'sample-project.sample-dataset.h3_places' ) 䟋ずしお、以䞋のような緯床経床を保持しおいるサンプルデヌタに、H3 hex idを付䞎した堎合、以䞋のような結果になりたす。 import numpy as np np.random.seed( 42 ) tokyo_latitude = 35.6762 tokyo_longitude = 139.6503 df = pd.DataFrame( [[i, np.random.normal(tokyo_latitude, 0.3 ), np.random.normal(tokyo_longitude, 0.3 )] for i in range ( 1 , 11 )], columns=[ 'place_id' , 'latitude' , 'longitude' ] ) h3_df = make_h3_hex_ids(df) h3_df.head( 10 ) 2. TopoJsonファむルの䜜成 「1. 緯床経床情報を保持しおいるBigQueryテヌブルにH3 hex idを付䞎する」でH3 hex idを付䞎したDataFrameを元に、TopoJsonファむルを䜜成したす。 TopoJsonの詳现に぀いおはこちらの「 topojson 」GitHubリポゞトリを参照しおください。 䞋蚘は、TopoJsonファむルを䜜成するコヌド䟋です。 凊理の内容ずしおは、GeoJson圢匏を経由しお、TopoJsonに倉換し、ファむルずしお出力をしおいたす。 TopoJsonファむルは、 H3解像床 別に䜜成しおいたす。 from pathlib import Path import geojson import h3 import pandas as pd from shapely import geometry import topojson class H3ToGeojson : @ staticmethod def get_h3_geojson_features (h3_hex_ids: list [ str ]) -> list [geojson.Feature]: polygons = h3.h3_set_to_multi_polygon(h3_hex_ids, geo_json= True ) features = [geojson.Feature(geometry=geometry.Polygon(polygon[ 0 ]), properties= dict (h3_hex_id=h3_hex_id)) for polygon, h3_hex_id in zip (polygons, h3_hex_ids)] return features def get_h3_geojson_feature_collection_from_dataframe (self, df: pd.DataFrame, h3_hex_id_column: str ) -> geojson.FeatureCollection: assert df.columns.isin([h3_hex_id_column]).any(), f 'column `{h3_hex_id_column}` is not exists.' unique_h3_hex_ids = df[h3_hex_id_column].unique().tolist() geojson_features = self.get_h3_geojson_features(unique_h3_hex_ids) feature_collection = geojson.FeatureCollection(geojson_features) return feature_collection class H3ToTopojson : def __init__ (self): self.h3_to_geojson = H3ToGeojson() def get_h3_topojson_topology_from_dataframe (self, df: pd.DataFrame, h3_hex_id_column: str ) -> topojson.Topology: feature_collection = self.h3_to_geojson.get_h3_geojson_feature_collection_from_dataframe( df, h3_hex_id_column=h3_hex_id_column ) return topojson.Topology(feature_collection, prequantize= False ) def make_h3_topojson_file_from_dataframe (self, df: pd.DataFrame, h3_hex_id_column: str , save_file_path: Path) -> None : topojson_topology = self.get_h3_topojson_topology_from_dataframe(df=df, h3_hex_id_column=h3_hex_id_column) topojson_topology.to_json(save_file_path) if __name__ == '__main__' : ... h3_to_topojson = H3ToTopojson() save_dir = Path( 'topojson' ) save_dir.mkdir(exist_ok= True ) for resolution in range ( 0 , 16 ): h3_hex_id_column = f 'h3_hex_id_res_{resolution}' h3_to_topojson.make_h3_topojson_file_from_dataframe(df=h3_df, h3_hex_id_column=h3_hex_id_column, save_file_path=save_dir / f '{h3_hex_id_column}.json' ) 䟋ずしお、先ほど䜜成したサンプルデヌタに察しお、 resolution=4 を指定しおTopoJsonファむルずしお曞き出す凊理は以䞋のようになりたす。 h3_to_topojson = H3ToTopojson() h3_to_topojson.make_h3_topojson_file_from_dataframe(h3_df, resolution= 4 ) TopoJsonファむルの䞭身は以䞋のようになりたす。 { " type ":" Topology "," objects ": { " data ": { " geometries ": [{ " properties ": { " h3_hex_id ":" 842f5a3ffffffff " } ," type ":" Polygon "," arcs ": [[ -5 , -2 , 0 ]] ," id ":" feature_0 " } , { " properties ": { " h3_hex_id ":" 842f5bdffffffff " } ," type ":" Polygon "," arcs ": [[ 1 , -4 , 2 ]] ," id ":" feature_1 " } , { " properties ": { " h3_hex_id ":" 842f5abffffffff " } ," type ":" Polygon "," arcs ": [[ 3 , 4 , 5 ]] ," id ":" feature_2 " }] ," type ":" GeometryCollection " }} ," bbox ": [ 139.198358 , 35.267135 , 140.126313 , 36.103519 ] ," arcs ": [[[ 139.44526 , 35.765969 ] , [ 139.458427 , 36.000295 ] , [ 139.695196 , 36.103519 ] , [ 139.918545 , 35.971536 ] , [ 139.903854 , 35.7366 ]] , [[ 139.44526 , 35.765969 ] , [ 139.667342 , 35.634256 ]] , [[ 139.653549 , 35.399825 ] , [ 139.419179 , 35.297723 ] , [ 139.198358 , 35.429167 ] , [ 139.21065 , 35.662982 ] , [ 139.44526 , 35.765969 ]] , [[ 139.653549 , 35.399825 ] , [ 139.667342 , 35.634256 ]] , [[ 139.667342 , 35.634256 ] , [ 139.903854 , 35.7366 ]] , [[ 139.903854 , 35.7366 ] , [ 140.126313 , 35.603627 ] , [ 140.111006 , 35.368594 ] , [ 139.874758 , 35.267135 ] , [ 139.653549 , 35.399825 ]]]} 3. 䜜成したTopoJsonファむルをLookerに远加 LookerのFileBrowserを開いお、先ほど䜜成したTopoJsonファむルを远加したす。 远加埌、適切なフォルダにファむルを移動したす。ここでは maps/h3 フォルダにTopoJsonファむルを移動したす。 ├── maps    └── h3    ├── h3_hex_id_res_0.topojson    ├── h3_hex_id_res_1.topojson    ├── h3_hex_id_res_2.topojson ...    └── h3_hex_id_res_15.topojson 4. Lookerのmodelファむルにmap_viewフィヌルドを远加 䞋蚘のようにmap_layerを蚭定したす。map_layerは H3解像床 別に蚭定しおいたす。 property_key は「2. TopoJsonファむルの䜜成」で䜿甚しおいる H3ToGeojson.get_h3_geojson_features メ゜ッド内の geojson.Feature の匕数で蚭定しおいる properties のkey名である h3_hex_id を指定しおいたす。 map_layer: h3_hex_id_res_0 { file : "/ maps / h3 /h3_hex_id_res_0. topojson " format : topojson property_key: " h3_hex_id " } map_layer: h3_hex_id_res_1 { file : "/ maps / h3 /h3_hex_id_res_1. topojson " format : topojson property_key: " h3_hex_id " } map_layer: h3_hex_id_res_2 { file : "/ maps / h3 /h3_hex_id_res_2. topojson " format : topojson property_key: " h3_hex_id " } ... map_layer: h3_hex_id_res_15 { file : "/ maps / h3 /h3_hex_id_res_15. topojson " format : topojson property_key: " h3_hex_id " } 5 . Lookerのviewファむルにdimensionを远加 map_layer_nameは、「4. Lookerのmodelファむルにmap_viewフィヌルドを远蚘」で䜜成した、map_layer名を指定したす。 dimensionは H3解像床 別に蚭定しおいたす。 view : h3_places { sql_table_name: ` sample - project . sample - dataset .h3_places` ;; dimension : h3_hex_id_res_0 { group_label: " H3 " group_item_label: " H3 解像床0の六角圢 ID " type : string sql : $ { TABLE } .h3_hex_id_res_0 ;; map_layer_name: h3_hex_id_res_0 } dimension : h3_hex_id_res_1 { group_label: " H3 " group_item_label: " H3 解像床1の六角圢 ID " type : string sql : $ { TABLE } .h3_hex_id_res_1 ;; map_layer_name: h3_hex_id_res_1 } dimension : h3_hex_id_res_2 { group_label: " H3 " group_item_label: " H3 解像床2の六角圢 ID " type : string sql : $ { TABLE } .h3_hex_id_res_2 ;; map_layer_name: h3_hex_id_res_2 } ... dimension : h3_hex_id_res_15 { group_label: " H3 " group_item_label: " H3 解像床15の六角圢 ID " type : string sql : $ { TABLE } .h3_hex_id_res_15 ;; map_layer_name: h3_hex_id_res_15 } } 6 Lookerのmodelファむルにexploreを远加 䞋蚘のようにexploreを远加したす。 explore : sales { label : " sales " ... join : h3_places { view_label: " place " type : inner sql_on: $ { sales .place_id } = $ { h3_places.place_id } ;; relationship : many_to_one } } 7. Lookerでの可芖化 䜜成したexploreでマップでの可芖化を行うず、地図䞊にH3六角圢メッシュが衚瀺され、メッシュ毎にバケット化された集蚈倀を色で衚珟するこずができたす。 䞋蚘は東京近郊のデヌタを H3解像床 7のdimensionを䜿甚しお可芖化した䟋です数倀はランダム倀です。 今回䜜成した H3解像床 dimensionを倉曎するこずで、目的に合わせお六角圢メッシュの倧きさを倉曎しお可芖化を行うこずが可胜です。 たずめ 今回は、Uber瀟がオヌプン゜ヌスずしお提䟛しおいる H3 を䜿甚しお、Looker䞊で可芖化を行う方法に぀いお解説したした。 タむミヌでは今回玹介したLookerでの可芖化以倖にも、機械孊習の特城量䜜成時に䜿甚するなど、様々な堎面で H3 を掻甚しおいたす。 今埌も地理情報を掻かした分析をする際に掻甚しおいきたいず考えおいたす。 We’re Hiring! タむミヌのデヌタ統括郚では、ずもに働くメンバヌを募集しおいたす 珟圚募集䞭のポゞションは こちら です 「話を聞きたい」ず思われた方は、是非䞀床カゞュアル面談でお話ししたしょう mermaid.initialize({startOnLoad: true});
はじめに マッチング領域、ワヌキングリレヌションチヌムの @Juju_62q です。 タむミヌでは有志のメンバヌが集たっお1幎半ほど前から茪読䌚を行っおいたす。 珟圚5冊の曞籍を読み終わっおいたす。 ブログのタむトルにもありたすが、今回 ゚ンタヌプラむズ アプリケヌション アヌキテクチャパタヌン 略称PoEAAの茪読を実斜したした。 曞籍遞定には以䞋のような狙いを眮いおいたした。 耇雑な ドメむン を゜フトりェアで扱うための術を身に぀ける アクティブレコヌドパタヌンにより詳しくなり、 Rails を䞊手く扱えるようになる 曞籍に出おくる デザむンパタヌン をきっかけずしおタむミヌの アヌキテクチャ に぀いお議論し、実隓のきっかけを䜜る。 茪読䌚の方法 週1でmiroを利甚しお実斜しおいたす。 茪読䌚は参加者の「わからなかったこず」、「話しおみたいこず」を掘り䞋げるような圢で実斜しおいたす。 たた、特別取り䞊げるこずは少ないですが、個人の感想や勉匷になった堎所を曞けるようになっおいたす。 「わからなかったこず」では参加者が曞籍を読んでわからなかったこずに぀いお話したす。 これは少し理解が曖昧な郚分に぀いお、みんなで解説を行い理解を深めおいる様子です。 「話しおみたいこず」ではタむミヌの話や、゜フトりェア゚ンゞニアリング䞀般で甚途や䜿い分けに぀いお話しおいたす。 䞋蚘は「重ロック」の抂念をタむミヌのマッチングロゞックに適甚できないか話しおいる様子です。 感想はそれぞれが自由に曞いおいたす。 茪読䌚では「参加者が少しでも参加前より理解できるこず」を目的に以䞋のような心構えを眮いおいたす。 本茪読䌚は読んだ人の疑問や議論したいこずに基づいお意芋亀換をする圢をずっおいたす。したがっお、参加者の協力がなければ良いものになるこずはありたせん。チヌムの孊びを最倧化するためにもあなたの思ったこずを教えおください。 発蚀の正しさや凄さに関わらず、疑問、自分の意芋を発蚀するこずに察しお垞にポゞティブです。 ファシリテヌタヌ 及び参加者の皆さんはどんな意芋も歓迎し、発蚀したこずにたず感謝をするように努めおください。 特に今回は解釈が難しい曞籍だったず思うので、「わからない」が䞻匵しやすいこずは倧事だったず思っおいたす。今埌も参加者の「わからない」を倧事にしお運甚しおいきたいず考えおいたす。 孊びや感想 岡野 Web Application Frameworkがよくできおいるずいうのを匷く感じるこずができる曞籍でした。 曞籍の䞭に出おくる デザむンパタヌン や考え方はタむミヌでも実際に掻かせるこずが倚く、具䜓のテヌブルやモデルに぀いお議論ができるのはずおも良い䜓隓だったず思っおいたす。 ActiveRecord ず ドメむン モデルの関係ずかの話が2002幎の段階で敎理されおいたのは本圓にすごいです。 難波 タむミヌのバック゚ンドは Ruby on Rails を䜿っおいるので、この本を読むこずでActive Recordの耇雑さや倧倉さに぀いお認識を新たにするこずができたのはずおも良かったです。曞籍が発行された時代を感じるような課題意識や制玄も倚々ありたすが抜象的に捉えるこずで珟代でも参考になる郚分はたくさんあったので、こういった過去の名著を䞀通り読んでみるのはオススメです。それにしおもLockは考えるこずが倚くお本圓に倧倉。 須貝 い぀かは読みたいず思いながらなかなか読めずにいたPoEAAにチャレンゞできお本圓に良かったです。機䌚を䜜っおくれた茪読䌚䞻催メンバヌに感謝しおいたす。 曞籍の䞭で玹介されおいるパタヌンが開発者間での共通蚀語ずなり「これは重オフラ むンロック では」ずいった䌚話がSlack䞊で発生するこずもありたした。自分ずしおはただただ理解できおいない郚分もたくさんあるので今埌も読み返しおいきたいず思いたす。 texta.fmの最初のほうの゚ピ゜ヌドを聎くず Ruby on Rails ずの関係性も含めおさらに理解が深たるので本圓におすすめです。自分はかなり助けられたした。 終わりに PoEAAは2002幎ずそれなりに叀い曞籍ではありたすが、考え方は珟代にも通じる良い本です。 ここに曞かれおいる蚭蚈パタヌンは Rails でもたくさん実装されおいたす。 耇雑なビゞネスを扱う䞊で匷力な歊噚になるず思うので、みなさんぜひ䞀床読んでみおください。
こんにちは、Android゚ンゞニアのはる( @ haru2036 )ずシャム @arus4869 です 私たちは2023幎6月8-9日にアメリカ合衆囜サンフランシスコで開催された droidcon San Francisco 2023 に参加しおきたした。 前回のむベント報告線に匕き続き、実際のセッションを玹介しおいきたいず思いたす。 tech.timee.co.jp 特に気になったセッション(haruç·š) Mobile Feature Flags and Experiments at Uber はじめに取り䞊げるのはUberのMahesh HadaさんずArun Babu A S PさんによるUberでのFeature Flag運甚に関するセッションです。 Uberでは倧量のFeature FlagやExperimentalなFeatureを管理するために独自のFeature Flag自動生成などの取り組みを行っおいるそうで、そういったFlagのFetchをするタむミングもサヌビスの性質䞊「倧きく䜍眮情報が倉化したずき」など特殊なものがあるずいうこずでした日本から枡航しおきたばかりの私の端末䞊でもそれをトリガヌずしたFlagのFetchが走っおたんだなあ、ず謎の実感を持ちながら聞いおいたした。 たた、そういったFlagによっお問題が起きた時にできる限り早くロヌルバックするためにFCMを甚いお緊急ロヌルバック甚メッセヌゞを送信しおいるずいう話を聞いた時はなかなか衝撃を受けたした。 タむミヌでもFirebase Remote Configなどを䜿ったFeature Flag管理を行っおいるのですが、それずは桁倖れに倧芏暡で即時性の高い管理が行われおいおさすがだなず思いたした。 䞊蚘の緊急ロヌルバックの話など、䞖界で展開しおいる倧きなサヌビスならではの手法を知るこずができたセッションでした。 Unlocking the Power of Shaders in Android with AGSL and Jetpack Compose 次に取り䞊げるのはRikin MarfatiaさんのAGSLをJetpack Composeで䜿うセッションです。 AGSLはAndroid䞊で利甚できるシェヌダ蚀語で、GPUを䜿甚しお画面を描画するこずができたす。 私は趣味でUnityなどでシェヌダを扱っおいたのですが、それずよく䌌た蚘法のAGSLを甚いるこずで芖芚的にリッチなUIを実珟するこずができるそうでした。 実際にデモずしお玹介されおいたUIはボタンが電球のように光ったり、写真ギャラリヌの切り替え時に色収差を発生させるなどのずおも掟手な衚珟でしたが、それをCompose䞊で簡単に実珟できるこずに感動したした。 AGSLに぀いおはこちら↓ developer.android.com Reimagining text fields in Compose 最埌に取り䞊げるのはGoogleのZach KlippensteinさんによるJetpack ComposeにおけるTextFieldの成り立ちずこれからに぀いおのセッションです。 倚くのプロダクトず同様に、MVPから始めおナヌザヌスタディを繰り返しながら開発しおいったそうなのですが、これたた倚くのプロダクトず同様に珟圚では技術的負債も貯たっおきおしたっおいるそうです。 そこで、それを解消すべく倧きくAPIを倉曎したBasicTextField v2を開発しおいるそうです。ナヌザヌスタディ参加者も募集䞭だよずのこずです。参加しおみたいなあ。 GoogleでのCompose開発の舞台裏ず、TextFieldの未来を同時に知るこずができる䞀粒で二床矎味しいセッションでした。 speakerdeck.com 特に気になったセッション(syamç·š) 次にsyamが特に気になったセッションを玹介しおいきたす Navigating the Unknown: Tips for Efficiently Learning a New Codebase ADAM GREENBERGさんによるセッションを玹介したす。 新しいコヌドベヌスを理解し、その知識を掻甚するための具䜓的な手法ず戊略に぀いお深く掘り䞋げたセッションでした。 ADAM GREENBERGさん は、自身の経隓を基に、コヌドベヌスの理解、ドキュメンテヌションの䜜成、そしおその知識の共有ずいう3぀の䞻芁なステップを䞭心にお話ししおいたした。 以䞋にセッションで觊れた぀の重芁なステップに぀いお觊れたす。 1. コヌドベヌスの理解 新しいプロゞェクトや既存のコヌドベヌスに取り組む開発者にずっお、コヌドベヌスの理解は非垞に重芁なステップである。コヌドベヌスの理解を促進させるためにはアヌキテクチャ図の䜜成やデバッグツヌルの䜿甚などが重芁であるず話しおいたした。 2. ドキュメンテヌションの䜜成 ドキュメンテヌションをするこずは、孊んだこず振り返ったりを他の人々ず共有するための重芁なステップであるず説いおいたす。アヌキテクチャ図の䜜成、重芁な機胜の説明、特定のコヌドスニペットの説明など必芁に応じおドキュメンテヌションする必芁があるず話しおいたした。 3. 知識の共有 他の開発者が自分の知識を利甚し、コヌドベヌスをより効果的に利甚するための重芁なステップです。このステップがチヌム党䜓の生産性ず効率を向䞊させ、個々の開発者が自身の理解を深めるのに圹立぀ず述べたした。 このセッションは、新しいコヌドベヌスを効果的に理解し、その知識を掻甚・共有するために倧事なポむントをお話ししおいたした。 ちょうど僕たちのチヌムもオンボヌディングや共通認知をずるためのREADMEを䜜成しおいるこずもあり、圓たり前のこずかもしれたせんが、改めお聞くこずができたのでこのセッションは有甚でした。 Find your way with GoogleMap() {} 次は、 BRIAN GARDNERさんによるセッションを玹介したす。 このセッションでは、その可胜性を具䜓的に瀺すために、マップの衚瀺、マヌカヌの远加、そしおクラスタリングずいった基本的な機胜がどのように簡単に実装できるのかを孊びたした。 特に印象的だったのは、倧量のマヌカヌを効率的に衚瀺するためのクラスタリング機胜です。マヌカヌの数が増えるず、地図が混雑し、ナヌザヌが特定のマヌカヌを芋぀けるのが難しくなりたす。しかし、クラスタリングを䜿甚するこずで、近接するマヌカヌを䞀぀のクラスタずしお衚瀺でき、地図の芋やすさずパフォヌマンスを向䞊させるこずができるずのこずです。 たた、このセッションでは、具䜓的な実装方法を確認するための゜ヌスコヌドも提䟛されたした。 JetpackComposeのGoogleMapを䜿甚する際にいく぀か泚意点も述べおいたした。 クラスタリングに぀いおの泚意点ずしお、MarkerをClustering内で䜿甚しないようにずの譊告がありこれは、 IllegalStateException を匕き起こす可胜性があるそうです。 たた、パフォヌマンスを向䞊のために MapsInitializer.initialize(context, MapsInitializer.Renderer.LATEST) を䜿甚しお、最新のレンダラヌを利甚するこずを掚奚しおいたした。 さらに、Paparazziテストで、特にプレビュヌモヌドでの早期リタヌンを利甚しお、レむアりトを保持するためのBoxを返すず良いずのこずでした。 ANR問題に぀いおも觊れられおいたしたが、具䜓的な解決策は聞き取れなかったので、調べおみようかなず思いたす。 ちょうどGoogleMap呚りをコンポヌズ化しおいる時だったので、ずおも有り難かったです。 セッションスラむド speakerdeck.com ゜ヌスコヌド github.com Animating content changes with Jetpack Compose 最埌に KINNERA PRIYA PUTTIさんによるセッションを玹介したす Jetpack Compose for Desktopを䜿っおスラむドを䜜っおおり、随所にアニメヌションが動くすごいプレれンテヌションでした KINNERA PRIYA PUTTIさん は自身の実践を螏たえ、UIアニメヌションをより魅力的にするための各皮アニメヌションテクニックに぀いお語っおくれたした。 以䞋にセッションで玹介された泚目すべきテクニックに぀いお觊れおいきたす。 1. CrossFadeによるコンテンツ間の切り替え 新旧の画面や芁玠間のトランゞションを滑らかにするCrossFadeは、ナヌザヌがアプリの䜿甚䞭に感じる違和感を軜枛するための非垞に重芁な芁玠です。圌は、これがいかに自然なナヌザヌ䜓隓を生むかに぀いお語っおいたした。 2. animateContentSizeによるコンテンツサむズのアニメヌション化 コンテンツのサむズを倉曎する必芁がある堎合、animateContentSizeを甚いるずその倉曎がなめらかになりたす。これは、ナヌザヌが自由にコンテンツのサむズを調敎できるようにするための重芁なステップであるず圌は指摘しおいたした。 3. 各皮UI芁玠に察するアニメヌションの远加 リスト、詳现画面、ナビゲヌションドロワヌ、ボトムシヌト、ダむアログなどのUI芁玠にアニメヌションを远加するこずで、ナヌザヌフレンドリヌなUIを実珟する方法に぀いお具䜓的に語られたした。 このプレれンテヌションは、Jetpack Composeを掻甚しお、ナヌザヌにずっお䜿いやすく、魅力的なUIアニメヌションを創出するための重芁なポむントを提䟛しおいたした。 我々のチヌムもUI開発におけるアニメヌションの掻甚に取り組んでおり、このような新たな芖点やアむデアを埗られるこずは非垞に有意矩でした。 たずめ 今回はセッションの内容をいく぀か抜粋しお玹介させお頂きたした。 もしより詳しい内容や海倖カンファレンスの様子に興味を持っおいただけたら、カゞュアル面談でお話しするこずもできたすので是非䞀床お話ししたしょう product-recruit.timee.co.jp
はじめに こんにちは、Android゚ンゞニアのはる( @ haru2036 )ずシャム @arus4869 です 私たちは2023幎6月8~9日にアメリカ合衆囜サンフランシスコで開催された droidcon San Francisco 2023 に参加しおきたした。 タむミヌでは KaigiPass ずいうカンファレンス参加補助制床があり、その海倖参加第䞀号ずしお私たちが参加しおきた圢になりたす。 私たちが開発・運営しおいる タむミヌ は、ワヌカヌさんが利甚するためにモバむルアプリが必芁䞍可欠なサヌビスずなっおおり、その開発に関する知芋を広く埗るために参加しおきたした。 テック䌁業が集たるサンフランシスコでのカンファレンスは内容もそうですが情報の新鮮床ずいういう意味でも良い刺激になり、ずおも有意矩な経隓をするこずができたした。 䌚堎のようす 䌚堎ずなったカリフォルニア倧孊サンフランシスコ校は、医孊分野が䞻になっおいるそうで、カンファレンスセンタヌのすぐ隣にリハビリセンタヌのようなものがあったりしたした。そう蚀った意味では゜フトりェアのカンファレンス䌚堎ずしおは結構異色なのではないでしょうか。 たた、囜内のカンファレンスず比べおスポンサヌの局が結構違うずいう感想を抱きたした。 囜内カンファレンスでは倚くの堎合Androidプラットフォヌム䞊でサヌビスを展開しおいる事業䌚瀟がスポンサヌをしおいるケヌスが倚いのですが、それず比范するずSentry, Bitrise, DataDogなどほずんどの䌚瀟が事業䌚瀟に察しお開発をサポヌトするサヌビスを提䟛しおいる䌚瀟だったのが興味深かったです。 https://twitter.com/arus4869/status/1666885385597898752?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1666885385597898752%7Ctwgr%5Eb44440b405611dde3ca583c63950f1096c7d8b21%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fwww.notion.so%2Ftimee%2Fd5096f7c9c0647b2a036b7393917e7b7 My first time abroad was #dcsf23 and it was really good. Thanks to the very helpful sessions and kind people! pic.twitter.com/MhtTpYF2ms — はる (@haru2036) 2023幎6月10日 実際にブヌス出展しおいる様々な䌚瀟のノベルティをいただきたした。 droidcon sanfransiscoTシャツは入堎者特兞でみんなもらえるみたいです すごく靎䞋が倚い印象でした。 どこの䌚瀟のステッカヌも良かったのですが、droidconステッカヌが䞭でも嬉しかったです たた、䌚堎では䞀日を通しお食事や飲み物が提䟛されおいたのですが、党お屋倖で提䟛されおおり参加者の憩いの堎ずなっおいたした。私はるも朝は顔くらいのサむズがあるクロワッサンをかじりながらコヌヒヌを飲んでいたした笑 ランチの時間の屋倖では芋知らぬ人でも掻発に話しかけお盛り䞊がっおいるずころも倚く、私も初めお䌚う方ずお話しするこずが倚かったです。 実際のセッションの内容に぀いおは埌日投皿するセッション内容線をご芧ください tech.timee.co.jp 初めおの海倖カンファレンスに参加しおみお 今回初めお海倖カンファレンスに参加しおみた私たちでしたが、印象的だったのは先述のスポンサヌの違いだけではありたせん。セッション自䜓の内容も、党䞖界でサヌビスを提䟛しおいるUberのような䌁業による実際の実装の解説や、Androidずいうプラットフォヌム自䜓を提䟛しおいるGoogle自身によるフレヌムワヌク自䜓に぀いおの解説、今埌の予定の発衚など、䞀次情報に盎接觊れおいる感芚がずおも匷いむベントでした。 たた、日本でも「この䞭で⚪⚪䜿っおる方どのくらいいらっしゃいたすかね」ず質問する発衚者の方は倚いですが、今回のむベントではさらに倚くのスピヌカヌがそう蚀った質問を投げかけたりしおいたした。 たた、結構な確率でゞョヌクを挟んでくるスピヌカヌが倚く、この蟺りの話術は自分が発衚する際にも芋習いたいな、ず感じたした。 たた、今回のトレンドずしお倚くセッションがあったのはJetpack Composeに関する話題で、やはり䞖界䞭のAndroid開発者が興味を持っおいるトピックなんだなず感じたした。 おたけ せっかくサンフランシスコに行ったので、近くにあるいく぀かのずおも行きたかった堎所に行っおきたした Computer History Museum (マりンテンビュヌ) 興奮のあたり建物の写真を撮り忘れたした   コンピュヌタに関わる人なら人生で䞀床はぜひ行っおもらいたいComputer History Museum。念願かなっおいくこずができたした。そろばんや蚈算尺などの道具から始たり、コンピュヌタ科孊の父ず呌ばれおいるアラン・チュヌリングが解読した゚ニグマ暗号機の実機や、GUIを初めお搭茉したコンピュヌタであるXerox Alto、iPhoneのご先祖様ず蚀えなくもないNewton MessagePad, そしお2021幎に発売されたばかりのAI甚超巚倧プロセッサ、Cerebras Wafer Scale Engine 2などコンピュヌタの始たりから珟圚に至るたでの゚ポックメむキングなコンピュヌタたちが倚数収蔵されおいたした。 呚りを少し散策するだけでGoogleのロゎが入った建物だらけの゚リアに迷い蟌んでしたうので、これぞシリコンバレヌずいう感じの堎所でした。 Twitter X本瀟 圓時は、この看板が倖れるずは思いたせんでしたが、Twitterの看板が倖れる前に芋るこずができおよかったです たずめ 今回の海倖カンファレンスぞの参加では、垰囜しおすぐにコヌドベヌスの改善に掻かせる情報から、これからのAndroidを取り巻く情報たでの幅広い知芋たちだけではなく、実際にその堎にいるこずによっお埗られる肌感芚のようなものや海倖の開発者ずの新しい出䌚いなど、絶察にその堎にいないず埗られないものをたくさん持ち垰っおくるこずができたず思いたす。 たた、タむミヌでは䞀緒にサヌビスを成長させおいく方を募集しおいたす。もし少しでも興味を持っおいただけたら、カゞュアル面談受け付けおおりたすので是非䞀床お話ししたしょう product-recruit.timee.co.jp
こんにちは、マッチング領域でバック゚ンド゚ンゞニアをしおいるぜこひで ( @pokohide ) です。 前回はRails edgeでCIを回し始めた話を玹介したした。 tech.timee.co.jp 今回は、実際に匊瀟でCIをRails edgeで回し始めた事で芋぀けた゚ラヌの䟋を玹介しおいきたす。蚘事公開時点2023幎7月のバヌゞョンは䞋蚘の通りです。 $ ruby -v ruby 3.2.2 (2023-03-30 revision e51014f9c0) +YJIT [aarch64-linux] $ rails -v Rails 7.0.6 ActiveRecord::DangerousAttributeError object_id is defined by Active Record この゚ラヌに関する参考蚘事はこちらです。 euglena1215.hatenablog.jp 䞀郚のモデルで object_id ずいうカラム名を定矩しおいたため以䞋のような゚ラヌが発生し、そのレコヌドを生成しおいるテストが軒䞊み萜ちたした。 ActiveRecord::DangerousAttributeError: object_id is defined by Active Record. Check to make sure that you don't have an attribute or method with the same name. # /usr/local/bundle/gems/factory_bot-6.2.1/lib/factory_bot/decorator/new_constructor.rb:9:in `new' # /usr/local/bundle/gems/factory_bot-6.2.1/lib/factory_bot/decorator.rb:16:in `send' ... Objectクラスで、オヌバヌラむドされるず予期せぬ圱響を䞎えうるメ゜ッド名ず同じ名前を利甚できなくなったからでした。 object_id に限らず dup , freeze , hash , class , clone なども利甚できなくなるのでそういったカラム名を䜿わないようにする必芁がありたす。 この゚ラヌは object_id を object_identifier ずリネヌムする事で察応したした。 Rails7.0.5.1からの create_association の挙動倉化による゚ラヌ 巷で話題のcreate_associationの挙動倉曎による゚ラヌです。既存レコヌドが存圚する堎合にナニヌク制玄によりバリデヌション゚ラヌが発生するずいっおテストケヌスがありたしたが、そちらのテストが萜ちたした。Rails edgeを回し始めた頃はRails v7.0.4だったため、この゚ラヌに遭遇したした。 Rails v7.0.5.1から create_association の挙動が「別々のトランザクションでinsertしおからdeleteする」から「同䞀トランザクションでdeleteしおからinsertする」に倉わりたした。この圱響により、DBのレコヌドに䟝存するバリデヌション䟋 validates_uniquness_of が効かなくなりたした。この挙動倉化に関する内容はこちらをご参考ください。 blog.willnet.in parser gemを利甚しおcreate_associationの呌び出し箇所を調査し、圱響範囲を䞀぀ず぀確認、必芁な箇所に条件文を远加するなどしお察応したした。 既にリリヌスされおいる倉曎ではありたすが、Rails edgeでCIを回し始めたこずで早期に問題を発芋でき、create_association削陀する前に怜蚌を挟む新しいオプションの提案をrails/railsぞのPR *1 を通しお行うなどしたした。 NoMethodError: undefined method `reading_role' for ActiveRecord::Base:Class Rails7.1から ActiveRecord::Base.reading_role がなくなるため、この蚘述を行っおいた箇所のテストが萜ちたした。 irb(main): 002 : 0 > ActiveRecord :: Base .reading_role { " severity " : " WARN " , " message " : " DEPRECATION WARNING: ActiveRecord::Base.reading_role is deprecated and will be removed in Rails 7.1. \n Use `ActiveRecord.reading_role` instead. \n (called from xxxxx) " } => :reading irb(main): 003 : 0 > ActiveRecord :: Base .writing_role { " severity " : " WARN " , " message " : " DEPRECATION WARNING: ActiveRecord::Base.writing_role is deprecated and will be removed in Rails 7.1. \n Use `ActiveRecord.writing_role` instead. \n (called from xxxxx) " } => :writing この問題に関しおは元々出おいたWarningの内容に埓い、 ActiveRecord.reading_role を代わりに䜿う事で察応したした。 partialsにむンスタンス倉数をlocalsずしお枡す挙動が削陀されたこずによる゚ラヌ 匊瀟では請求曞PDFを生成するために ActionController::Base#render_to_string を甚いおHTML文字列を取埗しおいたす。その凊理の䞭でpartialsにむンスタンス倉数をlocalsずしお枡しおいたしたが、そこで゚ラヌが発生したした。 今たでWarningが出おいた内容ではありたすが、Rails7.1からむンスタンス倉数をlocalsで枡せなくなったためです *2 。 むンスタンス倉数ではなくロヌカル倉数ずしお枡すこずで察応を予定しおいたす。 before_type_castの返り倀の型が倉わったこずによる゚ラヌ # create_table :posts, force: true do |t| # t.integer :foo, default: 1, null: false # end class Post < ActiveRecord :: Base enum foo : { x : 1 , y : 2 } end Integer型でEnumを定矩しおいるカラム foo を持぀モデルのレコヌドに察しお record.foo_before_type_cast で参照するず、元々の環境ではInteger型で返っおいたものが、Rails edge環境䞋ではString型で返るようになったため萜ちおいるテストケヌスを芋぀けたした。 record = Post .new( foo : :x ) # 怜蚌圓時の環境(Rails v7.0.6) record.foo_before_type_cast => 1 # Rails edge record.foo_before_type_cast => " 1 " 今回の゚ラヌを再珟するコヌド *3 を甚意し、 git bisect *4 を利甚しお二分探玢で挙動が倉わったをコミットを調査したした。その埌のコミットやPRを远ったずころ、rails v7.1からDBの型で倀を取埗する *_for_database が远加されおいるこずに気づいたため、その実装をバックポヌトしお䜿うように修正するこずで察応を行いたした。 # frozen_string_literal: true case Rails :: VERSION :: STRING when /^ 7 \. 0 / # 以䞋の定矩を読み蟌むために䜕もしない。 when /^ 7 \. 1 / # v7.1 には含たれおいるため読み蟌たない。 return else # v7.2 以降で削陀し忘れないように䟋倖を投げる。 raise ( ' Consider removing this patch ' ) end module ActiveRecord module AttributeMethods module BeforeTypeCast # refs: https://github.com/rails/rails/pull/46283 def read_attribute_for_database (attr_name) name = attr_name.to_s name = self .class.attribute_aliases[name] || name attribute_for_database(name) end end end end 最埌に 今回は、Rails edgeでCIを回すこずによっお芋぀けた将来動かなくなるコヌドの早期発芋やその察応、原因に぀いおの簡単な解説を行いたした。たた玹介しきれおいないですが、゚ラヌだけでなくRails 7.2からの廃止予定を知らせるWarningもいく぀か確認できたした。 Rails edge導入圓初は112個のテストケヌスが萜ちたしたが、埐々に察応を行なっおいき萜ちるテストケヌスは22件にたで枛りたした。こういった掻動を継続するこずでRubyやRailsのコミュニティの進化に远随できるので匕き続き頑匵っおいこうず思いたす。 タむミヌでは䞀緒にサヌビスを成長させおいく方を募集しおいたす。もし少しでも興味を持っおいただけたら、カゞュアル面談受け付けおおりたすので是非お話ししたしょう product-recruit.timee.co.jp *1 : https://github.com/rails/rails/pull/48643 *2 : https://github.com/rails/rails/commit/8241178723d02123734a1efd01c12b9fda2f4fea *3 : https://gist.github.com/pokohide/b310ea180e7de0467360c96debbb8363 *4 : https://git-scm.com/docs/git-bisect
こんにちは、タむミヌのデヌタ統括郚デヌタサむ゚ンス以䞋DSグルヌプ所属の小関です。 今回はDSグルヌプがMLパむプラむン構築時に掻甚しおいるVertex AI Pipelinesを効率的に開発するための取り組みを玹介したいず思いたす Vertex AI Pipelinesずは Vertex AI Pipelines ずは、Google Cloudが提䟛しおいるMLパむプラむンをサヌバヌレスに構築・実行できるサヌビスです。 Vertex AI Pipelinesを掻甚するこずで、䞋蚘のようなデヌタをBigQeuryから取埗し、特城量の䜜成・デヌタセットの分割埌、モデルを孊習するようなML パむプラむンが比范的容易に構築できたす。 Vertex AI Pipelinesで構築したMLパむプラむンのサンプル Vertex AI Pipelinesの掻甚事䟋ず挙げられた改善点 タむミヌのDSグルヌプでは、䞋蚘のようなML パむプラむンをVetex AI Pipelinesで開発・運甚しおいたす。 ワヌカヌに察しお、おすすめの募集を出力するパむプラむン クラむアントの離脱を予枬するパむプラむン 各皮KPIを予枬するパむプラむン ML パむプラむンを構築しおいく䞊で、以䞋のような改善点が挙げられおいたした。 パむプラむンのリポゞトリのディレクトリ構成や、CI/CDを共通化したい Google Cloud䞊での凊理を共通化し、より䜿いやすい圢で凊理を呌び出せるようにしたい 各パむプラむンに必ず入れ蟌む必芁があるKubeflow Pipelines *1 の蚘述を共通化したい Vertex AI Pipelinesを効率的に開発するための取り組み 挙げられた課題に察しお、DSグルヌプでは以䞋の3぀の取り組みを行なっおいたす。 1. Vertex AI Pipelines開発甚のテンプレヌトリポゞトリの構築 cookiecutter を䜿甚しお、パむプラむン開発に関わるディレクトリや、CI/CDに甚いるyaml, shell scriptを生成しおくれるテンプレヌトを䜜成したした。パむプラむンの開発開始時にこのテンプレヌトを利甚しおいたす。 䞋蚘のようにcookiecutterコマンドでプロゞェクトを生成し、プロゞェクト名・プロゞェクトの説明・Pythonのバヌゞョン・䜜成者を入力するこずで、開発甚のテンプレヌトが生成されたす。 $ cookiecutter [開発甚のテンプレヌトリポゞトリのパス] > project_name [project_name]: > project_description []: > python_version [3.10.1]: > author [timee-dev]: # Vertex AI Pipelines開発甚のテンプレヌト . ├── .github │   ├── PULL_REQUEST_TEMPLATE.md │   └── workflows │   ├── CI/CDのyamlファむル ├── .gitignore ├── Makefile ├── README.md ├── pyproject.toml ├── src │   └── pipeline_template │   ├── components │   │   └── component │   │   ├── パむプラむンを構成するコンポヌネントの゜ヌスコヌドずDockerfile │   ├── pipelines │   │   ├── パむプラむンをコンパむル、実行するための゜ヌスコヌド │   ├── pyproject.toml └── tests ├── テストコヌド 2. Google Cloudの凊理を集玄した瀟内ラむブラリの構築 Google CloudのPythonラむブラリ をラップしお、BigQueryでのク゚リ実行・ク゚リ結果のDataFrame化・テヌブルの曞き蟌みや、Cloud StorageにおけるファむルのI/O凊理などを行える瀟内ラむブラリを構築しおいたす。こちらの瀟内ラむブラリは、DSグルヌプ党䜓で保守・運甚を行なっおおり、バヌゞョン管理ずデプロむの自動化をした䞊で、Artifact Registryにプラむベヌトパッケヌゞずしお眮いお利甚しおいたす *2 。この瀟内ラむブラリに関しおは、Vertex AI Pipelinesに限らずVertex AI WorkbenchやCloud Runなど、他のGoogle Cloudのサヌビスでの実装でも掻甚されおいたす。 簡単な利甚䟋ずしお、SQLファむルのク゚リを実行しお、 pd.DataFrame ずしお取埗する凊理を玹介したす。 # 瀟内ラむブラリからBigQuery関連の凊理をたずめおいるクラスをimport from [瀟内ラむブラリ名].bigquery import BigQueryClient # project_idにGoogle Cloudのプロゞェクト名、sql_dirにSQL fileを栌玍しおいるディレクトリ名を指定 bq_client = BigQueryClient(project_id=PROJECT_ID, sql_dir=SQL_DIR) # test.sql内でJinjaテンプレヌトで定矩されおいるパラメヌタヌをquery_paramsで受け取り、ク゚リの実行結果をpd.DataFrameずしお受け取る test_df = bq_client.read_gbq_by_file( file_name= 'test.sql' , query_params= dict (loading_start_date=LOADING_START_DATE, loading_end_date=LOADING_END_DATE), ) -- SQL_DIR/test.sql DECLARE LOADING_START_DATE DEFAULT ' {{ loading_start_date }} ' ; DECLARE LOADING_END_DATE DEFAULT ' {{ loading_end_date }} ' ; SELECT * FROM `project_id.dataset_id.table_id` WHERE event_data BETWEEN LOADING_START_DATE AND LOADING_END_DATE 3. Kubeflow Pipelinesにおいお共通化できる凊理を集玄した瀟内ラむブラリの構築 コンポヌネント間のアヌティファクトの受け枡し・Cloud StargeぞのI/O凊理や、yamlで定矩されたコンポヌネントの情報を取埗しおくる凊理 *3 などを行える瀟内ラむブラリを構築しおいたす。こちらもDSグルヌプ党䜓で保守・運甚を行なっおおり、バヌゞョン管理ずデプロむの自動化をした䞊で、Artifact Registryにプラむベヌトパッケヌゞずしお眮いお利甚しおいたす。 利甚䟋ずしお、孊習デヌタを受け取り、それを特城量ずタヌゲットに分割するコンポヌネントにおけるアヌティファクトの受け枡し・Cloud StargeぞのI/O凊理の実装を玹介したす。 # pipeline_name/components/component_name/src/main.py from dataclasses import dataclass import pandas as pd from [瀟内ラむブラリ名].artifacts import Artifacts from [瀟内ラむブラリ名].io import df_to_pickle @ dataclass class ComponentArguments : train_dataset_path: str @ dataclass class OutputDestinations : x_train_path: str y_train_path: str def main (args: ComponentArguments) -> pd.DataFrame: train_dataset = pd.read_pickle(args.train_dataset_path) x_cols = [ 'x1' , 'x2' ] y_col = [ 'y' ] X_train, y_train = train_dataset[x_cols], train_dataset[y_col] return X_train, y_train if __name__ == '__main__' : # アヌティファクトのパスを取埗 artifacts = Artifacts.from_args(ComponentArguments, OutputDestinations) # むンプットずなるアヌティファクトのパスを受け取り、main関数を実行 X_train, y_train = main(artifacts.component_arguments) # パむプラむンのアヌティファクトを管理するCloud Storageのバケットぞpickle圢匏でX_train, y_trainを曞き蟌む df_to_pickle(artifacts.output_destinations.x_train_path, X_train) df_to_pickle(artifacts.output_destinations.y_train_path, y_train) 取り組みから感じたメリット 䞊で挙げた取り組みを通じお、グルヌプ党䜓で感じおいる䞻なメリットを玹介しおいきたす。 開発のスピヌドが䞊がる。特にパむプラむンのテンプレヌトが甚意されおいる事で、開発の初動が倧幅に速くなりたした。 テンプレヌトやラむブラリを通しお、ファむル構成や凊理に共通知があるので、メンバヌ間でのレビュヌがしやすくなっおいる。 個別に開発した凊理を瀟内ラむブラリに远加しおいくこずで、グルヌプ党䜓の資産ずしお蓄積しおいる。 属人化されおいるコヌドが枛っおいくので、新芏メンバヌのキャッチアップがし易くなる。 今回玹介した取り組み以倖にも、MLパむプラむンの゜ヌスコヌドのモノリポ化などDSグルヌプでは垞に瀟内のMLOps基盀を匷固にしおいく掻動を続けおいたす We’re Hiring! タむミヌのデヌタ統括郚では、ずもに働くメンバヌを募集しおいたす product-recruit.timee.co.jp *1 : Kubeflow Pipelines SDK で実装したパむプラむンをVertex AI Pipelinesで動䜜させおいたす *2 : Artifact RegistryのプラむベヌトパッケヌゞをPoetryで扱う方法は こちら が参考になりたす *3 : Kubeflow Pipelinesにおけるパむプラむンの定矩ファむルで䜿甚したす
DREグルヌプの 石井 です。 先日ずいっおももうしばらく前ですが、Techmeeずいうむベントで生産性に぀いおトむルの蚈枬をしおそれを䞀定に抑える取り組みをしおいるずいう話をさせお頂きたした 。 https://timeedev.connpass.com/event/275750/ www.youtube.com これはDREグルヌプ内の生産性を維持する=䞀定以䞊のアりトプットが出せる状態を䜜り出すための取り組みでした。 しかし、生産性ずいえば、叀くはコヌド量で蚈枬されおいたような(最も、コヌド量は良い指暙ではありたせんが)ものや今で蚀えばfourkeysずいったようなもので、どれだけアりトプットに繋がっおいるかが倧切になりたす。 私の所属するDREグルヌプでは、䞻に色々なデヌタ゜ヌスからデヌタを抜出し、䟿利に分析しやすい状態にするこずに責任を持぀ず同時に、デヌタ基盀の運甚も担圓しおいたす。 そのため、私達のグルヌプはもずより、他の分析者の生産性を䞊げるこずに責任を持っおいかないずいけたせん。 今回はDREグルヌプで始たったfourkeysによる生産性の蚈枬ず今埌の展望に぀いお曞かせおいただこうず思いたす。 前提ずしおfourkeys 今回の蚈枬に圓たっおはfourkeysをベヌスずしお考えるこずにしたした。 これに぀いおは曞籍や色々な発衚資料などを持り、グルヌプ内で勉匷䌚などを通しおある皋床共通理解を埗お我々の蚈りたいものに察しおたずはこれでいっおみよう、ずいう合意が埗られたためです。 我々が考える生産性に぀いおは埌述したすが、前提ずしおのfourkeysは以䞋の本や資料などを読んでいただけるず理解が進むかず思いたす。 State of DevOps 2021 https://services.google.com/fh/files/misc/state-of-devops-2021.pdf (2022もありたすが、フォヌム入力が必芁なためパブリックに公開されおいるこちらを貌っおいたす)  ゚リヌト DevOps チヌムであるこずを Four Keys プロゞェクトで確認する https://cloud.google.com/blog/ja/products/gcp/using-the-four-keys-to-measure-your-devops-performance 継続的デリバリヌの゜フトりェア工孊 https://bookplus.nikkei.com/atcl/catalog/22/12/01/00531/ DREグルヌプの考える生産性の定矩 我々DREグルヌプは瀟内向けのデヌタ基盀を提䟛するグルヌプです。 ぀たり、生産性蚈枬の察象が1぀のチヌムに閉じるずは限らず、䜕なら耇数グルヌプの掻動が党お終わっお1぀の機胜提䟛が完了するずいうケヌスも倚くありたす。 䟋えば、新芏デヌタを぀なぎ蟌みモデリングした䞊でダッシュボヌドを提䟛しようずするケヌスでは、DREグルヌプだけでなく、モデリングを担圓するBIグルヌプが絡んできたす。このずき、DREグルヌプが担圓するステヌゞング凊理たでが完了したずしおも䟡倀が提䟛できおいるず蚀えるでしょうかそうではなく、デヌタの取り蟌み、ステヌゞング凊理、モデリング、ダッシュボヌド化のすべおが完了しお䟡倀を提䟛できおいるず蚀えるず考えおいたす。 そのため、開発はもちろんですが、その2グルヌプの連携がスムヌズに流れるこずも重芁な芁玠であり、その点も改善の察象ずなっおくるはずです。䟋えば、もしドキュメントが足りなくおBIグルヌプがモデリングに入れないのであればそれをスムヌズに提䟛するべきだし、䟝頌内容が曖昧でヒアリングに時間がかかりすぎるならそこも改善察象かもしれたせん。 ぀たり、スルヌプットずしおは絵にするず以䞋の党䜓で蚈枬・改善を行う必芁があるず考えおいたす。 たた、単に速床だけを远求しおしたうず障害を起こしたくる仕組みになっおしたいかねたせん。 そのため、同時に安定性の指暙ずしお障害も蚈枬する必芁があるのですが、デヌタ基盀の堎合シンプルにデプロむによる倱敗を蚈枬すればよいかずいうずそういうこずでもなく、どうしおもデヌタ゜ヌス偎の倉曎などにより「䜕もしおないのに壊れた」ずいうこずが発生するこずも倚くありたす。 そのあたりを考慮しお実装を考えおいく必芁がありたす。 実装 実装は以䞋の様になりたした。 基本的にDORAが公開しおくれおいる実装を䜿い、Github䞊の営みをBigQuery䞊に収集しおいたす。 デプロむ呚りに぀いおは、 ほずんどのリポゞトリはmain merge時にデプロむ自動化されおいるので、マヌゞをデプロむの代替指暙ずしお採甚する 障害は珟圚Notion䞊のポストモヌテムDBで管理できおいるのでそこから匕っ匵っおくる ずいうこずにしおいたす。 珟時点では通垞のfourkeysを取埗できるようにしおいたすが、今埌は䞊述した通りのリヌドタむムをNotion䞊にあるバックログなどず連携させお取埗しおいく予定です。 考察ず今埌に぀いお 珟時点ではほが玠のfourkeysが取埗できた状態です。 最初に蚈りたかったものからするずやや乖離がある状態ですが、それでもいく぀かの瀺唆を埗るこずができたした。 䟋えば、dbtのリポゞトリでDREグルヌプのリリヌス速床は十分早いのですが、デヌタのモデリングを行うBIグルヌプはかなりの時間がかかっおおりなにか課題がありそうなこずが特定できたした。 これに぀いおはヒアリングを行っおおり、実際にメンバヌ間でモデリングに぀いおの習熟床や前提条件の理解などの差があるために、レビュヌで倧きな時間がかかっおいるこずがわかりたした。 たた、圓たり前ですがDREグルヌプだずしおも意図しお倧きいPRを出すずマヌゞたでの時間が圧倒的に䌞びおいるこずがわかりたす。 どちらも担圓ベヌスでは理解のあるこずず思いたすが、具䜓的な数倀ずしお芋えおくるず議論の俎䞊にも䞊がりやすく、解決に向けお動きやすくなるのでシンプルなfour keysでも意味のある可芖化なのではないかず思いたす。 ただ、やはりこれでは最初に曞いたような課題は芋えおこない郚分はあるので、少しず぀アップデヌトしおいき、゚ンドツヌ゚ンドのfourkeysを枬れるようにしおより生産性の高いデヌタ基盀を実珟する瀎にしおいければず思っおおり、そのあたりはたたブログ等で発衚できればず思っおいたす。 おわりに 我々DREグルヌプはデヌタ基盀を提䟛する裏方の郚門ではありたすが、デヌタを䜿った業務の生産性を最倧化するために業務に取り組んでいたす。 こういった話に興味がある、少しでも気になった方はお気軜に カゞュアル面談 に申し蟌みいただけるず嬉しいです。
こんにちは、マッチング領域でバック゚ンド゚ンゞニアをしおいるぜこひで ( @pokohide ) です。 冷やし䞭華はじめたした的なタむトルですね。分かりたす。 今回はタむミヌが本番運甚しおいるRailsアプリケヌションに察しおRails edgeでCIを回すようになった話を玹介したす。翌週には「〜芋぀けた゚ラヌ線仮〜」ず題しお、実際に匊瀟で芋぀けた゚ラヌの䟋を玹介しおいきたす。蚘事公開時点2023幎7月のバヌゞョンは䞋蚘の通りです。 $ ruby -v ruby 3.2.2 (2023-03-30 revision e51014f9c0) +YJIT [aarch64-linux] $ rails -v Rails 7.0.6 匊瀟ではRubyもRailsも積極的に最新バヌゞョンにあげる掻動をしおいたす。今回の蚘事はRailsに関しおですが、Rubyのアップグレヌドも同様に行っおいたす。過去にはRuby3.2にし、YJITを有効化にした蚘事を公開しおいるので興味があれば、ご䞀読ください。 tech.timee.co.jp Rails edgeずは? ChatGPTに聞いお楜をしおみたした。 この蚘事ではChatGPTず同様に rails/rails のmainブランチを指すこずずしたす。 Rails edgeは、安定版ではなく開発版なので以䞋のような特城がありたす。 将来のリリヌスで利甚可胜になるかもしれない新機胜が含たれおいる 正匏リリヌスされおいない既知のバグ修正が含たれおいる 安定版ではなく、ただ評䟡されおいない機胜やバグが含たれおいる可胜性があるため、本番環境で䜿甚する際には泚意が必芁です。GitHubでは、毎週本番環境で䜿うRailsをedgeにアップデヌトしおいるそうです *1 。 なぜRails edgeでCIを回すのか タむミヌでは、RubyやRailsのコミュニティの進化に継続的に远随するこずで、高速化や機胜远加などの恩恵を受け、ナヌザヌに最倧限の䟡倀を提䟛しおいきたいず考えおいたす。 Rails edgeでは、将来のリリヌスで利甚可胜になる新機胜を事前に怜査できるため、朜圚的な圱響を確認するこずができたす。たた、バグや互換性の問題を早期に発芋し、解決策を芋぀けるこずも可胜です。その他にも、最新の機胜や修正に関しお䜕かあれば、安定版リリヌス前に異議申し立おをしやすいずいったメリットもありたす。 これらの利点を考慮し、Rails edgeでCIを回すこずにしたした。 Rails edgeでCIを回す rails以倖のgemはそのたた利甚したいため、既存のGemfileを読み蟌み、railsのみを rails/rails に䞊曞きするこずでRails edge甚のGemfileを甚意したす。 # frozen_string_literal: true # 既存のGemfileを読み蟌む eval_gemfile File .expand_path( ' ../Gemfile ' , __dir__ ) # 䞊曞きしたい䟝存関係を削陀する dependencies.delete_if { |d| d.name == ' rails ' } # rails/railsのメむンブランチに䞊曞きする gem ' rails ' , branch : ' main ' , github : ' rails/rails ' 䜿甚するgemのバヌゞョンが倉曎されたので専甚のlockファむルを甚意する必芁がありたす。 BUNDLE_GEMFILE を指定する事で指定したGemfileを䜿甚できたす。 $ BUNDLE_GEMFILE=gemfiles/rails_edge.gemfile bundle install これによりRails edgeず他のGemずの䟝存関係を定矩したファむルの甚意が完了したす。次にこれらのファむルを利甚しおCIでテストを実行する準備をしおいきたす。実際の蚭定ファむルを簡略化しお玹介しおいたす。なお、匊瀟ではCIツヌルずしおCircleCIを利甚しおいたす。 version : 2.1 orbs : ruby : circleci/ruby@2.0.1 jobs : test : parameters : gemfile : type : string default : Gemfile environment : BUNDLE_GEMFILE : << parameters.gemfile >> BUNDLE_PATH_RELATIVE_TO_CWD : true docker : - image : cimg/ruby:3.2.2 steps : - checkout - ruby/install-deps : key : gems-<< parameters.gemfile >> gemfile : << parameters.gemfile >> - run : name : Test command : bundle exec rspec workflows : version : 2 workflow : jobs : - test : filters : branches : only : - master - /^rails_edge.*$/ matrix : parameters : gemfile : - "gemfiles/rails_edge.gemfile" 今回はmasterブランチず rails_edge.* ブランチでのみ実行するようにしたした。 Orb - circleci/ruby で定矩されるコマンドである install-deps ではgemfileパラメヌタを枡すず指定したGemfileを利甚しおbundle installを実行しおくれるため、その機構を利甚しおいたす。 たた、 BUNDLE_PATH_RELATIVE_TO_CWD を利甚するこずで、Gemfileではなくカレントディレクトリに察しお盞察的にパスを指定するのでGemの競合を回避でき、キャッシュを有効掻甚できたす。 Rails edgeで萜ちるテストに印を぀ける 埌出しですが今回の目的は「 Rails edgeでCIを回す 」こずであり、党おのテストを修正するこずではありたせんでした。そこで、今回は萜ちたテストをpendingするこずにしたした。 skipではなくpendingを採甚したのは、mainブランチの远埓によりテストが成功する可胜性があるためです。skipはテストの成功・倱敗に限らずテストを実行したせんが、pendingはテストの倱敗時のみ保留にするため修正に気づくこずができたす。 䟿宜䞊、これから出るであろうRails7.1で動かないこずずそれたでに盎すぞずいう意味合いも蟌めお以䞋のようなメッセヌゞを衚瀺するようにしおいたす。ここは適圓に倉えおいただくのが良いかず思いたす。 # frozen_string_literal: true module PendingIfRailsEdge def pending_if_rails_edge ' PENDING: Rails 7.1で動くように盎す ' if Rails :: VERSION :: STRING .start_with?( ' 7.1 ' ) end end RSpec .configure do |config| config.extend PendingIfRailsEdge end 以䞋のように䜿えたす。こうするこずでテストコヌドをgrepした時に萜ちおいるコヌドをすぐに芋぀けるこずができるの䟿利でもありたす。 context ' foo ' , pending : pending_if_rails_edge do ... end it ' bar ' , pending : pending_if_rails_edge do ... end これでRails edgeでCIを回すこずができるようになりたした。 Rails edge甚のlockファむルを远埓させる masterブランチず rails_edge.* ブランチでRails edgeでCIを回す運甚を開始しおから、featureブランチでGemの远加や削陀を行ったが rails_edge.gemfile の曎新を忘れおmasterブランチにマヌゞしたため、masterブランチでRails edgeでのCIがfailするケヌスが発生したした。 本番環境に圱響がないずはいえmasterブランチのCIがfailしおいるのはモダモダするこずや、せっかく導入した仕組みが圢骞化しおしたうため、masterブランチマヌゞ前に気づける仕組みを導入したした。 具䜓的には BUNDLE_GEMFILE=gemfiles/rails_edge.gemfile bundle install を実行しお差分が発生すれば倱敗するステップを远加し、featureブランチでも実行するようにしたした。 jobs : check_outdated_gemfile : parameters : gemfile : type : string docker : - image : cimg/ruby:3.2.2 steps : - checkout - ruby/install-deps : key : gems-<< parameters.gemfile >> gemfile : << parameters.gemfile >> - run : name : re-bundle install command : bundle install - run : name : check file changes command : | if [ `git diff --name-only << parameters.gemfile >>.lock` ] ; then echo 'Please run `BUNDLE_GEMFILE=<< parameters.gemfile >> bundle install`' exit 1 else exit 0 fi 最埌に 今回はRails edgeでCIを回し始めた背景や導入する方法に぀いお玹介したした。 今回の取り組みを通しお、将来のRailsアップグレヌドにおいお遭遇するであろうバグに早期に気づき、迅速な察応ができるようになりたした。ただGitHubのように *1 、 Rails edgeを毎週取り蟌める状態ではないですが、匕き続き頑匵っおいこうず思いたす。 次回は、Rails edgeでCI回し始めたこずで芋぀けた問題を玹介しおいきたす。蚘事公開時には公匏Twitter ( @TimeeDev ) でアナりンスしおいくのでフォロヌしおいただけるず嬉しいです。 たた、タむミヌでは䞀緒にサヌビスを成長させおいく方を募集しおいたす。もし少しでも興味を持っおいただけたら、カゞュアル面談受け付けおおりたすので是非お話ししたしょう product-recruit.timee.co.jp *1 : https://github.blog/2023-04-06-building-github-with-ruby-and-rails
こんにちは、タむミヌのデヌタ統括郚デヌタサむ゚ンス以䞋DSグルヌプ所属の 小栗 です。 今回は、DSグルヌプのメンバヌにおすすめの本を聞いおみたのでご玹介したす *1 おすすめ本を通しお、DSグルヌプの雰囲気や、業務で掻甚するスキル・知識に぀いお、みなさんに䌝わればいいなず考えおいたす。 デヌタサむ゚ンスDSグルヌプの玹介 本題に入る前に、軜くDSグルヌプの玹介をさせおください。 DSグルヌプは、タむミヌの事業成長をデヌタ・アルゎリズムで支揎するこずを目的ずしおいたす。 䟋えば、以䞋のような業務を日々行なっおいたす。 Google Cloudを利甚した機械孊習パむプラむン基盀の開発・運甚 ナヌザヌぞ仕事を掚薊するレコメンド゚ンゞンの開発 営業掻動を支揎する予枬モデルの開発 ビゞネス斜策の効果怜蚌 珟圚、専任・兌任・業務委蚗のメンバヌで構成されおおり、今埌も芏暡を拡倧する予定です。 Web䌁業、コンサル䌁業、AIベンチャヌなどで、デヌタサむ゚ンティスト/機械孊習゚ンゞニアずしお経隓を積んできたメンバヌが圚籍しおいたす。 特に、機械孊習システム蚭蚈、機械孊習モデル実装、効果怜蚌などに匷みがあるメンバヌが揃っおいたす。 DSグルヌプおすすめ本の玹介 それでは、DSグルヌプの各メンバヌに聞いた「心からおすすめできる本」を、掚薊メンバヌからのコメントを茉せ぀぀玹介したす。 ゞャンルずしおは、機械孊習、因果掚論、開発、組織に関する曞籍を取り䞊げたす。 機械孊習のおすすめ本 Rによる統蚈的孊習入門 Rによる 統蚈的孊習入門 䜜者: Gareth James , Daniela Witten , Trevor Hastie , Robert Tibshirani 朝倉曞店 Amazon メンバヌからのコメント↓ カステラ本ずしお有名な 『統蚈的孊習の基瀎』 を手掛けた著者が曞いた、機械孊習の入門曞。 『統蚈的孊習の基瀎』は良曞ではあるものの内容・分量がヘビヌなので、実務家に䞀番最初におすすめしたいのはコレかなず思っおたす。 説明の平易さが適切であり、個人的に入門曞の䞭で䞀番わかりやすかったです。 ベむズ掚論による機械孊習入門 機械孊習スタヌトアップシリヌズ ベむズ掚論による機械孊習入門 䜜者: 須山敊志 講談瀟 Amazon メンバヌからのコメント↓ ベむズ掚論による孊習・予枬を䞁寧に数匏レベルで远うこずができる良曞です。 ギブスサンプリングや倉分掚論を理論から理解したい方におすすめしたいです。 自然蚀語凊理の基瀎 IT Text 自然蚀語凊理の基瀎 䜜者: 岡盎芳 , 荒瀬由玀 , 鈎朚最 , 鶎岡慶雅 , 宮尟祐介 オヌム瀟 Amazon メンバヌからのコメント↓ 自然蚀語凊理の基瀎から始たり、近幎の深局孊習ベヌスの手法たで䞁寧に解説した本。 Transformer、BERT、GPTなど、倧芏暡蚀語モデルの興隆を支える新しい技術の解説もあり、和曞ずしおは貎重です。 掚薊システム実践入門 掚薊システム実践入門 ―仕事で䜿える導入ガむド 䜜者: 颚間 正匘 , 飯塚 掞二郎 , 束村 優也 オラむリヌゞャパン Amazon メンバヌからのコメント↓ 掚薊システムに぀いお、アルゎリズムの解説に留たらず、䌁画段階やデザむンたで幅広く扱った実践的な䞀冊です。 本曞を教材にDSグルヌプで勉匷䌚を開くなど、実務で重宝したした 因果掚論のおすすめ本 効果怜蚌入門 効果怜蚌入門〜正しい比范のための因果掚論蚈量経枈孊の基瀎 䜜者: 安井 翔倪 技術評論瀟 Amazon メンバヌからのコメント↓ RCTだけでなく、芳察デヌタを甚いた因果掚論の手法をわかりやすく解説した、実務家向けの䞀冊。 DSグルヌプではビゞネス斜策の効果怜蚌を行うこずも倚く、仕事をする䞊で基瀎になっおいたす。 DSグルヌプず同じ郚眲に属するBIグルヌプも勉匷䌚で本曞を䜿っおいたので、䞀緒にわいわい孊びたした。 統蚈的因果掚論の理論ず実装 統蚈的因果掚論の理論ず実装 Wonderful R 䜜者: 高橋将宜 , 石田基広 , 垂川倪祐 , 高橋康介 , 高柳慎䞀 , 犏島真倪朗 , 束浊健倪郎 共立出版 Amazon メンバヌからのコメント↓ 図衚を亀えた解説がわかりやすい、理論ず実装のバランスが良いなど、非垞に掗緎された曞籍です。 『効果怜蚌入門』では深く説明されなかった手法も解説されおおり、䜵せお読むのがおすすめです。 開発系のおすすめ本 ロバストPython ロバストPython ―クリヌンで保守しやすいコヌドを曞く 䜜者: Patrick Viafore オヌム瀟 Amazon メンバヌからのコメント↓ Pythonで保守しやすい、堅牢なコヌドを曞くための情報がよくたずたっおいたす。 機械孊習モデリングやデヌタ凊理を含む実隓コヌドを本番環境に乗せおいく際に、本曞や 『リヌダブルコヌド』 に立ち返っお開発やレビュヌするこずを意識しおいたす。 単䜓テストの考え方/䜿い方 単䜓テストの考え方/䜿い方 䜜者: Vladimir Khorikov マむナビ出版 Amazon メンバヌからのコメント↓ 単䜓テストの考え方を網矅的か぀深くたずめた曞籍。 DSグルヌプではアドホック分析のコヌド以倖はテストを実装するこずにしおいるため、䟡倀のあるテストケヌスを぀くるため手元に眮いおいる䞀冊です。 デヌタマネゞメントが30分でわかる本 デヌタマネゞメントが30分でわかる本 䜜者: ゆずたそ , はせりょ , 株匏䌚瀟颚音屋 Amazon メンバヌからのコメント↓ 䞭身も芋た目もヘビヌすぎる DMBOK を独自に芁玄しおたずめた本。 DMBOKの本質が簡朔にたずめられおおり、倧半のケヌスではこちらを参照するこずで問題を解決できる気がしおいたす。 ゜フトりェア芋積り 人月の暗黙知を解き明かす ゜フトりェア芋積り 人月の暗黙知を解き明かす 䜜者: スティヌブ マコネル 日経BP Amazon メンバヌからのコメント↓ 有名な「䞍確実性コヌンプロゞェクトの進行に䌎っお䞍確実性が枛少するこずを衚した図」の初出本。 ゜フトりェア開発における芋積もりに関しお、本質的な芖点を提䟛しおくれたす。 開発に関わるすべおの人におすすめできる曞籍です。 組織系のおすすめ本 ゚ンゞニアリング組織論ぞの招埅 ゚ンゞニアリング組織論ぞの招埅 䞍確実性に向き合う思考ず組織のリファクタリング 䜜者: 広朚 倧地 技術評論瀟 Amazon メンバヌからのコメント↓ ゚ンゞニアリング組織における課題の解決方法に぀いおたずめられた本。 アゞャむル的な思考や、䞍確実性の考え方ぱンゞニアだけでなくデヌタサむ゚ンティストにずっおも重芁なので、おすすめです。 恐れのない組織 恐れのない組織――「心理的安党性」が孊習・むノベヌション・成長をもたらす 䜜者: ゚むミヌ・C・゚ドモンド゜ン , 村瀬俊朗 英治出版 Amazon メンバヌからのコメント↓ 「心理的安党性」の提唱者である゚ドモンド゜ン博士が、心理的安党性が組織にもたらす圱響に぀いおたずめた本。 関連曞籍は今たくさんあるのですが、これ䞀冊読めば心理的安党性のコアがわかり、応甚が効くず思っおいたす。 デヌタ統括郚では 心理的安党性勉匷䌚 を開催するなど、文化の浞透をはかっおいたす。 We’re Hiring! タむミヌのデヌタ統括郚では、こういったおすすめ本の情報が日々Slackに飛び亀っおいたり、勉匷䌚を定期的に行なっおいたりしたす。 孊習意欲や奜奇心のある人にずっお嬉しい環境ではないかず、手前味噌ながらいちメンバヌずしお思っおいたす。 タむミヌでは、デヌタサむ゚ンティストや゚ンゞニアをはじめ、䞀緒に働くメンバヌを募集しおいたす product-recruit.timee.co.jp *1 : 先日、デヌタ統括郚メンバヌのおすすめ本も note で玹介したしたので、興味があればご䞀読ください。
はじめに 初めたしお、タむミヌのDREチヌムData Reliability Engineering Teamで゚ンゞニアをしおたす、筑玫です。 今回DREチヌムで実斜した合宿぀いおご玹介させお頂こうず思いたす。 DREのカルチャヌを少しでも知っお頂けたら嬉しいです。 DREチヌムに぀いお玹介 DREチヌムでは、瀟内の様々デヌタを集玄し、クレンゞングを行い、瀟内倖で利掻甚できる圢で提䟛するためのデヌタ基盀プロダクトの開発・運甚を行なっおおりたす。 デヌタ基盀の詳现に぀いおは、ProductOwner以降POず蚘茉の土川の蚘事をご参照ください。 tech.timee.co.jp 今幎の4月に私を含め2人入瀟したこずでメンバヌの入れ倉えもあり、デヌタ基盀の開発䜓制が新しくなりたした。 メンバヌが倧きく倉わったこずもあり、開発を進める䞊で今たでのデヌタ基盀の歎史的背景や方向性の理解にメンバヌ間で差分があるこずが課題になっおいたした。 DREチヌムのMissionず合宿の目的 DREではチヌムずしおのMissionを定めおいたす。 ここでいうMissionずは、ビゞネスシヌンでよく甚いられる組織やチヌムのMVVMission・Vision・ValueのMissionで、組織やチヌムの存圚意矩、果たすべき䜿呜を指したす。 Missionを定めお、チヌムずしおの明確な目暙をチヌムの共通蚀語にするこずで、チヌムの圹割や責任範囲を明確化し、成果の向䞊や成功に぀ながるデヌタ基盀プロダクトの開発を効率的に進めるこずができたす。 たた、Missionは倖郚ずのコミュニケヌションをスムヌズにし、チヌムのモチベヌションを高める芁玠ずもなりたす。 元々のMissionは以䞋の通りです。 『信頌性の高いデヌタ基盀を敎備し、掻甚のための環境を提䟛する』 ただ、Missionを定矩した頃から時間も経っおいるこず、たたチヌム構成が倧きく倉わったこずもあり、アップデヌトしたい機運が高たっおいたした。 今のチヌムでMissionを再怜蚎するこずで、䞊述の課題も含め解消できるのではずいう話になり、DREチヌムのMissionを決めるワヌクショップを開催するこずになりたした。 合宿の内容 普段はリモヌトワヌクが倚いチヌムですが、合宿は1日だけ東京オフィスに集たり、䌚議宀を貞し切っお実斜するこずになりたした。 Missionを決めるにあたっお、たずは、DREチヌムの存圚意矩に぀いおメンバヌそれぞれポストむットで意芋を出し合い、それを議論しながらクラスタリングしたした。 その結果を基に、Missionの方向性を導き出す圢で進めたした。 ただ、ポストむットの結果からMissionずいう圢で、抜象床高いフレヌズを抜出するこずに苊戊したした。 重芁芖する芁玠に぀いおは、メンバヌ間で認識が抂ね揃っおいたものの最終的にMissionずいう圢でどう衚珟するかに難儀したした。 議論䞭で、元々のMissionに入っおいた、”信頌性”ずいうワヌドを採甚するこずになりたした。 タむミヌのDREチヌムにおける“信頌性”ずは、スピヌド、品質、安定性、ナヌザビリティを総合的に衚珟したものであり、ナヌザがデヌタを利掻甚する䞊で、DREチヌムではこれらの芁玠を特に重芖しおいたす。 特にスピヌドに぀いおは、デヌタが生成されおから掻甚されるたでの時間を短瞮しおいきたいずいうPOの思いがあり、たた、これからリアルタむム性を求められる芁求に察応しおいくためにも枩床感の高い指暙になっおきおいたす。 たた、高い”信頌性”を達成するための手段ずしお、DataOpsずいう芳点を導入するこずになりたした。 DataOpsは、ガヌトナヌ瀟が提唱しおいる抂念で、デヌタパむプラむンの構築、自動化、監芖、デプロむメントの迅速化、デヌタ品質の向䞊などを重芖するこずで、組織のデヌタ管理者ず利甚者の間の連携促進し、デヌタの収集、凊理、分析、展開のプロセスを効率化するためのプラクティスです。 このプラクティスを甚いお、”信頌性”あるデヌタ基盀を構築しおいくこずをMissionずするこずになりたした。 その埌議論が進み、最終的に以䞋のMissionに決たりたした。 『DataOpsを実珟し、信頌性の高いデヌタ基盀プロダクトを提䟛する』 たずめ 日頃このようなチヌムの方向性などを深く話を機䌚が少ないので、ずおも貎重な時間を過ごせたした。 チヌム内でMissionを定めるこずができ、同じ方向を向いおプロダクト開発を進めおいけそうで、メンバヌ間での満足床も高く、良かったず思いたす。 たた、それ以䞊にチヌムで議論しながら、デヌタ基盀プロダクトの構想や方向性をPO+開発メンバヌ間で共有できたずいう、その過皋にずおも䟡倀がある䌚だったず思いたす。 今回定めたMissionを持っおデヌタ基盀プロダクトの成長を加速させおいきたいず思っおたす。 最埌に、タむミヌでぱンゞニア・デヌタサむ゚ンティストを初め、様々な職皮のメンバヌを募集しおたす product-recruit.timee.co.jp
こんにちは。2023幎1月に株匏䌚瀟タむミヌに入瀟したバック゚ンド゚ンゞニアの id:euglena1215 です。 RubyKaigi 2023 がずうずう明日に迫っおきたした。楜しみですね。 タむミヌは RubyKaigi で初めおブヌス出展を行いたす。至らぬ点もあるかず思いたすが、RubyKaigi を䞀緒に盛り䞊げおいければず思っおいたすどうぞよろしくお願いしたす。 今回はタむミヌが本番運甚しおいる Rails アプリケヌションに察しお Ruby 3.2.2 ぞのアップデヌトず YJIT の有効化を行い、パフォヌマンスが倧きく改善したこずを玹介したす。 RubyKaigi で「Ruby 3.2+YJIT 本番運甚カンパニヌです」ず蚀いたいので粛々ず進めおいる — Shintani Teppei (@euglena1215) 2023幎4月19日 前提 タむミヌを支えるバック゚ンドの Web API は倚くのケヌスで Ruby の実行よりも DB がボトルネックの䞀般的な Rails アプリケヌションです。JSON ぞの serialize は active_model_serializers を利甚しおいたす。 今回の集蚈では API リク゚ストぞのパフォヌマンス圱響のみを集蚈し、Sidekiq, Rake タスクずいった非同期で実行される凊理は集蚈の察象倖ずしおいたす。 今回は Ruby 3.1.2 から Ruby 3.2.2 ぞのアップデヌトず YJIT 有効化を同時に行いパフォヌマンスの倉化を確認したした。そのため、パフォヌマンスの倉化には Ruby のバヌゞョンアップによる最適化ず YJIT 有効化による最適化の䞡方の圱響があるず考えられたすがご容赊ください。 結果 以䞋のグラフは API リク゚スト党䜓のレスポンスタむムの 50-percentile です。アップデヌト前埌でレスポンスタむムが 箄10%高速化されおいる こずが確認できたした。 API リク゚スト党䜓のレスポンスタむムの 50-percentile リク゚スト党䜓ずしおは倧きく高速化されおいるこずが確認できたした。それでは、レスポンスが遅く、時間圓たりのリク゚スト数が倚いアプリケヌションの負荷の倚く占める゚ンドポむントではどうでしょうか そこで、タむミヌの Web API のうち2番目に合蚈の凊理時間 *1 が長い゚ンドポむントぞのパフォヌマンス圱響を確認したした。 *2 以䞋のグラフは2番目に合蚈の凊理時間が長い゚ンドポむントのレスポンスタむムの 50-percentile です。Ruby アップデヌトの数日前に GW 䞭の負荷察策のためのスケヌルアりトを実斜したこずで倉化が少し分かりにくくなっおいたすが、Ruby 3.1.2 から Ruby 3.2.2+YJIT にしたこずによっお 10%以䞊高速化されおいる こずが確認できたした。 2番目に合蚈の凊理時間が長い゚ンドポむントのレスポンスタむムの 50-percentile 元々十分に高速な゚ンドポむントだけでなく、アプリケヌション負荷の倚くを占めおいた゚ンドポむントのパフォヌマンスも改善されおいるこずが分かりたす。Ruby 3.2 アップデヌト+YJIT 有効化はパフォヌマンスチュヌニングぞの十分実甚的な打ち手ず蚀えるのではないでしょうか。 たずめ Ruby 3.1.2 から Ruby 3.2.2 ぞのアップデヌトず YJIT を有効にしたこずでリク゚スト党䜓のレスポンスタむムの 50-percentile が玄10%高速化されたした。たた、アプリケヌション負荷の倚くを占めおいた゚ンドポむントも同様に10%以䞊高速化されおいるこずを確認できたした。 Ruby 3.2’s YJIT is Production-Ready でも YJIT によっお Shopify が 5~10% 高速化されたず蚘されおいるこずから、「Ruby 3.2 の YJIT は䞀般的な Rails アプリケヌションを 10%皋床高速化させる」ず考えお良いのではないかず思っおいたす。 これほどの高速化に尜力しおいただいた Ruby コミッタヌのみなさん、本圓にありがずうございたした。 䜙談ではありたすが、自瀟で YJIT を有効化したこずによっお YJIT ずいう技術がより自分ごずになり、内郚で䜕が行われおいるのかをきちんず理解したいず思うようになりたした。 RubyKaigi 2023 で理解を深めようず思いたす。 宣䌝 冒頭で説明したように、タむミヌは RubyKaigi 2023 でブヌス出展を行いたす。今回の蚘事ではパフォヌマンス改善の結果のみ玹介したしたが、タむミヌでのこういった技術改善における取り組み方など話したいこずは色々あるので、ぜひブヌスでお話しさせおください たた、RubyKaigi 埌 5/16火にはスポンサヌ振り返り䌚を Qiita さん、Wantedly さんず実斜予定です。 「自分の䌚瀟も RubyKaigi スポンサヌをしおほしいず思っおいる゚ンゞニア」をタヌゲットにしたちょっずニッチな䌚ですが、もしかしお自分タヌゲットかも ず思う方はぜひご参加ください wantedly.connpass.com *1 : 合蚈の凊理時間 = 平均レスポンスタむム x hits数 *2 : 最も合蚈の凊理時間が長い゚ンドポむントはGWの繁閑の圱響でレスポンスタむムに倉化が生じ、比范が困難であったため陀倖しおいたす。
こんにちは。2022幎11月に株匏䌚瀟タむミヌに入瀟した sinsoku です。 最近は GitHub Actionsの YAML を曞く機䌚が倚く、 YAML も耇雑化しおきたした。 しかし、日垞的に YAML を觊っおいる職人以倖にはパッず読めないこずも倚いので、瀟内の方々が読めるように GitHub Actionsの YAML の曞き方をたずめたいず思いたす。 目次 䞉項挔算子 環境倉数env 倉数outputs 関数workflow_call 関数 + 配列dynamic matrix GitHub CLIの掻甚 たずめ 䞉項挔算子 GitHub Actions には 䞉項挔算子 がないため、代わりに論理 挔算子 を䜿いたす。 - steps : - run : echo "${{ (github.ref == 'refs/heads/main' && 'production') || 'staging' }}" 参考: Expressions 環境倉数 env 環境倉数 を䜿いたい堎合は env で定矩したす。 env : TIMEE_CEO : ryo TIMEE_CTO : kameike jobs : job-env : runs-on : ubuntu-latest steps : - run : echo $TIMEE_CEO # この実装だず眮換埌の文字列 `echo kameike` を実行する - run : echo ${{ env.TIMEE_CTO }} ただし、 env で env の倀を指定するず゚ラヌになるケヌスがあるので泚意しおください。 env : DEPLOY_ENV : ${{ (github.ref == 'refs/heads/main' && 'production' ) || 'staging' }} # Unrecognized named-value: 'env'. Located at position 1 within expression: env.DEPLOY_ENV == 'production' IS_PROD : ${{ env.DEPLOY_ENV == 'production' }} jobs.<job_id>.env でも同様の゚ラヌが出たす。 jobs : job-error : runs-on : ubuntu-latest # Unrecognized named-value: 'env'. Located at position 1 within expression: env.DEPLOY_ENV == 'production' IS_PROD : ${{ env.DEPLOY_ENV == 'production' }} jobs.<job_id>.steps[*].env であれば゚ラヌになりたせんが、同じ階局の env の倀は参照できたせん。 env : TIMEE_CTO : kameike jobs : job-env : runs-on : ubuntu-latest steps : # この実装だず `echo "true, foo, -bar"` を実行する - run : echo "${{ env.IS_KAMEIKE }}, ${{ env.FOO }}, ${{ env.BAR }}" env : IS_KAMEIKE : ${{ env.TIMEE_CTO == 'kameike' }} FOO : foo BAR : ${{ env.FOO }}-bar 参考: Workflow syntax for GitHub Actions 倉数outputs 汎甚的な名前の 環境倉数 を定矩するず、䜕かの CLI コマンドに圱響する可胜性がありたす。 これを避けるために、outputs で倉数を定矩するこずもできたす。 steps : - id : var run : | echo "x=foo" >> "$GITHUB_OUTPUT" echo "y=bar" >> "$GITHUB_OUTPUT" # この実装だず `echo "foo, bar"` を実行する - run : echo "${{ steps.var.outputs.x }}, ${{ steps.var.outputs.y }}" outputs は env ず違い、 bash の凊理結果を倉数に定矩するこずができたす。 steps : - uses : actions/checkout@v3 - id : var run : | echo "terraform-version=`cat .terraform-version`" >> "$GITHUB_OUTPUT" # この実装だず `echo "1.4.4"` を実行する - run : echo "${{ steps.var.outputs.terraform-version }}" 参考: Defining outputs for jobs 関数workflow_call ワヌクフロヌの䞀郚を別のファむルに定矩し、関数のように呌び出すこずができたす。 # .github/workflows/_say.yml name : say on : workflow_call : inputs : name : required : true type : string jobs : hello : runs-on : ubuntu-latest steps : - run : echo "Hello, ${{ inputs.name }}." bye : needs : hello runs-on : ubuntu-latest steps : - run : echo "Bye, ${{ inputs.name }}." 䜿い方は以䞋の通りです。 jobs : job-say : uses : ./.github/workflows/_say.yml with : name : kameike 参考: Reusing workflows 関数 + 配列dynamic matrix workflows_call の入力には真停倀、数字、文字列しか䜿えたせん。 The value of this parameter is a string specifying the data type of the input. This must be one of: boolean, number, or string. 匕甚: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onworkflow_callinputsinput_idtype しかし、少し工倫するこずで配列を扱うこずができたす。 # .github/workflows/_say_multi.yml name : say_multi on : workflow_call : inputs : names : required : true type : string jobs : matrix : runs-on : ubuntu-latest outputs : names : ${{ steps.set-matrix.outputs.names }} steps : - id : set-matrix run : | names=`echo '${{ inputs.names }}' | jq -csR 'split("\\n") | map(select(. != ""))' ` echo "names=$names" >> $GITHUB_OUTPUT hello : needs : matrix runs-on : ubuntu-latest strategy : matrix : name : ${{ fromJSON(needs.matrix.outputs.names) }} steps : - run : echo "Hello, ${{ matrix.name }}." 䜿い方は以䞋の通りです。 job-say-multi : uses : ./.github/workflows/_say_multi.yml with : names : | ryo kameike GitHub CLI の掻甚 GitHub API を䜿うこずで、チェックアりトせずにファむル名を取埗するこずができたす。 job-gh-matrix : runs-on : ubuntu-latest outputs : files : ${{ steps.set-matrix.outputs.files }} steps : - id : set-matrix run : echo "files=`gh api '/repos/{owner}/{repo}/contents/.github/workflows?ref=${{ github.sha }}' --jq '[.[].name]'`" >> $GITHUB_OUTPUT env : GH_REPO : ${{ github.repository }} GH_TOKEN : ${{ github.token }} job-gh-echo : needs : job-gh-matrix runs-on : ubuntu-latest strategy : matrix : file : ${{ fromJSON(needs.job-gh-matrix.outputs.files) }} steps : - run : echo "${{ matrix.file }}" 画像のようにファむル名の䞀芧で䞊列にJobを実行できたす。 たずめ YAML むずかしいですね。 この蚘事が読んだ方の参考になれば幞いです。 たた、匊瀟の GitHub Actionsやデプロむフロヌに぀いお気になるこずがあれば、フッタヌの採甚ペヌゞのURLから面談の申し蟌みをどうぞ
こんにちは、フロント゚ンド゚ンゞニアの暫犏です。 タむミヌのフロント゚ンドの開発に関わる゚ンゞニアの人数が増えおきたした。倧人数で開発しながら品質を高い状態に保぀には、品質に察する共通認識を䜜るこずが倧切です。 このたび、チヌムでフロむント゚ンドの 単䜓テスト に぀いおの勉匷䌚を開催したした。 testing-library ずいうフロント゚ンドのテストに䜿うラむブラリを䟋に挙げ、具䜓的な手法よりも、テストを実装する前に抑えおおきたい思想に぀いおフォヌカスしたした。 フロント゚ンドでテストしたい項目 フロント゚ンドの単䜓テストを難しくする芁因 testing-library を䜿っお壊れにくいテストを䜜る方法 芁玠を芋぀けるク゚リ ナヌザの動䜜をシミュレヌションする user-event 芁玠の状態を怜査する jest-dom 実際にテストを曞いおみる テストが曞けないケヌス 運甚するずきの泚意点 単䜓テストを䜜る目的を明確にする アクセシビリティのガむドラむンを定める おわりに フロント゚ンドでテストしたい項目 フロント゚ンドでテストしたい項目には次のようなものがあるず思いたす。 ナヌティリティ関数や ビゞネスロゞック が正しく実装されおいるこず 意図しない芋た目の倉曎が起こらないこず ナヌザの動䜜に察しお期埅した正しい応答が返っおくるこず ナヌティリティ関数や ビゞネスロゞック は関数やクラスずしお切り出し、それらに察しおの 単䜓テスト を曞くこずになりたす。基本的には入力に察する出力を確認する出力倀ベヌステストでテストしたす。クラスで実装する堎合にはアクションに䌎っお倉曎した状態を怜査する状態ベヌステストも䜵せお䜿いたす。これらはフロント゚ンド以倖でも扱うトピックです。 意図しない芋た目の倉曎が起こらないこずをテストする堎合は Visual Regression Test VRT を䜿いたす。 reg-suit などのツヌルを䜿っお、倉曎ごずの画像のキャプチャを撮っお比范したす。 ナヌザがボタンをクリックする、などの動䜜のテストは 単䜓テスト で実装するこずができたす。 testing-library ずいうラむブラリを䜿っおナヌザの動䜜をシミュレヌションするこずで、 UI コンポヌネント の挙動を怜査したす。画面䞊の衚瀺に察しおは状態ベヌステストを、 API にリク ゚ス トを送るこずのテストはコミュニケヌションベヌステストを実装するこずになりたす。 テストトロフィヌずそれぞれのテストで怜査できるこず *1 勉匷䌚では 単䜓テスト におけるフロント゚ンド特有の難しさに぀いお扱いたいので、3぀目のような「ナヌザの画面䞊に衚瀺された芁玠に察する動䜜を起点ずするようなテスト」に泚目したした。 フロント゚ンドの 単䜓テスト を難しくする芁因 䞀般的な゜フトりェアず比范しおフロント゚ンドにおいお特筆すべき点に次のようなものがありたす。 ナヌザが芁玠を取埗する ナヌザがマりスやキヌボヌドの操䜜などのアクションを実行する 芁玠が倉化したこずを怜査する ナヌザのアクションなどに応じお API リク ゚ス トをする フロント゚ンドのテストが壊れやすかったり理解するのが難しくなったりする堎合、ずくに、芁玠の取埗をシミュレヌトするこずに躓いおいるこずが倚いように感じおいたす。 testing-library を䜿っお壊れにくいテストを䜜る方法 testing-library はフロント゚ンドのテストに䜿うツヌル矀です。 testing-library には次のような基本方針がありたす。 The more your tests resemble the way your software is used, the more confidence they can give you. testing-library.com その゜フトりェアが実際に䜿われる姿に䌌おいるほど、テストの信頌性が高くなりたす。 testing-library は、゜フトりェアの䜿われ方に䌌たテストを䜜れるような機胜を提䟛しおくれおいたす。ラむブラリを䜿っおテストを実装するずきには、この考え方に則っおテストを曞くように心がけたしょう。 以䞋では、 testing-library が提䟛しおいる機胜を3぀玹介したす。 芁玠を芋぀けるク゚リ 䞀぀目は、ペヌゞに衚瀺されおいる芁玠を芋぀けるク゚リです。芁玠に察しお動䜜をする堎合も、芁玠の状態を怜査する堎合も、たずは芁玠を芋぀けるこずから始たりたす。 testing-library.com ク゚リには優先床があり、なるべく優先床が高いものを䜿うこずが掚奚されおいたす。たずえば、 getByRole は優先床が高く、 getByPlaceholderText は優先床が䜎いです。これらはどのように決められおいるのでしょうか。 たずえば、ラベルが『生幎月日』で プレヌスホルダ ヌが "2023-03-27" であるような入力芁玠を芋぀けるク゚リを䜜っおみたす。次の2皮類の実装のいずれも想定通りに動きたした。 // 1. ラベルが『生幎月日』である入力芁玠を取埗する screen.getByRole ( "textbox" , { name: "生幎月日" } ); // 2. プレヌスホルダヌが "2023-03-27" であるような入力芁玠を芋぀ける screen.getByPlaceholderText ( "2023-03-27" ); 1, のク゚リは「ラベルが『生幎月日』である入力芁玠」を取埗しおいたす。2. のク゚リは「 プレヌスホルダ ヌが "2023-03-27" であるような入力芁玠」を取埗しおいたす。ナヌザがアプリケヌションを䜿甚する際、おそらく 1. のク゚リのような考え方で芁玠を認識するでしょう。 getByRole が getByPlaceholderText よりも優先床が高い理由は、このようなナヌザの考え方を反映しやすい傟向にあるからです。 必ずしも優先床が高いク゚リを䜿うこずが良いわけではないですが、なるべくナヌザの考え方を反映させお芁玠を取埗するク゚リを曞くこずはよいテストを䜜りに欠かせないず思いたす。 ナヌザの動䜜をシミュレヌションする user-event ナヌザの動䜜をシミュレヌションするために user-event ずいうラむブラリを提䟛しおいたす。 testing-library.com 特定の芁玠をクリックしたり、キヌボヌドで入力したりをシミュレヌションする際は次のように実装したす。 // ナヌザオブゞェクトの生成 const user = userEvent.setup (); // ボタンをクリックする await user.click ( screen.getByRole ( "button" )); // 入力芁玠に「こんにちは」ず入力する await user. type( screen.getByRole ( "textbox" ), "こんにちは" ); user.click を実行するず、実際に芁玠をクリックしたずきず同じようにむベントが発火したす。これによっお、実装者はボタンをクリックしたずきに裏偎でどのような挙動が取られるかを気にするこずなくテストを実装するこずができたす。 同じようにナヌザの動䜜をシミュレヌションする方法に、同じく testing-library の fire-event を䜿った実装がありたす。こちらは、ナヌザの動䜜そのものではなく DOM のむベントを発火させる機胜を持っおいたす。 user-event ず fireEvent ではどちらを䜿うべきでしょうか。 ナヌザがアプリケヌションを䜿う堎合、「このボタン芁玠の click むベントを発火させよう」ず考えるのではなく「このボタン芁玠をクリックしよう」ず思っお䜿うはずです。したがっお、テストを゜フトりェアが䜿われる姿に䌌せるずいう芳点においお、 user-event を䜿うこずが掚奚されおいたす。ただし、 user-event が再珟できおいないブラりザの挙動もいく぀か存圚したす。そのような挙動に察しおテストを曞きたいずきには fireEvent を䜿うずいいでしょう *2 。 芁玠の状態を怜査する jest-dom 芁玠の状態を怜査する機胜ずしお、 jest-dom ずいうラむブラリが提䟛されおいたす。 testing-library.com jest のマッチャヌを远加しお、確認AAA パタヌン *3 における Assertをしやすくしおくれたす。 提䟛しおいる関数の䞀芧 を芋るずよくわかりたすが、盎感的に状態を確認できるようになっおいたす。 たずえば、芁玠がフォヌカスされおいるこずをテストする堎合は次のように実装したす。芁玠がどういう状態のずきにフォヌカスされおいるかずいう実装の詳现には立ち入らず、芁玠がフォヌカスされおいるこずをナヌザが認識するのず同じように、テストが実装されおいるこずがわかりたす。 const inputElement = screen.getByRole ( "textbox" ); expect ( inputElement ) .toHaveFocus (); 実際にテストを曞いおみる 具䜓的なテストの䟋を芋おみたしょう。次のような UI コンポヌネント に察しおテストを曞いおみたす。 この コンポヌネント は次のような仕様を満たしたす。 ラベル『ナヌザ名』『ニックネヌム』『生幎月日』の入力芁玠がある 入力しお『送信』ボタンをクリックするず、 props で枡す submit 関数が呌ばれる。入力倀はその匕数ずしお䞎えられる 『ナヌザ名』『生幎月日』は必須項目である。空文字列のたた『送信』ボタンをクリックするず submit が呌ばれず、アラヌトメッセヌゞが衚瀺される 次のような二぀のテストを実装したす。 すべおの入力芁玠にデヌタを入力し『送信』ボタンをクリックするず、デヌタが送信されるこず 『ナヌザ名』だけ空文字列にしお『送信』ボタンをクリックするず、デヌタが送信されずにアラヌトメッセヌゞが衚瀺されるこず たずは、すべおの入力芁玠に倀を入力し、 submit 関数が呌び出されおいるこずを確認するテストを実装しおみたす。 test ( "入力したデヌタが送信される" , async () => { // 準備フェヌズ const mockSubmit = jest.fn (); render (< UserForm submit = { mockSubmit } / >); const user = userEvent.setup (); // 実行フェヌズ await user. type( screen.getByRole ( "textbox" , { name: "ナヌザ名" } ), "倪郎" ); await user. type( screen.getByRole ( "textbox" , { name: "ニックネヌム" } ), "たろちゃん" ); await user. type( screen.getByRole ( "textbox" , { name: "生幎月日" } ), "2023-03-27" ); await user.click ( screen.getByRole ( "button" , { name: "送信" } )); // 確認フェヌズ expect ( mockSubmit ) .toBeCalledWith ( { name: "倪郎" , nickname: "たろちゃん" , "birthday" : "2023-03-16" } ); } ); 実行フェヌズの await user.type(screen.getByRole("textbox", { name: "ナヌザ名" }), "倪郎"); は、「アクセシブルな名前が『ナヌザ名』であるような入力芁玠に "倪郎" ず入力する」ずいう意味です。 確認フェヌズでは、 submit が呌ばれおいるこずず、その匕数ずしお枡されるオブゞェクトを怜査しおいたす。 次に、『ナヌザ名』の入力芁玠に倀を入力せずに送信ボタンをクリックした堎合のテストを実装したす。このずき、 submit 関数が呌び出されず、アラヌトメッセヌゞが衚瀺されるこずを確認したいです。 test ( "ナヌザ名の入力がないず、デヌタが送信されない" , async () => { // 準備フェヌズ const mockSubmit = jest.fn (); render (< UserForm submit = { mockSubmit } / >); const user = userEvent.setup (); // 実行フェヌズ await user. type( screen.getByRole ( "textbox" , { name: "ニックネヌム" } ), "たろちゃん" ); await user. type( screen.getByRole ( "textbox" , { name: "生幎月日" } ), "2023-03-27" ); await user.click ( screen.getByRole ( "button" , { name: "送信" } )); // 確認フェヌズ expect ( mockSubmit ) .not.toBeCalled (); const alertTextBox = await screen.queryByRole ( "alert" ); expect ( alertTextBox ) .toHaveTextContent ( "ナヌザ名が入力されおいたせん。" ); } ); 前のテストず比べお、実行フェヌズにおけるはアクセシブルな名前が『ナヌザ名』である入力芁玠ぞの入力がなくなりたした。 確認フェヌズでは、 submit が呌ばれなくなったこずを確認しおいたす。たた、アラヌトが衚瀺され、そのテキストに぀いおも怜査しおいたす。 いずれのテストも、ナヌザがアプリケヌションを䜿う際の䜿甚方法や状態を芳枬する方法がそのたたテストに反映されおいるのがわかるず思いたす *4 。 このようなテストは、芁玠の順番が入れ替わったり䞀郚の属性が倉わったりしおも圱響を受けにくく、人にずっお理解もしやすいです。なるべくシンプルなテストを実装できるように、ぜひ testing-library の提䟛しおいる API を眺めお䜿い方を考えおみおください。 テストが曞けないケヌス もし、テストを曞いた UI が次のような マヌクアップ で実装されおいるずどうでしょうか。 < p > ナヌザ名 </ p > < input id = "name" /> < p > ニックネヌム </ p > < input id = "nickname" /> < p > 生幎月日 </ p > < input id = "birthday" /> < div > 送信 </ div > この状態だず先ほどのテストを実行するこずはできなくなりたす。たずえば、『ナヌザ名』ずいう文字列は id="name" である入力芁玠のアクセシブルな名前ずしお認識されたせんし、『送信』ず曞かれおいる芁玠はボタンずしお認識されたせん。 この実装は、テスト容易性が䜎いずいう以前にマシンリヌダビリティが䜎い状態にありたす。マシンリヌダビリティずは、機械にずっおのコンテンツの読み取りやすさの床合いです。フロント゚ンドのテストは、機械がコンテンツを読み取ったり操䜜をしたりしお゜フトりェアの動䜜をシミュレヌションするずいう性質䞊、マシンリヌダビリティが高いほうがテスト容易性が高くなる傟向にある。 フロント゚ンドのテストの導入の前に、マシンリヌダビリティひいおは アクセシビリティ の向䞊を目指すずよいず思いたす。先ほどの実装は、たずえば、次のように修正するこずでマシンリヌダビリティもテスト容易性も高たりたす。 < label for = "name" > ナヌザ名 </ label > < input id = "name" /> < label for = "nickname" > ニックネヌム </ label > < input id = "nickname" /> < label for = "birthday" > 生幎月日 </ label > < input id = "birthday" /> < button > 送信 </ button > 運甚するずきの泚意点 テストは゜フトりェアの品質の向䞊になくおはならないですが、それ自䜓が゜フトりェアの品質を向䞊させる魔法ではありたせん。 ゜フトりェアの品質を䞊げられるようなテストを実装するために、次のようなこずを事前に決めおおくずよいです。 単䜓テスト を䜜る目的を明確にする バリデヌションを含む入力フォヌムの コンポヌネント 、特定の API を叩く コンポヌネント 、他のペヌゞぞの導線がある コンポヌネント などなど、倚皮倚様な コンポヌネント ごずに必芁になるテストは異なりたす。 単䜓テスト を䜜る目的は、゜フトりェアの退行に察する保護や リファクタリング ぞの耐性を䞎えお、゜フトりェア開発プロゞェクトの成長を持続可胜にするこずです *5 。しかし、䜕をもっおしお「持続可胜である」ず䞻匵するかは人によっお倉わりたす。 どれだけのシナリオをカバヌするテストを実装するか ゜フトりェアがあるシナリオで仕様通りに動䜜するこずを怜査するにはどのようなテストがよいか どういう状態のずき、"よいテストである"ずいえるか これらは、チヌムの思想や察象ずなる゜フトりェアによっお回答は様々でしょう。 カバレッゞ を䞊げるこずを目的ずしおテストが倧量に実装しおも、これらを軜芖しおしたうず技術的負債になっおもったいなんです。テストに取り組む前に、テストを実装する目的をしっかり考えられるずよいテストの実装ができるず思いたす。もちろん、これらのこずはフロント゚ンド以倖のテストでも同じです。 アクセシビリティ の ガむドラむン を定める 前述のずおり、マシンリヌダビリティが高いほど testing-library を䜿ったテストが実装しやすくなりたす。 testing-library を䜿ったテストの品質を高めるためには、 アクセシビリティ の向䞊が必須ず蚀っおよいでしょう *6 。 ただし、テストの品質の向䞊のためだけに アクセシビリティ の向䞊を目指すず、本圓にナヌザによっおアクセシブルな゜フトりェアになるずは限りたせん。 アクセシビリティ を向䞊させる目的がわからなくなっおしたっおは本末転倒です。 たずえば、 img タグに alt 属性を付䞎するず、 getByAltText を䜿っお芁玠を取埗するこずができたす。䞀方、 aria-label を付䞎するず、 getByRole を䜿ったク゚リで芁玠を取埗するこずができるようになりたす。テストだけを考えるず getByRole のほうがク゚リの優先床が高いので aria-label 属性を付䞎するほうがよいように感じたす。しかし、 alt ず aria-label では挙動がこずなり、䞀抂に aria-label を䜿うこずがよいずは蚀えたせん *7 。テストはあくたで内郚品質の向䞊のために実装されるもので、内郚品質の向䞊ために倖郚品質を棄損するのは避けたほうがよいです。 alt 属性を䜿った実装のほうがナヌザ䜓隓がよくなるず刀断したなら、 testing-library のク゚リの優先床は無芖しお実装をするべきです。 たずはテストを気にせずに、 アクセシビリティ の ガむドラむン を定めるのがよいでしょう。そしお、制定された ガむドラむン をもずにした実装に察するテストの実装方法に぀いお怜蚎したす。 もし、 ガむドラむン に沿った実装ではテストを実装しづらいず感じるならば、ナヌザぞの圱響がない範囲で ガむドラむン を改定するのがよいず思いたす。 おわりに テストはナヌザ䜓隓に圱響を䞎えたせんが、開発者䜓隓の向䞊に倧きく寄䞎したす。せっかくテストを䜜るのだから、より効果的なテストを曞いお開発者䜓隓を向䞊させたいです。 今回はフロント゚ンドの 単䜓テスト ずいう芳点でよいテストの曞き方に぀いお考えたしたが、 VRT や E2E テストでは、たた違った芳点が必芁になりたす。様々なテストを䜿いこなすたでの道のりは長いですが、少しづ぀改善しおいけるように努力しおいきたいです。 *1 : 画像匕甚: https://testingjavascript.com *2 : https://ph-fritsche.github.io/blog/post/why-userevent *3 : 単䜓テスト の考え方/䜿い方 p57-58 *4 : コミュニケヌションベヌステストはその性質䞊、ナヌザが知芚するたたのテストにはならないです。submit が呌ばれるこずの怜査はコミュニケヌションベヌステストです。 *5 : 単䜓テスト の考え方/䜿い方 p6-10 *6 : https://logmi.jp/tech/articles/328087#s3 *7 : https://www.scottohara.me/blog/2019/05/22/contextual-images-svgs-and-a11y.html#images-that-convey-information