Timee Product Team Blog

タイミー開発者ブログ

JaSST'24 Tokyoに参加しました

タイミーの矢尻、須貝、razです。

ソフトウェアテストに関する国内最大級のカンファレンス「JaSST (Japan Symposium on Software Testing) ‘24 Tokyo」が2024/03/14、15の2日間にわたって開催されました。

jasst.jp

登壇時の様子

今回は我らがGo AkazawaとYorimitsu Kobayashiも登壇!その応援も兼ねてQAコーチ、エンジニア、スクラムマスターの3名が参加。世界中で開催されるすべての技術系カンファレンスに無制限で参加できる「Kaigi Pass」という制度を利用しました。

productpr.timee.co.jp

本レポートでは、印象に残ったセッションの内容を中心に、2日間の会の様子をお伝えします。

噛みしめるほどに味わい深い「Making Quality Tangible」

今年の1月に入社したばかりの駆け出しQAコーチの矢尻です。

毎年楽しみにしているJaSST Tokyoに今年もオンライン視聴で参加しました。

視聴したすべてのセッションが示唆に富んだ学び多きものでしたが、中でもインパクトの大きかったGojko Adzic 氏による基調講演「Tangible software quality」の感想をお話します。

「Tangible software quality」を直訳すると、「具体的なソフトウェア品質」となります。

このセッションでは直接的にテストできないソフトウェア”品質”をプロダクトに”作り込む”ためのマインドセットやモデルが紹介されました。

セッションの最後に紹介された5つの「Making Quality Tangible(品質を具体化するためのガイドライン)」は、哲学的で難解ですが、噛みしめるほどに味わい深いものでしたので私なりに意訳して感想に代えさせていただきます。

  1. MEASURE PRESENCE, not absence(意訳:不在ではなく存在を測定せよ) 欠陥や問題点ではなく、実現された価値に焦点を当てることの重要性を強調されました。ポジティブな側面や魅力を評価することが、価値や魅力を感じるための鍵であると感じました。
  2. Describe multiple QUALITIES(意訳:複数の質を記述せよ) 内容に忠実な感想ではありませんが、例えば生活の質(QOL)のように健康・経済的安定・教育・職業・家族関係・文化的充足感など様々な指標で構成され、どれか一つが満たされていれば幸福というわけではないということに似ていると感じました。 ソフトウェアも同様に、使うひとが幸せであるための多様な構成要素を要求される水準で満たすことが重要と受け取りました。
  3. Trade-offs are a PRODUCT DECISION(意訳:トレードオフは製品の意思決定の一環である) 誰もがt_wada氏の「質とスピード」を想起したのではと思っています。 もちろん「質とスピード」の間のトレードオフは解決可能と私も思っていますが、ここでは網羅的なテストでリスクをゼロに近づけることではなく、どの品質特性がどの程度重要なのか重み付けをして、重要なものからバランス良くリソースを配分するのが重要と受け取りました。(「要はバランス」ですね)
  4. Shape priorities with a MODEL(意訳:モデルを用いて優先度を形成せよ) 製品の意思決定の一環として生じるトレードオフを判断する基準として勘は通用しません。ここでシンプルで有用なモデルとして「有用性」「差別化」「飽和点」から成るQUPER Modelと「マズローの5段階欲求モデル」が紹介されていました。

    QUPER model for better requirements

    Redefining software quality

  5. VISUALISE and ACT(視覚化して行動せよ) もうこれは字面通り「収集したメトリクスを根拠に行動せよ」ということかと思います。 (そういえば最近「見える化」って聞かなくなりましたね)

まさにタイミーでも価値あるソフトウェアを最速でデリバリーするためにチームトポロジー型の組織戦略を採用しています。価値に着目している点で同じ方向性のセッションだと感じましたので、今回紹介されたモデルやメトリクスは折に触れてチームで紹介し試していけたらと考えています。

異業種の品質保証から得られた学び

自動テストが好きなバックエンドエンジニアの須貝です。

JaSSTは初参加(オンライン視聴)でして、弊社の赤澤と小林の登壇を応援しようというのがきっかけでした。

全体を通して一番印象に残ったのはトヨタ自動車の長尾洋平氏による「自動車のソフトウェア品質に関する現場の試行錯誤」です。

自動車を制御するソフトウェアは数千万から数億行のコードからなっており、まずその規模と複雑さに驚きました。また、テストコードの品質にも規格があり、その質を担保するためにミューテーション分析などを活用しているそうです。

一方で実機テストの制約の多さに苦労されているとのことでこれは自動車ならではの悩みだなと思いました。テストのアプローチとしてQAが要件定義段階から関与するいわゆるシフトレフトを実践されている点も非常に興味深かったです。

また他のセッションですと「音楽の世界から学ぶ、ソフトウェア品質」は、プロ演奏者を招いて音楽とソフトウェアという無形のプロダクトの質について探る野心的な試みでした。

私はソフトウェアエンジニアという立場ですが、日々の開発では自身でもテストを行っているため、大変学びの多いイベントでした。

「アジャイル」「スクラム」が多く出てきたことに驚き

QAやテスト界隈がどんな感じなのか気になったので参加しましたスクラムマスターのrazです。

私もJaSSTに初参加(オンライン)でした。正直なところ、社内で参加希望者を募るまで、存在も知らなかったのですが、参加できてよかったです。

私も印象に残ったのは、トヨタ自動車の長尾洋平氏による「自動車のソフトウェア品質に関する現場の試行錯誤」なのですが、須貝さんが感想を書いてくださってるので割愛しておきます笑。

色々な発表を見させていただきましたが、全体的な感想として「アジャイル」や「スクラム」といったキーワードがたくさん出ていたのが驚きでした。ソフトウェアエンジニアがアジャイルなプロダクト開発に変化していった中で、QA組織やQAエンジニアがその変化へ適応していこうとしているように感じました。

その中でも「品質」について「誰のなんのための品質なのか」を考えているのが、とても良かったです。発表の中には「本当にその考えでいいのか?」という議論の余地はあったかもしれませんが、顧客中心に品質を議論する活動、それを継続するのは素晴らしいことだと思います。

弊社でも「顧客のための品質」について、もっと考えていければと思います。

おわりに

弊社は今回ゴールドスポンサーとして初めてJaSST Tokyoに協賛させていただきました。次回以降もなんらかの形で貢献して一緒にコミュニティを盛り上げていければと思います。

また、弊社ではQA、SETの採用も積極的に行っております。

hrmos.co

hrmos.co

タイミーのQA、ソフトウェアテストについてもっと知りたいという方はぜひカジュアル面談でお話しましょう。

product-recruit.timee.co.jp

dbt exposureによるデータ基盤アウトプットの登録を自動化しました

はじめに

こんにちは。okodooonです!!
データ基盤を参照したアウトプットが社内に溢れかえっていませんか?
弊社は追いきれていないLookerStudioやConnectedSheetがめちゃくちゃ溢れかえっていました。
そんな折、yoshidaさんの以下の記事を拝読いたしまして、今回の実装に至った次第でございます。

LookerStudioの記事 ConnectedSheetの記事
www.yasuhisay.info www.yasuhisay.info

面識ないですがこの場を以て感謝の意を表させていただきます!ありがとうございます!

課題感・背景

使用しているBIツールについて

弊社ではBIツールを数種類利用して、BigQueryデータ基盤上のデータを活用しています。
以下がその一覧とざっくりとした役割です。

  • Looker: 社内の主要な分析プロセスをカバーするセマンティックレイヤーを提供
  • LookerStudio: アドホックなレポーティング、Lookerでカバーしきれていない指標を用いたダッシュボード構築
  • GoogleスプレッドシートのConnectedSheet: スプレッドシート上でビジネスメンバーが作業する際のデータソースとしての使われ方
  • Redash: 元々LookerStudio同様の使われ方をしていた。ガバナンス向上とSSoT実現のために廃止作業中

Looker経由のアウトプットであれば、ソースデータに変更が発生したり社内の指標出力ロジックに修正が発生した場合に、ディメンショナルモデリング層で吸収したりLookerのContentValidator機能などでガバナンスを効かせることができます。
しかしBIツール側に直接クエリを書く形となるLookerStudioとConnectedSheetを用いたアウトプットの保守とガバナンスが問題となっていました。

BIツールの使用ボリューム感について

こんな感じのクエリで調査しています。

SELECT
    DISTINCT
    JSON_VALUE(protopayload_auditlog.metadataJson, "$.firstPartyAppMetadata.sheetsMetadata.docId") AS sheet_id,
FROM
    `example-project.bq_usage_logs.cloudaudit_googleapis_com_data_access_*`
WHERE
    protopayload_auditlog.serviceName = "bigquery.googleapis.com"
    AND JSON_VALUE(protopayload_auditlog.metadataJson, "$.firstPartyAppMetadata.sheetsMetadata.docId") IS NOT NULL
SELECT
  DISTINCT
  label.value AS report_id,
FROM `example-project`.`region-xx`.`INFORMATION_SCHEMA.JOBS_BY_ORGANIZATION`,
UNNEST(labels) AS label,
WHERE label.key = "looker_studio_report_id"
  • 過去半年にクエリが走ったConnectedSheetの数: 600個強
  • 過去半年にクエリが走ったLookerStudioの数: 400個強

前述したロジックやソースシステム側の破壊的な変更への対応工数の観点以外にも、もう使われていないConnectedSheetに配信し続けている可能性などが考えられるため、まずはアウトプットを管理できる体制が必要であると考えました。

やったこと:概要

以下のような処理の流れを構築しました。

  • exposure登録情報を出力するviewをdbtで構成
  • 以下の処理をweeklyで実行
    • viewの結果を取得してexposureのyaml形式に変換
    • アウトプット単位でexposureのyamlファイルを作成
    • 未登録と変更があったexposureを登録するpull requestを作成

参考にしたブログから、弊社の運用に合わせて変更した点は以下です。

  • exposure単位でyamlファイルを作成する方針に変更しました
  • referenced tableにテーブル名ではなくdbtモデル名が入るようにしました
  • 各種アウトプットの公開設定をmeta情報として付与する方針としました
  • tagを追加してexposureの検索性を向上させました
  • exposureのnameにシートとダッシュボードのタイトルを反映する方針にしました

今回の実装によって以下のような形式のexposure用のyamlファイルが自動生成されます。

version: 2
exposures:
- name: {{ConnectedSheetタイトル}}_{{ConnectedSheetId}}
  label: {{ConnectedSheetId}}
  type: dashboard
  tags:
  - shared_externally
  - spreadsheet
  url: https://docs.google.com/spreadsheets/d/{{ConnectedSheetId}}
  owner:
    name: test@example.com
    email: test@example.com
  depends_on:
  - ref('hogehoge_model')
  - ref('foo_bar_model')
  - ref('chomechome_model')
  meta:
    visibility: shared_externally

やったこと:詳細

説明があるとわかりやすそうな部分の詳細を記載していきたいと思います。

referenced tableにテーブル名ではなくdbtモデル名が入るようにしたことについて

弊社はdbtモデル名とBigQuery上のテーブル名が一致しないため、INFORMATION_SCHEMAやaudit_logから取得したテーブル名をref関数化してもリネージュを作成できません。

そのため、dbtモデル名とBigQuery上の対応関係を取得するためにdbt-elementary実行時に生成されるdbt_modelsテーブルを活用しました。
このテーブルは

カラム名 内容
dbt_models.name dbtモデル名
dbt_models.alias BQテーブル名
dbt_models.schema_name BQデータセット名
dbt_models.database_name BQプロジェクト名

このような情報を持つカラム群を保持しています。
このテーブルを活用することでINFORMATION_SCHEMAが保持するBQテーブル名をdbtモデル名に変換してref指定することができています。

各種アウトプットの公開設定をmeta情報として付与する方針としたことについて

https://support.google.com/a/answer/9079364?hl=ja

google workspaceのactivityログを使うことで、LookerStudio,SpreadSheetの公開設定とタイトルを取得することができるので、それらを取得しています。

SELECT
    data_studio.asset_id AS report_id,
    data_studio.asset_name AS report_name,
    data_studio.visibility AS visibility
FROM example-project.google_workspace.activity
WHERE activity.data_studio.asset_type = 'REPORT' AND activity.event_name = 'VIEW'
SELECT 
    drive.doc_title AS sheet_title,
    drive.doc_id AS sheet_id,
    drive.visibility
FROM `example-project.google_workspace.activity` 
WHERE drive.doc_type = 'spreadsheet'

tagを追加してexposureの検索性を向上させたこと

dbt exposureはmeta, owner, typeなどの情報を使って、dbt lsコマンドなどでアウトプットを一覧することができません
dbt ls --resource-type exposure --type dashboard --owner example@example.com
みたいなことがしたいのですができないです。

そのため、exposureに対して適切なtagを付与することで絞り込みができるようにしました!

今回は公開設定,アウトプット種別の二つをtagとして持たせました。
これによって
「xxx_modelを参照しているshared_externally設定にしているスプレッドシート一覧を出したい」という要望に対して
dbt ls --select xxx_model+,tag:shared_externally,tag:spreadsheet --resource-type exposure
このようなコマンドで出力ができるようになります

exposureのnameにシートとダッシュボードのタイトルを反映する方針にしたこと

Add Exposures to your DAG | dbt Developer Hub

こちら公式Docにexposureのnameに指定するのはスネークケースにしてくださいという記載がありますが、なんとスネークケースにしなくても日本語名でも通ります!(名前をユニークにする必要はあります)
そしてexposure.nameがリネージュ上で表示される名前なので、データリネージュの可視性を高めるためにLookerStudioとコネクテッドシートのタイトルをnameに含む形で設定している状態です。

LookerStudioID, SpreadSheetIDだけをnameにすると、このようにデータリネージュ上でどのアウトプットのexposureかぱっと見判断がつかないのですが {{タイトル}}_{{ID}}の形式にすることでデータリネージュ上の可視性を確保した形です。

今後の発展

保守運用の設計

アウトプットが全件自動で管理されるようにはなったことで、「ソースシステムに影響が起きた場合」や「算出ロジックに変更が生じた場合」の影響範囲は迅速に把握できるようになりました。

しかし使われていないことがわかったアウトプットに対してどのようにアクションしていくのか、フローが組めていない状態です。
管理ができるようになった上でどのように運用改善に繋げるのか。どのように削除やdeprecatedにしていくのか。あたりのフローはしっかりと組んで、ユーザーの目に触れるアウトプットの品質の最大化に努めていきたいです。

カラムレベルリネージュ ✖️ exposure

dbt cloud enterpriseではカラムレベルのリネージュがexplore上で確認できるようになりました。
docs.getdbt.com 重要なアウトプットはBIツール側にクエリを書くのでなく、dbt側にそのアウトプット専用のマートを作成することで、カラムレベルでの影響範囲調査が可能となるのではと考えています。

before after

この図でいうbeforeからafterの構成に変えることでマートまではdbtで管理されるようになるため、dbt exploreのcolumn level lineageで可視化することで、カラムレベルでのアウトプットへの影響範囲を確認可能です。
こうすることで、「このテーブルに何かしら変更を加えたら最大でどのくらいの数のアウトプットに影響があるんだろう」から「このテーブルのこのカラムを消したらどのアウトプットに影響があるんだろう」まで影響調査の解像度を上げることができます。

こういった理由から、アウトプット専用マート作成の取り組みを始められたらなと思っております。
(column level lineageは現状dbt exploreで見ることができるだけですが、もうちょっと使いやすくなって欲しいです)

おわりに

yoshidaさんの記事を参考に少しだけカスタマイズしただけで、課題となっていたアウトプット管理の問題を解決することができました!
運用面などまだまだ磨き込んでいきたい部分は多分にありますが、この実装を通して社内ユーザーのデータ活用体験の最大化に繋げていきたいです!

アウトプットがいっぱい登録されました。(オレンジ色がexposure)

We're Hiring!!

タイミーではデータ基盤を一緒に開発してくれる仲間を募集しています!
お力をお貸しいただける方いらっしゃいましたらご応募お待ちしております!

データエンジニア hrmos.co

アナリティクスエンジニア hrmos.co

タイミーでデータアナリストとして働いた1年を振り返る

こんにちは!タイミーのデータアナリストの@yuyaです。

2020年にスマホゲームを運用する企業へ新卒入社をし、イベントプランナー兼データアナリストとして活動。2社目にECサイトを運用する企業でデータアナリストとして従事した後、2023年3月に3社目となるタイミーへ入社しました。入社からちょうど1年が経ったので、タイミーでのデータアナリストとしての働き方をこれまで自分が所属した企業と比較して、どうだったかについて振り返りたいと思います。

タイミーでの役割

まずは、私がタイミーでどのような役割を担っているデータアナリストなのかを記載したいと思います。

タイミーのデータアナリストチームは、大きく以下の3つの役割に分かれております。

  • プロダクトアナリティクス:プロダクトの機能開発に関わる分析
  • マーケティングアナリティクス:マーケティングに関わる分析
  • ビジネスアナリティクス:経営・事業活動に関わる分析

私は、ビジネスアナリティクスに所属しており、営業周りのデータ分析や店舗周りのデータ分析を主に行っております。

タイミーでの1年を振り返る

オンボーディング期

入社直後のオンボーディング期は、社内のデータ構造を理解しながら、データ抽出を行う依頼をこなしておりました。

タイミーでは、前述した3領域に関わらず、全社的にデータ抽出や簡単な分析をデータアナリストに依頼できるフローが存在しており、そこの依頼を担当することで、アプリ関連のデータ、マーケティング関連のデータ、営業関連のデータなど、タイミー内に存在する様々なデータ構造を理解し、使いこなせるようになるよう努めていました。

個人的に、これまで営業が存在する企業に所属したことがなかったため、営業関連のデータに触れることが新鮮で、分析領域としても1つ広がっていく感覚があり、非常に面白みを感じていました。

また、多くのデータが分析しやすいように整備されており、クエリを書くのが楽だったのも印象的でした。

ビジネスアナリティクス領域に配属

オンボーディング期が終わると、ビジネスアナリティクス領域に配属となりました。

私が配属された直後は、すでに社内での連携部署が定まっており、連携部署との間で分析テーマを決めて分析に取り組んでおりました。

当初取り組んでいたテーマとしては、「店舗の流入経路別のLTVの分析」や「新規導入に至るまでのファネル分析」、「CPの効果検証」などのように、課題の特定や戦略に関わる部分の分析から施策の効果検証まで幅広く様々な分析を行っておりました。

初めて営業関連の分析に着手する中で一番苦戦したのが、「どのデータが使えるのか?」を明確にするところでした。

前職と前々職では、アプリやマーケティングのデータを分析しており、基本的に自動でデータ収集されている状況でした。しかし、営業関連のデータは、営業の方が手動でデータを入力しないといけないため、たとえデータとしてカラムが存在していたとしても、データを入力している人としていない人が存在していたり、チームによって若干運用方法が違っていたりしていたため、現場への確認が必要でした。

今あるデータからどんなインパクトが出せそうかを考えるのも大事ですが、そもそもどのようなデータをきちんと収集していくと良さそうなのか、それをどうやったらきちんと収集できるようになるのかを考えていくのも重要そうだなという気づきを得ました。

営業組織が変革し、連携部署を再検討する

ビジネスアナリティクス配属から約半年後、営業組織が変革されるイベントが発生しました。

これを機に、改めて「データアナリストとして、どのような動き方をすると価値を最大限発揮できるのか?」を考えていくことになります。

こちらについて、まだ明確な結論は出ていないものの、現状の営業組織の解像度を上げる(どこでどのような人が関わり、どのように意思決定が行われ、どのように影響していくのかなどを明確にする)ことで、データアナリストとしてインパクトを与えていける動きができそうかの仮説を一定立てられるところまでは来たかなと思っております。

これまで所属していた企業(チーム)が、20名程度と100名程度であったため、特に意識しなくてもどこで誰が何をしているか理解できていたのですが、タイミーのように組織も急成長を遂げ、規模も1,000人を超えてくるような大きな組織になってくると、きちんと現場の状況をキャッチアップしにいく動きをすることが重要なのだなと改めて気付かされました。

最後に

これまで、時系列的にどのようなことを行っていたのかを簡単に紹介してきました。

タイミーは、現在サービスも組織も急成長中であり、環境が目まぐるしく変わっていっており、都度都度その変化に適応していく必要があります。そのため、チームとしても明確な型のようなものが存在しているわけではなく、常に「どのように動くことが一番インパクトが出せるのか?」を考え、状況に合わせて柔軟に動き方を変えていく必要があるなと感じています。

これまで所属した企業では、良くも悪くも、データアナリストとしての動き方がすでに固まっており、教えられた動き方をするだけで、自然とインパクトも出せるような環境でした。そのため、組織として自分がどのように振る舞うことが一番インパクトが出せるのかを考える機会があまりありませんでしたが、タイミーでは、日々そのようなことを考えるため、視野を広げる良い機会になったかなと思っております。

組織が急拡大する中で、カオスなことも多いですが、これまでにない経験から得られる学びや気付きが多く、タイミーに転職して良かったなと感じております。

We’re Hiring!

私たちは、ともに働くメンバーを募集しています!!

カジュアル面談も行っていますので、少しでも興味がありましたら、気軽にご連絡ください。

【イベントレポート】チーム分割においていかれたアラートをチームで責任を持てる形に再設計した

イベント概要

2023年12月5日に「Next Year Con for SRE〜来年の登壇を応援する勉強会〜」と題してSREに関するトピックでタイミー、ココナラ、ビットキー、マジックモーメントの4社合同で勉強会を開催しました。 その中でタイミーバックエンドエンジニアの岡野さん(@Juju_62q)の講演をイベントレポートにまとめてお届けします。

チーム分割においていかれたアラートをチームで責任を持てる形に再設計した

自己紹介&想定聴衆

2020年にタイミーに入社し、現在では3年半ほどエンジニアをしている岡野と申します。 主にストリームアラインドチームの機能開発を担当しており、その一方でサイトリライアビリティエンジニアリングも行っています。

想定聴衆

  • 「よくあるアラート」に困っているエンジニア
  • 組織分割を考えているEMやCTO
  • EnablingをやっていきたいSREs

今日お話しないこと

  • どのようなアラートを設定すべきなのか
  • アラートから繋がるオンコール対応周辺の話

アラートとFBサイクルとチーム

私が最も優れていると考えるアラート(右の図)は、問題が発生したら、エンジニアが問題を解決すると宣言し、リカバーするアラートです。理想的には、問題が自動的に解決することが望ましいですが、今回の話の範囲では、アラートの責務を超えていると捉え、理想的なアラートの形をこのように考えています。

次によくあるアラート(左の図)は、CPU使用率がN%を超えると、エンジニアが介入せずとも時間と共に回復したり、500エラーがy回を超えると何もせずとも回復するようなアラートです。このようなアラートは、時間が経過すると自然に解決し、次第に無視されがちです。

本来アラートはアクションを要求するための通知であるべきであり、アクションなしにアラートが鳴ることは無意味です。実際にタイミーにも、このような無駄なアラートが長期間存在していました。

現状、完全な解決には至っていませんが、タイミーがアラートを少しずつ改善した話を共有していきます。

タイミーではどのようにして「よくあるアラート」ができたのか

前提条件
1. 開発と運用を同じチームでやっていること
タイミーでは、CTOが開発と運用を一つのチームで行うことを重視しています。CTOが好んでいるチームトポロジーの書籍では、「運用は開発への最大のフィードバック源である」と述べられており、私たちの組織でもこれを大切にしています。

2. エンジニアはアラートがなっていることを好ましく思っていないこと
エンジニアはアラートが鳴る状況を好ましく思っていません。行動を起こすかどうかは別として、アラートが鳴っていること自体は好まれていませんでした。

3. エンジニアは機能開発以外にある程度の時間が使えること
タイミーのエンジニアは、10%から20%の時間を技術改善に充てることができます。実際には、少なくとも10%の時間をこれに割り当てることが求められています。

2〜3年前、我々のチームは以下のような横割りの構造でした。

  • バックエンドチーム
  • Webフロントエンドチーム
  • モバイルチーム

これらのチーム間では、バックエンドチームがアラートの設定を行い、障害経験を基にアラートシステムが構築されました。この時期には、ユーザー数も少なく、アラート対応の難易度も低めでした。赤く表示されるアラートに対しては、チーム文化として積極的に対応していました。

しかし、この横割り組織では、一つのチームだけで機能を完全に提供することが難しく、これが課題となりました。そのため、職能を横断する縦割りの組織構造への移行を進めました。この新しい形では、モバイルやWebフロントエンドなど、異なる専門分野のメンバーが同一チームに所属するようになりました。

ただし、この組織変更の際に、アラートシステムの見直しは行われず、バックエンドエンジニアが引き続きアラートの責任を担うことになりました。

アラートが鳴った際の反応はどうだったかというと、以下のような反応が一般的でした。

Aチーム「アラート鳴ってるけど、よくわからんな」 Bチーム「アラート鳴ってるけど、うちのチームとは関係無さそう」

チーム間で分断されていると、特定の機能についてどのチームが対応すべきかの判断が難しくなります。特に、人員が増加するにつれて、過去の経緯も失われ、このような問題は増えていきます。

いつも鳴ってるし今日も大丈夫だろう

『いつも鳴ってるし、今日も大丈夫だろう』という感覚が常態化すると、アラートが頻繁に鳴るようになります。アラートが放置され、対応が行われないため、アラートの数は増加の一途をたどります。

改善したいけどハードルが高そう

仮に意欲的なエンジニアが現れても、「何とかしたいが、どう変えればいいかわからない」という状況に陥りがちです。Aチームの同僚は協力的ですが、Bチームは相対的に距離があるため、意見を述べるのが難しいと感じることがあります。同じ会社に属していても、日常的に顔を合わせていない人に対し、合意を得る必要があるかもしれないという懸念が生じます。

なぜこのようなことが起こるのか

なぜこのような状況が発生したのか、その原因を考察します。

アラートの作成は元々、バックエンドチームが責任を持って設定していました。当初、アラートに対するフィードバックはバックエンドチームに集中しており、このチームだけでアラートの削除や修正が行われていました。しかし縦割り組織への移行後、アラートに関するフィードバックは複数のチームに分散し、単一のチームだけでの削除や修正が難しくなりました。アラートに対する対応が不明確になり、長期間勤務している経験豊富なメンバーに相談することや、アラートに関する変更の承認を得るまでのプロセスが必要になることもありました。このように、フィードバックが機能しなくなった結果、アラートの数は増加し、特に新入社員にとっては理解しづらいものとなりました。この状況が、「よくあるアラート」の誕生に繋がったのです。

「よくあるアラート」を改善するためにしたこと

結論を述べると Aチーム・Bチームそれぞれにフィードバックと意思決定権を与えました。

具体的な行動

  • 各チームで対応の必要があると思われるアラートを選んでもらう
  • アラートに対してチームメンションをつける
  • アラートはメンションのある単一チームで変更していいと周知する
  • アラート対応に関する振り返りを実施

各チームで対応の必要があると思われるアラートを選んでもらう

すべての問題を即座に解決するのは難しいため、Slackに「問題なし」または「問題あり、オンコール対応が必要」というコメントを残すことを最低限行うことにしました。このとき、多くのアラートのうち、選ばれなかったアラートは一旦すべて削除しました。

アラートに対してチームメンションをつける

次に、アラートに対してチームメンションをつけることにしました。以前はアラートにメンションがなく、全てのチャンネル通知をオンにする運用でしたが、これではどのチームが対応すべきか不明確でした。そこで、アラートにメンションを付与し、「このメンションのチームがオーナーです」と伝えるようにしました。

メンションのある単一チームで変更していいと周知する

次に、バックエンドのアラートに関しては、バックエンドチーム全体の許可がなければ変更できないと考えられていました。しかし、メンションのある単一チームでの意思決定による変更を推進しました。これにより、各チームは素早く意見を反映できるようになりました。

アラート対応に関する振り返りを実施

最後に、アラート対応に関する振り返りを実施しました。最初の改善はできるだけサポートするため、メンション付きのアラート対応について1ヶ月後に第1回の振り返りを各チームで行いました。これは、必要に応じて2回、3回と続けました。この流れで、チーム内での改善が少なくとも1回行われるところまで改善できました。

今、どのような変化があったのか

現在、アラートシステムにおいて以下のような変化が生じています。

アラートに反応する人やチームの増加

アラートに反応する人数やチームが明確に増えました。

アラートの定期的な変更や見直し

アラートに対応しないと自分たちが困難な状況に陥るため、変更や見直しを定期的に行うようになりました。

Runbookの整備

チームごとにRunbookが整備され、アラート対応のプロセスが民主化されています。この分野にはまだ改善の余地があると感じていますが、良い変化が見られていると思います。

これらの変化により、「よくあるアラート」から徐々に脱出していると感じています。ただし、不要なアラートが多いことや、復旧の自動化がまだ十分ではないことは、今後の大きな改善ポイントです。

まとめ

  • アラートは組織構造とFBを受ける人が不一致の場合に機能しなくなっていく
  • アラートは単一チームで変更の意思決定ができないと硬直化する
  • 組織が変わった際に、アラートの組織に合わせて変更するのが大切

最後に、アラートシステムのまとめです。アラートは、チームの構造とフィードバックが不一致になると、効果を失ってしまう可能性があります。フィードバックを受ける人々が明確でない場合、アラートの機能性が低下する傾向があります。またアラートに関しては、「単純接触効果」のとおり、日常的に顔を合わせる人々に対して意見を伝えやすいことが多いです。そのため、単一のチームで意思決定ができない場合、アラートシステムは硬直化しやすいと思われます。

結論、組織が変化した際には、アラートシステムの構造も組織の形態に合わせて変更することが重要です。

その他の方の発表も気になる方はこちら!

www.youtube.com

少しでも興味を持っていただいた方は是非こちらからカジュアルにお話しましょう!

devenable.timee.co.jp

【イベントレポート】YAPC::Hiroshima 2024に参加しました

はじめに

こんにちは、タイミーでバックエンドエンジニアをしている新谷須貝難波です。

2月10日に広島国際会議場YAPC::Hiroshima 2024 が開催されました。タイミーはGold Sponsorとしてブース出展をしており、エンジニアが3名とDevEnable室が3名の総勢6名で参加させていただきました。

どのセッションも興味深かったのですが、この記事では我々が拝見したセッションのうち特に印象に残ったものをいくつかピックアップしてご紹介します。

なお、タイミーには世界中で開催されている全ての技術カンファレンスに無制限で参加できる「Kaigi Pass」という制度があり、エンジニアはこれを使って参加しております。詳しくは下記のリンクをご覧ください。

productpr.timee.co.jp

経営・意思・エンジニアリング

speakerdeck.com

普段我々が行なっているソフトウェア開発の延長線上に CTO の仕事があるよ、という発表でした。経営者が物事をどう捉えているのかを垣間見ることができ、個人的にはベストトークでした。

ソフトウェア設計と組織設計が相似的なアーキテクチャであるということはコンウェイの法則などもあることから直感的に理解できましたが、事業設計とも相似的なアーキテクチャであるという話はまだピンときていないのでまたどこかのタイミングでお伺いしたいと思っています。

また、意思が重要という話はプロジェクトを成功するためには強い意思を持つ推進者が必要不可欠という点で共感していました。ただ、プロジェクトが短期間で終わるものであれば良いのですが、ある程度期間のかかる類のものは個人の意思では難しいこともあるかと思っていて、そういったものはどう対処しているんだろうとも気になりました。

短期的成果の重力に負けないよう、これからのプロダクト開発を行なっていきたいと思います。

(新谷)

関数型プログラミングと型システムのメンタルモデル

speakerdeck.com

コンピュータアーキテクチャに近い手続き型プログラミングから関数型プログラミングへメンタルモデルを変えていこう、という発表でした。私は普段 Ruby on Rails でアプリケーション開発をしていて関数型プログラミングとは距離があるのでとても興味深く聞かせていただきました。

オニオンアーキテクチャは DI ができるとかモックが可能とかが重要なのではなく、手続き型言語の考えに引き摺られがちな I/O の部分を業務ロジックから切り離し、業務ロジックに対して別のパラダイムを適用できるようにするのが本質という話を聞き、なるほどと勉強になりました。

一方、関数型プログラミングが Web アプリケーションのバックエンドに本当に適用できるのかはまだイメージが湧いていないのが正直なところではあります。質疑応答で質問をさせていただいて RDB の書き込みに相当する I/O の部分は Repository 層に閉じ込めるという話は納得したのですが、Web アプリケーションは本質的に並行処理だと思っていて、リクエストを処理している最中に状態が書き換わることをどうやって純粋な関数で表現するのかが気になっています。

懇親会で確定申告の話と一緒に質問しようと思っていたのですが残念でした…

(新谷)

変更容易性と理解容易性を支える自動テスト

speakerdeck.com

自動テストの目的は

信頼性の高い実行結果に
短い時間で到達する状態を保つことで、
開発者に根拠ある自信を与え、
ソフトウェアの成長を持続可能にすること

という結論からスタートし、その結論に向かって一つずつ解説していく内容でした。

この目的は極限まで削れば「ソフトウェアの成長を持続可能にすること」だと私は思います。これだけだと飛躍があるので一つずつ順を追っていくと、まずソフトウェアの持続可能な成長には変更容易性(変更しやすい)と理解容易性(わかりやすい)が必要です(ないとツラい)。そして変更による既存機能への影響を知る手段のひとつに自動テストがあります。また、自動テストには既存コードの理解を助ける役割もあります。もちろんただ自動テストがあればよいわけではなく、良い自動テストが必要です。

ではどうすれば良い自動テストを書けるのかという話になるわけですが、ここで私が思い出したのは「単体テストの考え方/使い方」(Vladimir Khorikov 著、須田智之 訳)です。

この本の「4.1 良い単体テストを構成する4本の柱」で以下の4つの要素が挙げられています。

  • 退行(regression)に対する保護
  • リファクタリングへの耐性
  • 迅速なフィードバック
  • 保守のしやすさ

目的で挙げられた「信頼性の高さ」は「退行に対する保護」(偽陰性からプロダクション・コードを守るもの)と「リファクタリングへの耐性」(偽陽性の数を最小限に抑えるもの)であり、「短い時間で到達する状態」は「迅速なフィードバック」に相当します。そして「信頼性の高い実行結果に短い時間で到達する状態を保つ」ためには「保守のしやすさ」が欠かせません。つまり冒頭の二行に良いテストの条件がすべて凝縮されていたのです。

発表にあった「実行結果は情報」という指摘には良いフィードバックの重要性も感じました。また、Googleのテストサイズの話なども非常に勉強になりました。今回のセッションをきっかけに改めて自動テストの目的に立ち返り、自分たちがより根拠のある自信を持ってコードを書けるようにしていきたいと強く感じています。

最後に余談ですが、発表の中で気になったことを懇親会でtwadaさんご本人に直接質問できたのはオフラインイベントの醍醐味だなとしみじみ感じました。

(須貝)

非同期な開発体制を支えるドキュメント文化

speakerdeck.com

時差のあるメンバー同士でも適切にコミュニケーションを行うために Launchable, inc.で実際に行われているドキュメンテーションの事例を紹介頂く内容でした。

発表の中で特に印象に残ったものを3つほど挙げさせていただきます。

  • フィードバックの平等性
  • 検索性の意識
  • ドキュメントの型化

まず「フィードバックの平等性」についてです。組織にいるメンバーは多様であり聞いた話について素早く考えて話すことが得意な人もいればじっくり考えたい人もいます。また組織内公用語として使われている言語が第一言語でない人もいます。そういった場合に同期的なMTGでやり取りすると議題に対するフィードバックを行う人が偏る傾向があり、またフィードバックの観点も偏りがちです。非同期にフィードバックをもらうようにすることでこの課題の対策としているというのは良い視点だと思いました。なお、タイミーでも参加者が多い一部のMTGでは議事録のドキュメントにフィードバックの欄があり、またMTGの録画を行うことで非同期にフィードバックを行いやすい運用をしていたりします。

次に「検索性の意識」についてです。ドキュメントをしっかり残すことは非同期か否かに関わらず非常に良い文化であり実践している組織も多いと思いますが、ドキュメントが増えると必然的に起きるのが検索性の悪化です。タイミーではドキュメンテーションにNotionを使用しているのですが、閲覧したいドキュメントがなかなか見つからなかったり、見つかったドキュメントが実は古いものだったといったことはどうしても発生します。その対策としてまず部門ごとにConfluenceのspaceを分けているとのことでした。他部門の情報が簡単に閲覧できるという透明性は重要ではあるものの、それは権限管理をしっかりやれば解決できることです。また積極的にアーカイブ(≠ 削除)を行うことでデフォルトの検索設定では検索にヒットしないようにするという話もあり、これはその通りだと思う一方でそれを組織文化とするのは一朝一夕では無いなと感じます。

最後に「ドキュメントの型化」についてです。ドキュメントが一定のフォーマットに準じて作られていれば書き手にとっては書くべき情報が漏れにくいですし、読み手にとっても慣れれば慣れるほど要点を理解しやすくなります。また適切なフィードバックを受けるための30/60/90% framework for feedbackについても勉強になりました。これはドキュメントのフェーズに対して適切なフィードバックを行おうというもので、普段から意識してはいたもののそういった名前が付いていたことは知らなかったので今後のコミュニケーションの際に使おうと思います。そして関連資料のドキュメントへの記載です。ドキュメントを書く際は何かしら参考にした別のドキュメントというものがある場合が多いですし、書き手にとっては自明でも読み手にとってはそうでない場合も多いです。こういった資料のリンクを書き手だけでなく、読み手も積極的にドキュメントに残していこうというのは今後より意識していきたいです。

(難波)

杜甫々さんのキーノート

あの日あの場にいたことを自慢し続けようと思います。

(須貝)

おわりに

YAPCは長く続いているイベントですが、今回エンジニアで参加したメンバーは初参加だったり9年ぶりの参加という感じでした。それでもYAPCの和やかな雰囲気とPerlに関係するテーマもそうでないものも受け入れている包容力で皆大変楽しむことができ、また勉強になったカンファレンスでした。

来年以降もまたスポンサーや参加ができればと思います。

最後にランチとして配られた広島名物のあなごめしの画像を貼って終わりとします。

【イベントレポート】Railsアプリで秘匿情報を環境変数からCredentialsに移行した話

イベント概要

2023年11月15日に「GENBA #1 〜RubyRails開発の現場〜」と題してRuby/Railsでの開発に関するトピックでタイミーとエンペイ社合同で勉強会を開催しました。 その中でタイミーバックエンドエンジニアのpokohideさん(@pokohide)の発表「Railsアプリで秘匿情報を環境変数からCredentialsに移行した話」をイベントレポート形式でお届けします。

登壇者紹介

Credentialsとは

Credentials は、Rails 5.2から追加された秘匿情報を管理するための仕組み※1 で、Rails 6から複数の環境をサポート※2 しています。

【主な登場人物】

  • 暗号化ファイル: config/credentials/.yml.enc
  • 復号用の伴: ENV[”RAILS_MASTER_KEY”] or config/credentials/.key

【セキュアな構成管理】

  • Railsアプリ起動時に Rails.env に対応する暗号化ファイルと鍵を参照し復号する
  • 復号化が完了すると Rails.application.credentials 経由で取得可能になる

【暗号化と参照方法】

  • YAML形式のファイルを暗号化(YAMLの構文に依存) ⇆ 復号
  • 復号化された後は ActiveSupport::OrderedOptions を介してアクセス可能
  • fetchdig が使える


▲Credentialsの例
※1Add credentials using a generic EncryptedConfiguration class #30067
※2Add support for multi environment credentials. #33521

Credentialsへの移行目的

Credentialsへの移行は、組織内での秘匿情報管理の責任を明確化し、デプロイプロセスを効率化することを目的としています。

  • 手間の削減

以前はECSのタスク定義に環境変数としてパラメータストアのSecureStringを利用していました。秘匿情報を追加する際にパラメータストアに登録し、ECSタスク定義とアプリケーションコードの両方を変更する必要があり、手間がかかっていました。

  • 責任境界の曖昧さ

AWSリソースの管理はインフラチームが主導していましたが、その結果、責任境界が曖昧になることがありました。
⇒ Credentials導入によって、秘匿情報の管理に関する責任の所在が明確になり、責任境界が明確化されました。

  • デプロイの難易度

複数の場所での操作が必要だったため、デプロイが容易ではありませんでした。
⇒ Credentials導入によって、アプリケーションコードを変更することで秘匿情報を追加・参照できるようになるため、デプロイも容易になりました。

  • レビューの困難さ

独自の対話型CLIを使用してパラメータストアを操作していたため、プロセスのレビューが困難でした。

  • セキュリティの向上

⇒ Credentials導入の副産物として、セキュリティ向上が挙げられます。RAILS_MASTER_KEYのみを管理することでパラメータストアの操作権限を削減でき、全体的なセキュリティレベルが向上しました。

Credentialsの安全性

Credentialsの安全性は、主に使用される暗号化アルゴリズムとマスターキーの管理方法に依存します。2023年時点で、AES-256-GCM暗号化アルゴリズムを用いた暗号化は、最も安全だといわれています。
しかし、最も重要なのはマスターキーの管理です。マスターキーが流出すれば、暗号化された情報が容易に解読されてしまう可能性があります。そのため、マスターキーの安全な保管とアクセス管理は非常に重要です。
管理方法については、ビジネスの環境やリスクに応じて慎重に検討し、適切なセキュリティ対策を講じる必要があります。

Credentials 移行の手順

移行の手順は、とてもシンプルです。

  1. 何を移行するか決める
  2. 移行対象の秘匿情報を全てCredentialsに追加する
  3. 少しずつ Rails.application.credentials に移行する

1. 何を移行するか決める

まず、何をCredentialsに移行するかを決定します。アプリケーションの構造を分析し、環境変数をリストアップします。秘匿情報には、環境変数だけでなく、証明書、秘密鍵Google Cloudの認証用JSONキーなどが含まれる可能性があります。
また、秘匿情報が本当にCredentialsへの移行が必要かを考えましょう。環境ごとの固有の設定であれば config_for を使用することで解決できるかも知れません。コンテナ化された環境やデータロックサービスのような動的に注入する必要がある情報や、頻繁に更新される情報は、Credentialsへの移行が適切かどうかを慎重に検討します。

2. 移行対象の秘匿情報を全てCredentialsに追加する

秘匿情報を一括でCredentialsに追加することをおすすめします。その理由は、暗号化ファイルのレビューが難しいためです。Credentialsへの移行前もレビューは難しい状況でしたが、暗号化ファイルを扱う現在も同様です。そのため、秘匿情報をまとめて移行し、Railsコンソールでリリース前に値が正しく一致しているか確認することで、プロセスがよりスムーズになります。

3. 少しずつ Rails.application.credentials に移行する

Rails.application.credentials への移行は段階的に行います。このプロセスは、多くのプルリクの作成と対応を伴い、障害が発生する可能性もあります。実際に起きた一例として、全角スペースと半角スペースを間違えて登録し、参照時にエラーが発生しました。秘匿情報のファイルレビューは通常、Syntax Highlightが効かない素のVimなどで行われるため、特に細心の注意が必要です。

タイミーでは技術改善のために割り当てられる時間が全体の約20%で、この時間を利用してCredentialsへの移行作業を行いました。全体としては約5ヶ月の期間を要しました。もし環境が異なれば、移行にかかる時間は1ヶ月程度に短縮可能かもしれません。移行の過程では、ステージング環境と本番環境で同じ秘匿情報を使用していたこともあり、そのような点にも対応しながら作業を進めました。

Credentials移行時のTips

1. config.require_master_key 設定を有効にする

Railsアプリケーションを起動する際には、Credentialsのマスターキーが必須です。マスターキーがないとアプリの起動に失敗する設定を有効にしておくと良いでしょう。

2. エディタの指定

暗号化ファイルの編集にはエディタの指定が必須なので用意(Dockerを利用している場合はemacsなどでもOK)

3. エスケープ文字の扱い

秘匿情報にエスケープ文字が含まれている場合は、ダブルクォーテーションで囲むことが推奨されます。暗号化ファイルがYAML形式に依存しているため、YAMLの構文規則に従う必要があります。

4. 改行の利用方法

秘匿情報に改行を含めたい場合は、パイプなどのYAMLの構文を利用します。

5. 外部サービスとの認証方法を変更する

外部サービスとの認証方法も変更しました。具体的には、以前は秘匿情報をファイルから読み込んでいた認証方法を、Credentialsで管理する形式に変更しました。

6. バイナリデータの取り扱い

YAML形式はテキストベースのデータ形式であり、バイナリデータの直接的な扱いには向いていません。特に、証明書などのバイナリデータをCredentialsで管理する際は、事前にBase64エンコードする必要があります。アプリケーションでは、このエンコードされたデータを取得し、適切にデコードして使用します。データの識別を容易にするために、YAMLファイル内でエンコードされた値には base64_encoded というプレフィックスを付けると便利です。

7. 秘匿値をコンソールで非表示にする

Railsコンソールを使用する際、デフォルト設定では秘匿値が表示されてしまうことがあります。(Rails 7.1からは、この秘匿値を非表示にする機能が標準で実装されています。)この変更によって、Railsコンソールから秘匿情報が誤って露出するリスクを軽減できます。

8. SECRET_KEY_BASEを Credentials に移行

SecretsはRails 7.1から明示的に非推奨化されたため、SECRET_KEY_BASEを Credentials に移行しました。各環境の credentials.yml に SECRET_KEY_BASE を移行すればOKなはずです。Rails 5.1以前で secrets.yml を使用して秘匿情報を管理していたアプリケーションの場合、移行プロセスは少し複雑になる可能性があります。

9. SECRET_KEY_BASE_DUMMYの活用

Rails 7.1から SECRET_KEY_BASE_DUMMY が導入されました。これは、SECRET_KEY_BASE の代わりにダミー値を自動的に設定する SECRET_KEY_BASE_DUMMY です。assets:precompile 実行時に SECRET_KEY_BASE が必要ない場合でも、エラーが発生することを防げます。

10. Heroku Data for Redis

これはタイミーではなく個人のアプリでの経験ですが、 Herokuで運用、Heroku Data for Redisを利用してる個人アプリのREDIS_URLをCredentialsに移行したらRedisに接続できなくなりました。自分で管理していない環境変数などを移行する場合は注意しましょう。

移行の結果

Credentialsに移行した結果、下記のような成果を実感しています。

ただし、依然としてレビューが大変です。データが暗号化されているため、プルリクエストを出しても差分が分からず、暗号化ファイルのdiffを確認するには公式の bin/rails credentials:diff を利用できますが、Railsの実行環境からgit操作が必要です。一般的な環境ではないかもしれませんが、当社では開発環境にDockerを使用し、ホスト側でgit操作を行っています。そのため、コンテナにgitを導入する検討をしています。

記事の発表やその他の発表が気になる方はこちら!

www.youtube.com

少しでも興味を持っていただいた方は是非こちらからカジュアルにお話しましょう!

devenable.timee.co.jp

【イベントレポート】「Railsアプリと型検査」

イベント概要

2023年11月15日に「GENBA #1 〜RubyRails開発の現場〜」と題してRuby/Railsでの開発に関するトピックでタイミーとエンペイ社合同で勉強会を開催しました。 その中でタイミーバックエンドエンジニアの正徳さん a.k.a 神速さん(@sinsoku_listy)の発表「Railsアプリと型検査」をイベントレポート形式でお届けします。

登壇者情報

Railsアプリと型検査

RBSの基本

RBSとは

RBSRuby Signature)は、Ruby 3.0から導入された言語機能で、Rubyのコードに型情報を追加し、型検査と入力補完を可能にするための言語です。RBSファイルの拡張子は .rbsで、通常はプロジェクト内の sig/ ディレクトリに配置されます。

RBSのメリット

RBSの主なメリットは「型検査」と「入力補完」の2つがあります。

型検査とは

型検査には、Steepと呼ばれるツールがあります。Steepを使用すると、RBSの定義に違反するコードを検出する役割を果たします。例えば、関数に指定された引数の数が実際の呼び出しと一致しない場合、エラーが検出されます。この型検査は、Rubyコードを実行する前に問題を発見できます。

下記は型検査(Steep)の実行例です。

入力補完とは

VS Codesoutaro.steep-vscode 拡張をインストールすると、RBSファイルを読み込んで、Rubyコードの入力補完が賢くなります。

IRB v1.9.0で、RBSを使った入力補完がサポートされました。入力補完を有効にするには、gem install prismコマンドでprismをインストールし、IRBを起動するときに-r prismオプションを指定します。

タイミーの導入事例:実際の手順

ここまで一応RBSの基本の話だったんですけど、弊社が実際に導入事例を紹介したいと思います。

RBS導入のきっかけ

RubyKaigi 2023やメドピアのブログを読んだことから、RBSの導入への意欲が高まりました。 実際に試してみると、型チェックを無効にして、入力補完に重点を置くことで、比較的簡単にRBSを導入できることが分かりました。すぐに社内での調整を行い、方針を策定しました。 社内の開発者に質問してみたところ、RBSを完全に書くことには乗り気ではないものの、重要な部分だけを一部記述したいというニーズがありました。 しかし、それを別のファイルに書くのは少しつらいという声も聞かれました。

そこで元々弊社で使用していた Yard(ヤード)のドキュメントを活用し、重要な部分に型情報を明示し、コメントからRBSを生成して活用するアプローチを考えました。

実際にプロジェクトで検証した結果、うまく機能しそうだったため、「入れてみてダメだったら消そう」というノリで、試してみることになりました。

1. Gemfile に rbs_rails, steepを追加します

2. Steepfileを追加し、既存の型検査エラーは無視する

3. rbs_collection.yaml を作成する

Ruby公式で管理されている rbs-gem-collection というリポジトリに、有志の方が提供している情報を利用し、rbs_collection.yaml ファイルを作成します。

4. RBSを生成するRakeタスクを追加する

様々なコマンドを個別に実行するのは手間がかかるため、一度にタスクを生成できる「RBSセットアップ」という独自のコードを作成しました。 このコードは、rbs-gem-collection からRBSをダウンロードし、自社のプロダクトのコードを解析し、適切な雛形を生成し、全てのクラスとメソッド名が含まれたRBSを生成できるものです。

5. .gitignoreディレクトリを無視する

RBSは生成されるものとして扱っているため、.gitignore ファイルでこれを無視するように設定します。

6. RBSの定義エラーを回避するために最小限の型を書く

これまでの作業で、多くの型情報を生成できましたが、やはり一部の型情報は自動生成できない場合があります。そのような場合、手動で最小限の型情報を記述することで、エラーを回避します。例えば、Active Admin など一部のジェムは公式の型情報が提供されていないため、自社で型情報を記述する必要があります。ここまで実施し、RBSの文法エラーがない状態にプロジェクトを持っていきます。

まとめ:最小限のRBSで入力補完に型を使用できる

RBS + Sord の導入方法

Sordというジェムを使用しヤードドキュメントからRBSコマンドの型を生成します。

まずSordを導入し、Rakeタスクでsordを実行します。このとき sord のバグは、GSub で書き換えるとうまくいくことがあります。

この手順で、bin/rails rbs:setup を実行するとRBSが生成され、入力補完が賢くなる世界を作ることができました。 ちなみに、RubyMine や VS Code を使用していると、入力補完が賢くなるケースがあるようです。

型検査の課題

タイミーにおける型検査の課題は、Steepの型定義が少ないため、誤検知が発生する可能性があること、 また、特定のファイルのみを無視することができないため、段階的な導入が難しいことが挙げられます。

実際にどれくらいエラーが検出されるか検証をしてみると、656件ありました。ほとんどが誤検知ですが、そのなかで3件ほど面白いエラーがありましたのでご紹介します。

型検査で見つけたコード例1

型検査では、nilチェックが甘いため、ハーストした後にnilが来る可能性があることを考慮せず、IDなどの値に代入してしまうケースがありました。

型検査で見つけたコード例2

タイミーでは、ハッシュから銀行コードを取得する際に、全銀コードがない場合、nilが返されます。このときエラーを検知してしまいます。これは、Steepが全銀コードが正しい値しか渡されないことを前提としているためです(全銀コードが存在しないケースを想定できていない)

型検査で見つけたコード例3

足し算と掛け算をするときに、右の値をぼっち演算子を使うのですが、このときNilエラーが発生します

まとめ

今後、開発がさらに進化し、堅牢なコードを手軽に書ける世界がやってくるかもしれません。特に、入力補完の文脈で型検査を導入することは導入ハードルが低く、Railsアプリケーションの開発に大きな価値をもたらす可能性があります。明日からでも是非、Railsアプリ開発に型検査を取り入れてみてください。

記事の発表やその他の発表が気になる方はこちら!

www.youtube.com

少しでも興味を持っていただいた方は是非こちらからカジュアルにお話しましょう!

devenable.timee.co.jp