うっかりミスを防ぐPull-Requestテンプレート

こんにちは、M&Aクラウドの津崎です。

今日は、プロダクトチームで使っているGitHubのPull-Request(以下PR)テンプレートについて紹介したいと思います。

プロダクトチームでは、「ミスは個人の問題ではなくチームの問題」と取られ、 ミスした個人を責めるのではなく、「同じミスが起こらないようにするにはどうすればいいか? 」と考える文化が根付いています。

そのため、「気をつける」「教育する」「ミスしないように周知する」といった精神論ではなく、 そもそもミスしない仕組みを作り、ブラッシュアップすることを日常的に行っています。

プロダクトチームでは、2週間のスプリントの終わりにスプリントの振り返りを行う会を開いています。 スプリントの振り返り会では、KPT(Keep Problem Try)を議論する時間があり、 Tryの一環としてGitHubのPRテンプレートの更新を行ってきました。

今回は、我々が運用しているPRテンプレートについて公開し、 どんな風に使っているか紹介します。

f:id:zacky2:20200626153709p:plain
pr_template

PRテンプレートの解説

📝確認すべき項目

レビュアとPMがわかるように「どのURLの」「どのパーツが」「どうあるべきか」 を書く  
例: `/mypage/applications` の絞り込みパネルでステータスで絞り込みができること)

必要に応じてスクショも貼っておく。

この項目は、PRのレビューするひとがPRを動作ベースで確認するときに必要な情報を書きます。 この情報を埋めることで余計な情報交換を減らし、スムーズにレビューできるように心がけています。

🛠️リリース時作業

あれば
- PRタイトルに `[作業有]` をつける
- 手順をここに書く。2行以上あるならesaに書いてリンクを貼る

この項目は、リリース時に手動での作業が必要な場合について記載します。

リリースはCIにより半自動化していますが、DBの値を書き換えたり、環境変数を変更するなどの作業がリリース前後に必要な場合があります。 そういった場合は、ここに詳細を記載し、PRのタイトルにも[作業有]という文字列を追加します。

PRを作った人とリリースする人が別になることもよくあるので、 「誰でもリリースできる」「抜け漏れを起こさない」ためにこの項目を作りました。

😎ユーザーに伝えること

機能の使い方が変わった場合や新機能など、新しい使い方の説明を書きましょう。

これはプロダクトオーナーからの要望で追加しました。

弊社のプロダクトは、カスタマーサクセスチームや営業チームも仕様を理解している必要があります。 うっかり伝え漏れがあると、「いつの間にか使い方が変わってる」「お客さんに間違ったことを教えてしまった」といった問題が起こってしまいますので、 漏れのないようこちらに記載するようにしています。

✅PR前のチェック項目

- [ ] PRのタイトルの先頭に必要に応じて`[プロジェクト名]`または`[影響無し]`を付けた

PRのタイトルを工夫することで、PRの詳細を開かなくても必要な情報がわかるようにしています。

[影響無し]がついたPRは、リリース時にユーザー影響がないPRを意味しています。 通常はリリース前にプロダクトマネージャを含めた動作チェックを行っていますが、[影響無し]なPRは簡易的な確認だけでスピーディにリリースできます。

- [ ] PRのタイトルに「どのツールの」「なんの機能が」「どうなるか」が分かるように書いた

こちらもPRのタイトルについてのリマインドです。

プログラミングもそうですが、名前はとても重要です。 適切な名前であれば、わざわざPRの詳細を確認する必要がなく、プロダクトマネージャやリリース担当の負担を軽減できます。

- [ ] PMへの事前仕様確認 or 仕様はもう明確になっている

プロダクトマネージャと仕様のすり合わせが終わってるかの確認を促しています。

プロダクトマネージャと仕様の認識がずれていていると、リリース前の開発環境での動作確認のタイミングで仕様変更が発生し、 リリースが伸びたり、HotFixで追加のリリースが必要だったりと、手間が増えてしまいます。 そういった問題を軽減するためにPR作成の段階で、その仕様で大丈夫か?と確認するようにしています。

- [ ] テストを書いた or すでにある or 不要なほど軽微な修正

テストちゃんと書いてねという確認です。

- [ ] 動作検証した

動作確認は大事です。

開発中はもちろん全員動作確認はしているはずですが、 PRを投げる直前にゴミが混入してしまったり、リファクタでぶっ壊れたりしてる可能性もあります。

レビュワーに「動かない」と報告されるケースが何度かあったので、テンプレートに追加しました。

- [ ] ユーザ影響度: 高ならラベルをつける or 無し
  - `高`の定義: 注意深いレビューが必要(コードの仕様理解と動作確認)。サイト外に影響して取り返しのつかないもの(メール送信など)や、ユーザ行動に影響する部分(登録フォームや打診フォームなど)の改修。

ユーザー影響度についてラベルをつけようという確認です。

ユーザー影響度:高のPRはレビューと動作確認で入念なチェックを行うようにしています。

🌐インフラ影響がある場合(不要な場合は削除)

- [ ] PRのタイトルに`[インフラ]`を付けた
- [ ] 作業者は影響範囲を可能な限り説明できる
- [ ] 確認会・共有会(15~30min)をスケジュールに設定する

インフラ系の変更を行うPR向けの確認事項です。

インフラ系の変更は、予想外の影響が起こることが今までに多々ありました。 そこで、同じ問題を起こさないために、私達のチームでは出来るだけ「確認会」を実施しようと決めています。

(関連: workerインスタンスを追加したら障害が発生した話 https://tech.macloud.jp/entry/advent_calendar_2019_12_17 )

📊効果測定

機能の効果を測定できるRe:dashのURLを貼ってください。

Re:Dashはプロダクトの分析ツールです。 ここには、リリース後にプロダクトにどういった影響が出たかわかるようなRe:Dashのページを作成して追加します。

プロダクトチームでは6月から OODAループに基づく開発を行うことにしています。 そのため、プロダクトの新機能開発や機能改善を行うときは、その効果が現れたのかどうか効果を測定できるように、分析ページの作成も同時に行っています。

ℹ️issue

close: #

関連するIssue番号を入力できるようにしています。 close: #123と書けば、PRがマージされた時に#123も同時にCloseしてくれます。

以前、よくIssueの閉じ忘れがあったのですが、このテンプレートを追加してから閉じ忘れることは減ったように思います。

まとめ

今回は、うっかりミスを防ぐ方法として、PRのテンプレートについて紹介しました。 プロダクトチームでは、他にも「CircleCIを使ったリリースの自動化」や、「リリースのためのリリースタグ作成作業の自動化」、「リリース時の作業内容のテンプレート化」など、ミスを起こさない仕組みを随時取り入れていいます。

私達のPRテンプレートはかなり「ごった煮」な具合になっていますが、組織の数だけPRテンプレートはあってもいいと思います。 プロダクトの性質やチーム、文化に合わせて、自分達にぴったり合うPRテンプレートに熟成させていけたらと思います。

以上、参考になりましたら幸いです。

付録(PRテンプレートファイル)

Pull-Rquestテンプレートファイルはプロジェクトディレクトリに特定のパスで格納してあります。 .github/PULL_REQUEST_TEMPLATE.md 詳しくはこちらをご覧ください。

help.github.com

### 📝確認すべき項目
レビュアとPMがわかるように「どのURLの」「どのパーツが」「どうあるべきか」 を書く  
例: `/mypage/applications` の絞り込みパネルでステータスで絞り込みができること)

必要に応じてスクショも貼っておく。


### 🛠️リリース時作業
あれば
- PRタイトルに `[作業有]` をつける
- 手順をここに書く。2行以上あるならesaに書いてリンクを貼る

### 😎ユーザーに伝えること(CX等社内向けも含む)
機能の使い方が変わった場合や新機能など、新しい使い方の説明を書きましょう。

### ✅PR前のチェック項目
- [ ] PRのタイトルの先頭に必要に応じて`[プロジェクト名]`または`[影響無し]`を付けた
- [ ] PRのタイトルに「どのツールの」「なんの機能が」「どうなるか」が分かるように書いた
- [ ] PMへの事前仕様確認 or 仕様はもう明確になっている
- [ ] テストを書いた or すでにある or 不要なほど軽微な修正
- [ ] 動作検証した
- [ ] ユーザ影響度: 高ならラベルをつける or 無し
  - ``の定義: 注意深いレビューが必要(コードの仕様理解と動作確認)。サイト外に影響して取り返しのつかないもの(メール送信など)や、ユーザ行動に影響する部分(登録フォームや打診フォームなど)の改修。

### 🌐インフラ影響がある場合(不要な場合は削除)
- [ ] PRのタイトルに`[インフラ]`を付けた
- [ ] 作業者は影響範囲を可能な限り説明できる
- [ ] 確認会・共有会(15~30min)をスケジュールに設定する

### 📊効果測定
機能の効果を測定できるRe:dashのURLを貼ってください。

### ℹ️issue
close: #

TOPページリニューアルのデザイン裏話

f:id:tomoyasu_nagatake:20200615204509j:plain

こんにちは。M&Aクラウド Webデザイナーの長竹です🐤
入社してから約1年立ちました!

note.com

ここ数ヶ月では、M&Aクラウドの主要ページのリニューアルを進めてきました。 その振り返りも含めて、学んだことや意識的に行った事をまとめたいと思います。 今回はTOPページのリニューアルについて振り返ります。

リリースまでのフロー

始めてみると、必要なタスクは膨大にありました。 他部署に協力してもらったり、多くのユーザー様にご協力頂き、少しづつ進めていきました。

f:id:tomoyasu_nagatake:20200612125721j:plain

トップページの課題

f:id:tomoyasu_nagatake:20200615090247j:plain
旧TOPページ

  • M&Aクラウド」というサービスを印象付けるものが無い
  • 資金調達もできることが伝えられていない
  • 新しいサービスなのに、その説明や魅力を伝えられていない

サービスの成長に伴い、主に上記3つが課題として存在していました。 これらを解決するために今回リニューアルを進めていきました。

UXリサーチ

様々なデータや、今まで貰っていたユーザーの生の声、普段ユーザーと対話しているメンバーにヒアリングなどを行い 現状の課題感やユーザーの求めるものを整理しました。

  • アナリティクスやマウスフローなどのデータ解析
  • ユーザーから今までに貰っていた意見をまとめる
  • 要望のヒアリング
  • 改めてペルソナを作成

軸を定める

M&Aという業界で、競合や類似業界のTOPページがどんな軸で作られているのかを調査しました。 まず、コンテンツを見せているのか?サービスの説明をしているのか?といった大きい軸に当てはめ、競合や類似サイトを2つに分類しました。

f:id:tomoyasu_nagatake:20200615142651j:plain

旧トップページは後者で、コンテンツをメインにしていました。 しかし、今までに無い新しいサービスなのにあまり説明をせずにコンテンツを見せているため、そのコンテンツが何なのかをユーザーが理解していなかったりなど問題がありました。

そこで、今回のリニューアルではまずはしっかりとサービスを理解してもらい、M&A業界にサービスを浸透させていくことを軸として定めました。

プロトタイプを作る

様々な参考サイトを集め、UXリサーチで得た情報を基にプロトタイプを作成します。 ユーザーヒアリングを想定しているため、今回はある程度作り込みます。

デザインのルールを見直す
M&Aクラウドで使用しているカラーリングをまずは見直し、プロトタイプ作りを進めました。

サービスサイトでは、M&Aクラウドのロゴカラーの「赤」と「青」を様々なボタンに使用しています。 しかし、どちらも色が強く、結果ユーザーを迷わせてしまいます。

f:id:tomoyasu_nagatake:20200615110126p:plain
白黒にした場合の色の濃さがほぼ同じ

f:id:tomoyasu_nagatake:20200615115912p:plain
新カラー

そこで、新しいカラーを用意し、強調したいボタンをより明確にしました。 このルールをサイト全体に反映し、分かりやすいUIを目指します。

ファーストビューを考える
社内・外からアイデアを募り「事業売却と資金調達で次のステージへ」というキャッチコピーを作成しました。

事業売却と資金調達をする事で、各々の「次のステージ」に進む事が出来る。といったメッセージを込めています。 出来上がったキャッチコピーを基に「次のステージに向かってる感!」のあるファーストビューを作成しました。

訴求のテーマを決める
説明をしっかりしたいので、どのような訴求の流れが良いのかを模索し、今回は「悩みを解決」をテーマにサイトを構成しました。

ユーザーヒアリングを実施

出来上がったプロタイプを基に、計6回ほどユーザーヒアリングを行いました。 新鮮な意見を聞くことができとても参考になりました。

例)「売却案件」とありますが、売り手側からすると「案件」ではないので違和感があります。 など、本当にユーザー目線でいなければ気づかなかった細かい視点に今回多く気付く事ができました。

遂にリリース

Before f:id:tomoyasu_nagatake:20200615090247j:plain

After f:id:tomoyasu_nagatake:20200612130111p:plain

思い切ってファーストビューでの検索フォームは外し、キャッチコピーを目立たせています。 サービスについても具体的で分かりやすくなったと思います。

今回のリニューアルでは、業務フローや技術はもちろん
弊社のミッション「テクノロジーの力でM&A流通革命を」を実現するデザイナーとしてユーザーの理解がまた少し進んだと実感しました。

現在デザイナーは1名なので、引き続きオールマイティーに頑張りたいと思います!

テストを再設計して開発効率と実効速度を向上しました。

こんにちは、M&Aクラウドのかずへいです。

M&Aクラウドのサービスでは、サービスが拡大するにつれて、開発当初は気にならなかったいくつかの課題が生まれました。

今回、テストの設計を見直し、これらの課題を解決する取り組みを行いましたので、ご紹介したいと思います。

テスト環境に発生していた課題

テスト環境に発生していた課題には以下のようなものがありました。

  • Migrateが遅い
  • Seedingが遅い、Seedが複数のテストで使われており、変更がしづらい
  • テストが足りていないと感じる
  • DomainServiceのテストが書きづらい
  • Test時間が長い

それぞれどういうことが説明します。

Migrateが遅い

M&Aクラウドでは、2年間サービスを運用してきて、Migrationのファイルが積み重なっていました。テーブルを追加するものから、カラムを1つ追加するだけの細かなものまで合わせて280ファイルあまりが存在しました。

このMigrateをテスト実行の一番最初に実行していましたが、1回にローカルのPCで40秒ほど掛かっていました。

Seedingが遅い、Seedが複数のテストで使われており、変更がしづらい

M&Aクラウドのアプリケーションでは、テスト用のデータもSeedingという形で、テスト前のデータベース構成時に一括でデータを流し込んでいました。

そのおかげでテスト時にDBにデータを言える手間が省け、すぐにテストが書けるという状態になっていましたが、2年間かけてSeedingの分量が積み上がっていました。

また、アプリケーションが複雑になるにつれて、Seedのデータを複数のテストが呼び出すようになってしまいました。これでは、テストのためにSeedを変更すると関係ないテストが落ちるということが起きてしまいます。テストがSeedを介して密結合になり壊れやすくなってしまいました。

テストが少ないと感じる

テストが多いかどうかについては、カバレッジのような指標もありますが、基本的には開発者がどう感じているかが重要だと考えています。 「今のコードをリリースするのが不安だ」、「テストをちゃんと書いているのに不具合が出る」と感じているとき、テストが足りていないのでは無いかと思います。

既存のアプリケーションの設計上、テストを書くのに大きなコストが掛かったりパターンを網羅するのがむずかしい状態になっていたりすると、個別の開発者の努力だけではこの不安を払拭するのは難しいと思います。

DomainServiceのテストが書きづらい

M&Aクラウドのアプリケーションでは、データを持ったDomainクラスに収まらない、複数のDomainクラスを呼び出して調整するような操作をDomainServiceクラスという名前で扱っています。

Domainクラスを返してくれるRepositoryクラスがあり、DomainServiceクラスは複数のRepositoryクラスを呼び出し、Repositoryクラスから受け取ったDomainクラスをもとにビジネス上の処理を行います。

このようなクラスは、他の複数のクラスを呼び出す構造にあるため、Unitテストを書こうとするとMockを複数箇所に使ってテストを書かなければならず、テストを書く際の大きな負担になっていました。

Test時間が長い

M&Aクラウドのアプリケーションでは、テストの数は1,500件程度とそれほど多くありませんが、その6割に当たる900件ほどのテストがUnitテストではなくFeatureテストであり、すべて実行すると10分ほど掛かるようになっていました。

解決策

このような課題が発生していましたが、中にはアプリケーションの設計そのものに関係するものもあり、個別の課題を一つづつ直せば解決するというわけではありませんでした。

ここで問題を整理し、以下のような複数の解決案を講じました。

  • 過去のMigrateをまとめてSQLのダンプにする
  • Unit、Featureの2つの区分だったテストをUnit、DbIntegration、Featureの3種類に分割する
  • テストを並列実行し、実行時間を短くする

過去のMigrateをまとめてSQLのダンプにする

過去のMigrateをMySQLのdumpにしてすべてまとめた1つのmigrateにしました。 これによって実行時間が40秒→6秒ほどになりました。

MySQLのdumpにしてしまったので、MySQL以外のDBとの互換性が無くなってしまったということはありますが、すでにMigrateの中にMySQL依存のSQLなども書かれていたことから思い切ってMySQLのみというふうに決め込むことにしました。

Unit、Featureの2つの区分だったテストをUnit、DbIntegration、Featureの3種類に分割する

テストピラミッドという考え方をご存知でしょうか?Unitテスト > 統合テスト > UIテストの順にテストの数を増やすことで、無駄なく信頼性の高いテストを保守できるという考えです。

f:id:mac-tech:20200607185951p:plain
テストピラミッド

M&AクラウドのアプリケーションはLaravelを使っており、PHPUnitでテストを実行しています。Laravelのアプリケーションには、インストールしたときからUnitとFeatureという2つのテスト区分が存在しており、M&Aクラウドではそれをそのまま使ってテストを書いていました。

Featureテストはリクエストからレスポンスまでの一連の処理がすべて行われて初めてGreenになるため、Featureテストが動いていれば機能がちゃんと動いているという安心感?からか、どうしてもFeatureテストを書きがちになってしまいます。

しかし、Featureテストは統合テストに近い概念なので、これではテストピラミッドに違反してしまいます。

どうすればFeatureテストを減らし、Unitテストを増やすことができるでしょうか?

Featureテストで担保していたロジックをUnitテストに移す

Featureテストでは、リクエストからレスポンスまでの処理のすべてがテストできるため、ここの部分をテストしているぞ!という意識が希薄になりがちで、実際にUnitテストできるはずのものもFeatureテストに含まれていました。

f:id:mac-tech:20200607191457p:plain

今回それらを抽出し、アプリケーションの設定とともに見直すことで、Unitテストを書けるようにしました。

f:id:mac-tech:20200607191513p:plain

以下が抽出されたクラスです。

  • Requestクラス
  • Responseクラス
  • Repositoryクラス

次からどのようにクラスが抽出されテストされるのかを説明します。

Controllerの処理をRequestとResponseに分解しテスト可能にする

Laravelはとても便利なので、ControllerでLaravelが提供してくれるリクエストとレスポンスのクラスを活用するだけで簡単に処理が書けてしまいます。

例えば

return view('view_name', $params);

と書くだけで簡単にレスポンスを返す事ができます。

しかし、これではリクエストとレスポンスをテストするためにControllerを呼び出さねばならずFeatureテストになるのは必至です。

そこでRequestをFormRequestを継承したクラスとして、ResponseをResponsableインターフェースを実装したクラスとして丁寧に実装してやります。

これによりRequestとResponseのクラスを個別にテストすることができます。

以下はResponsableなクラスのテストの例です。

qiita.com

UnitテストとFeatureテストの間として、DbIntegrationテストを定義する

データベースからデータを取得する箇所のテストは、Mockに差し替えてしまうと本質的にはテストできません。よってどうしてもFeatureテスト側によってしまいがちです。そこで、DbIntegrationテストとしてUnitテストとFeatureテストの間に「データベースにアクセスしちゃうけど、Featureテストではないテスト」を新しく定義することにしました。

また、課題になっていたDomainServiceクラスのテストもこのDbIntegrationテストに含め、データベースアクセスを許すことにしました。 Mockをたくさん書かないといけないテストはMockの処理自体がコードと密結合してしまうため、テストが壊れやすくなってしまうという問題があります。また、Mock::aが呼ばれて、Mock::bが呼ばれて…とMockが正しく呼ばれることをテストに書き、Mock経由で得られた値が返却されることをテストできても、それはテストとして正しく動いているのか?というと疑問があります。

この問題は「モックの泥沼」という名前で「初めての自動テスト」という本に紹介されていますので、是非読んでみていただければと思います。

初めての自動テスト ―Webシステムのための自動テスト基礎

初めての自動テスト ―Webシステムのための自動テスト基礎

  • 作者:Jonathan Rasmusson
  • 発売日: 2017/09/21
  • メディア: 単行本(ソフトカバー)

よってDomainServiceのテストは、テスト中にデータベース接続することを許し、Mockを使いすぎないようにするという方針にしました。

DbIntegrationテストは以下のような方法で、テストに接続はするが遅くはならないように実装しています。

qiita.com

テストを並列実行し、実行時間を短くする

新しくテストをUnitテスト、DbIntegrationテスト、Featureテストに分割したことにより、それぞれのテスト郡に属するテストが減り、並列に実行するとテスト時間が抑えられます。

弊社ではCircleCIを利用していますので、テストを並列実行し、全てが完了したら開発環境にデプロイするといった仕組みを組んでいます。

f:id:mac-tech:20200607193754p:plain

現状ではまだFeatureテストが多いですが、徐々にUnitとDbIntegrationに寄せていくつもりです。

まとめ

アプリケーションの成長とともにテストの設計が開発効率を下げるようになってしまったので、アプリケーションの設計とともにテストの設計を見直した事例を紹介させていただきました。

テストの設計もアプリケーションと同様に、最初の設計をただ守り続けるだけではなくて、状況に合わせてアップデートしていく必要があるなと改めて思いました。

OpenAPI(Swagger)を用いたフロントエンドとバックエンドを疎結合にする開発

こんにちは。エンジニアの鈴木(@yamotuki)です。
今日はAPIドキュメントを書くことでフロントエンドとバックエンドの開発を疎結合にして平行して開発を進めている話を書こうと思います。

疎結合とは?

通常の開発フローだとバックエンドAPIを先に実装して、そのあとでフロントエンドの開発を進める必要があります。これはAPIからどのようなレスポンスが帰ってくるかわからないので、フロントエンドは先に実装することはできないと言う事情があります。では、APIを完全に実装しきってからではないとフロントエンドの開発がすすめられないのか、というとそうではないと考えています。

依存関係逆転の原則(DIP)の考え方を導入すると、フロントエンドが依存する対象を変えることができます。DIPを一言で言うと "詳細に依存するな、インターフェースに依存しろ" だと私は考えています。

依存性逆転の原則 - Wikipedia

今回のAPIとフロントエンドの結合部分においてはAPIの表向きのレスポンスフォーマット、すなわちインターフェースが重要です。レスポンスフォーマットとはレスポンスステータスやJSON形式などです。 フロントエンドもAPI実装のそのどちらもAPIのインターフェースだけに依存するようにすれば依存性逆転が実現できそうです。

APIインターフェースの定義の仕方はデファクトスタンダードとしてOpenAPIがあります。

OpenAPI (Swagger) とは

swagger.io

The OpenAPI Specification (OAS) defines a standard, language-agnostic interface to RESTful APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection.

要するに、APIのインターフェースを記述するための仕様です。 OpenAPIは version 3 からはOpenAPIと呼ばれており、version 2の時にはswaggerと呼ばれておりこちらのほうを聞いたことがある人も多いのではないかと思います。

最終的に書かれるインターフェース定義書はYAMLまたはJSONです。弊社ではSwagger-phpと言うライブラリを使ってアノテーションから自動生成させています(詳細は後述)。 例としてニュース一覧を返すAPI についての記述を以下に示します。レスポンスステータスは200で、内容は別途定義された schema の内容を返すことが定義されています。この記述は内部実装には依存しません。内部実装がこの仕様に依存するように実装していきます。

        "/api/media/news": {
            "get": {
                "responses": {
                    "200": {
                        "description": "success",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/news_list_responder"
                                }
                            }
                        }
                    }
                }
            }
        },

PHP/Laravel でどのように書くか

PHPにOpenAPIを組み込むのはSwagger-phpと言うライブラリがあります。

弊社はバックエンドのフレームワークとしてLaravelを使っています。 Laravelに対しては L5-swagger と言うライブラリを使うと、上記のSwagger-phpに加えて人間がより読みやすい表現をブラウザ経由で見れるswagger-uiを同時に導入できます。

GitHub - DarkaOnLine/L5-Swagger: Swagger integration to Laravel 5

This package is a wrapper of Swagger-php and swagger-ui adapted to work with Laravel 5.

Swagger-php の記法でかくと以下のようになります

    /**
     * @OA\Get(
     *   path="/api/media/news",
     *   @OA\Response(
     *       response="200",
     *       description="success",
     *       @OA\JsonContent(ref="#/components/schemas/news_list_responder")
     *   ),
     * )
     */
/**
 * @OA\Schema(
 *     schema="news_summary",
 *     required={"id", "title", "created_at"},
 *     @OA\Property(property="id", type="integer", example=1),
 *     @OA\Property(property="title", type="string", example="タイトル"),
 *     @OA\Property(property="created_at", type="string", example="2020-01-17T11:25:28+09:00"),
 * )
 */
/**
 * @OA\Schema(
 *   schema="news_list_responder",
     * @OA\Property(
     *     property="news",
     *     type="array",
     *     @OA\Items(
     *       ref="#/components/schemas/news_summary"
     *     ),
     * )
 * )
 */

これがSwagger-phpによって解釈されると先に記述したJSON形式での仕様書になり、さらにswagger-uiの機能で以下のように人間が読みやすい形になります。

swagger-ui のブラウザで見たときのイメージ

f:id:yamotuki:20200521162408p:plain
swagger-ui

これを参照してフロントエンドを実装することで、フロントエンドはAPIのインターフェースに依存することができました。 次はバックエンド実装が実際にAPIインターフェースと一致していることを確認する方法です。

API実装がAPIインターフェースに一致していることを自動テストする

gitlab.com

この openapi-validator を使うことで、APIレスポンスが実際に定義に一致しているかを自動テストできます。 このライブラリはStar数もそんなに多くなく、ネット上に情報も少ないので使い方の参考実装も置いておきます。

テスト例。それぞれのAPIの仕様のテストはこれだけです。

    public function testInvokeSpec()
    {
        $this->specTest('get', '/api/media/news', [], 200,
            NewsListGetAction::class);
    }

以下のコードで openapi-validator をラッピングしています。

    protected function specTest(string $method, string $path, array $params, int $statusCode, string $actionClass): void
    {
        $method = strtolower($method);
        switch ($method) {
            case 'get':
                $response = $this->getJson($path, $params);
                break;
            case 'post':
                $response = $this->postJson($path, $params);
                break;
            case 'delete':
                $response = $this->deleteJson($path, $params);
                break;
        }

        $openApiValidator = OpenApiValidator::getValidator();
        $specResult = $openApiValidator->validate($actionClass . '::__invoke', $statusCode,
            json_decode($response->getContent(), true));
        echo $specResult;
        $this->assertEquals($specResult->hasErrors(), false);
    }

Validator インスタンスの取得コードです。毎回定義書を更新するたびにapi-docsを手動で再生成するのが面倒なので l5-swagger:generate を最初に叩いています。

use Illuminate\Support\Facades\Artisan;
use Mmal\OpenapiValidator\Validator;

class OpenApiValidator
{
    protected static $openApiValidator;

    // ref: https://gitlab.com/mmalawski/openapi-validator
    public static function getValidator()
    {
        if (is_null(static::$openApiValidator)) {
            Artisan::call('l5-swagger:generate');
            static::$openApiValidator = new Validator(
                json_decode(file_get_contents('./storage/api-docs/api-docs.json'), true));
        }

        return static::$openApiValidator;
    }
}

終わりに

この手法の良い点、悪い点をまとめておきます。

良い点

  • フロントエンドとバックエンドを並行開発しやすい
  • お互いの開発者は実装よりも仕様に集中できるので議論しやすい
  • 先にAPI外部設計を議論して固めることにより実装がスムーズ
  • APIレスポンスは仕様に沿っているか自動テストされているので保守が楽

悪い点

  • PHPの場合はOpenAPIのAnnotationを手動で書かなければいけない
    • プロパティが多いAPIだと正直つらい
    • 型がもっとはっきりしている言語だと最初の実装から自動生成してくれるなどもあるようです
  • API POST リクエストのパラメータのテストは openapi-validatorがサポートしていない(?)
    • 実装とPOSTパラメタに関するテストコードだけを誤って修正してしまうとOpenAPI仕様書が古い状態になる可能性がある

Nuxt.js化計画vol.2

f:id:kubotak:20200317182842j:plain

こんにちは、久保田です(@kubotak_public)です。

以前以下の記事を公開していましたが、引き続きNuxt.js化が進められているのでvol.2ということで紹介したいと思います。

tech.macloud.jp

リリースはGW前の4/29に行われました。 サービス停止を伴う大型なアップデートで、フロントエンドのみならず、データベース構造を再設計したリニューアルをいたしました。 データベースに関しては別稿で紹介されるかと思いますが、本稿ではNuxt.js化ということでフロントエンドの紹介をします。

今回対応したページはログイン必須なページのため、リンクを張って紹介できないのでご了承ください。

ページ遷移アニメーション

今回はリニューアルというよりは新規ページ作成のほうが多く、新しい挑戦も行いました。 まずは、アニメーションを伴うページ遷移です。

Nuxt.jsなどのSPAを作成できるフレームワークであればブラウザリロードなしの画面遷移に加え、遷移中にアニメーションでUIをリッチにすることがよくあると思います。 しかし、弊社プロダクトはもともとMPA(Multiple Page Application)で作成されているサイトをページ単位でNuxt.jsに移行しています。 ですので、基本的にリンクタグはaタグもとい、アンカータグを利用しています。

しかし、今回は新規ページというとこで一連の遷移をnuxt-linkやrouter.pushを利用した遷移を利用し、nuxt.jsのpage transition機能で遷移中にアニメーションを行う実装をしました。

f:id:kubotak:20200511154902g:plain

フォームパーツをStorybookで管理

新規で作成したページでは十数種類のフォームパーツが必要でした。 独立して作成し、動作確認、レビュー、そして導入方法のカタログとして活用できるStorybookを利用しました。

先程のページ遷移アニメーションとは別に、事前にフォームパーツを作成できるのでとても重宝しました。 Storybook上で作成、動作確認をしたコンポーネントはそのまま導入時に挙動やProps確認するためのカタログとしても役に立ちます。 Nuxt.js、Vue.jsではこのようなツールの使い方などを紹介しているサイトなども多く、ドキュメントも豊富なので助かりますね。

f:id:kubotak:20200511170155g:plain

Vuexの利用

すでにVuexは利用していたのですが、今回の新規ページでは特にこのVuexのおかげで楽に状態管理ができたといえます。 アニメーションで遷移するページの各フォームのデータはVuexに同期されていて、ユーザーの入力した情報はサーバーとクライアントで基本的には同期されています。 ページを跨いでもSPAのためVuexステートは保持され続けるので状態管理がしやすいです。 ただしブラウザリロードも考慮しないといけないのでちゃんとアプリケーション起動時にはHTTP APIから取得したデータを初期値としてVuexにマッピングしています。 これもNuxt.jsであればサーバーサイドで実行・マッピングしたVuexデータをクライアント側にHydrateしてくれるのでクライアントでの不必要なAjax通信しなくてよいのも良い機能だと思います。

最後に

引き続き弊社プロダクトはNuxt.jsへのリプレイスを進めています。 Nuxt.js化したページは随時紹介していきたいと思います。

サービスの可用性を担保するための取り組みについて

こんにちは。エンジニアの濱田( @hamakou108 )です。

今回は弊社サービスの可用性を担保するために開発チームで取り組んでいることについて紹介したいと思います。

はじめに

新型コロナウイルスの脅威が世界的に拡大していく中、経済への打撃は日に日に深刻さを増しています。 私達M&Aクラウドではこういった状況下でも積極的に買収・出資を検討している企業様を見える化する施策を行っています。

macloud.jp

この施策はプロジェクト立ち上げから1週間程度というスピードでリリースすることができましたが、その裏にはサービスの信頼性や可用性を担保するための平常的な取り組みの存在があります。 機能が何らかのエラーで利用できない、サービスが重くて使えないといった問題が多発していれば、保守運用に掛かりっきりで新規開発どころではありませんよね。 M&Aクラウドの開発チームで可用性を担保するために取り組んでいることの1つが SLO の設定とその評価の自動化です。

SLO/SLI/SLA

一概にサービスの可用性とは言うものの、どのようにして可用性を評価すればよいでしょうか? ここで役立つのが SRE (Site Reliability Engineering) の文脈で用いられる SLO 、 SLI 、 SLA という概念です。 Google Cloud の CRE チームのブログ記事によると以下のように表現できそうです。

  • SLO (Service-Level Objective): システムの可用性を担保するにあたってターゲットとする目標、数値。
  • SLI (Service-Level Indicator): SLO が満たされているか評価する際に用いる指標。エラー率やスループットなど。
  • SLA (Service-Level Agreement): サービスの利用者に対して約束する可用性のレベル。

一般的には SLO と SLI を設定して一定期間ごとに評価することで可用性が担保されているか判定します。 サブスクリプションとして利用者にサービス提供している場合などは SLA を設定し、満たせなかった場合に罰則が発生するような契約を結ぶケースもあります。

ここで SLO は高ければ高いほど良いというわけではなく、事業目標を達成する上で理にかなっているかという点が重要となります。 サービス品質向上のためにリソースを割けば、その分だけ機能開発に費やすためのリソースを失うことになります。 機能開発と品質向上をうまくバランスさせて、事業目標を達成できるような SLO を設定することが1つの肝です。

チームにおける SLO/SLI と評価のための仕組み

M&Aクラウドの開発チームでは SLO として可用性 99.95 % を掲げており、 SLI については Web サービスという性質から HTTP レスポンスステータスを採用しています。 すなわち Server Error 5xx ステータスを返す割合が 0.05 % 未満であれば SLO が満たされていると評価するような形です。

私達はアクセスログをカスタムしたデータを ElasticSearch に格納しており、 Kibana でステータスコードごとにグルーピングしたグラフで可視化していつでも確認できるような仕組みを作成しています。

Kibana でステータスコードによってグルーピングしたアクセスログのグラフ

また可用性を継続的に評価するため、 Kibana のアラート機能を使って週に1度可用性を計測し、 SLO を下回っている場合は Slack 通知する仕組みも作成しています。 こちらに関しては具体的な設定方法を Qiita で公開しています。

qiita.com

Slack 通知の仕組みを作成して2ヶ月程ですが、今のところ SLO を下回った週はありません。 通知が来ない間は可用性について特に心配する必要はないので、他の開発に集中することができています。

終わりに

最後に内容をまとめます。

  • 新規開発をスピーディーに進めるにあたって、サービスの信頼性や可用性の担保が不可欠。
  • サービスの可用性を評価するための手段として SLO や SLI といった概念が有用。
  • M&Aクラウドの開発チームでは SLI としての HTTP レスポンスステータスの可視化、および SLO を下回った場合の通知の自動化を行い、 SLO を継続的に評価している。

全員リモートワークに伴ってアナログカンバンを捨ててGitHub Projectsに移行しました

こんにちは。M&Aクラウド津崎です。

M&Aクラウドでは、新型コロナの感染対策として、ほぼ全社員がリモートワークを行なっています。 弊社はもともと原則としてリモート ワークを行なっていなかったため、リモート ワークの導入に伴い、いくつか工夫しなければならない点がありました。 そのうちの一つが、カンバンです。

エンジニアチームでは、スプリントで実施するタスクについてカンバンで管理しています。 カンバンは、アナログな物理的カンバンボード(ホワイトボードに付箋を貼る)を使って運用していました。 当然ながら、このボードはインターネットで閲覧することもタスクも操作することもできません。(なんということでしょう!)

そういうわけで、オンラインで使えるプロジェクト管理ツールを使うニーズが生まれたわけです。 プロジェクト管理ツールはBacklogやRedmine,Asanaなどいろいろ有名どころはありますが、 以前から部分的に活用(※1)していたGitHub Projectsへの移行を検討しました。

※1 GitHub Projectsはタスクの付箋製造マシーンとして使ってました。 もともと、スプリントごとにGitHubのIssueをポストイットに手書きで書き写してタスク化するつらい作業がありました。 それでは時間がもったいないということで、 GitHubのIssueをGitHub Projectsに表示して、CSSを上書きして見た目を付箋風に調整した上で印刷し、ハサミで切り取って付箋化してました。

f:id:zacky2:20200415165937j:plain

図 我々の物理カンバンボード(タスクをグルーピングしたり、週の予定を書いたり色々カスタマイズされている)

GitHub Projectsってなに?

GitHub Projects はGitHubが提供してるカンバンツールです。 ボードはリポジトリ単位または組織単位で(リポジトリをまたいで)作ることができます。 Issueをタスクとして表示できたり、GitHubのアカウントがそのまま使えるのが他のタスク管理ツールと比較した特徴かなと思います。

f:id:zacky2:20200415172651j:plain
github projects

GitHub Projectsを2週間ちょっと使った結果

弊社のエンジニア5名と、デザイナー1名にGitHub Projectsについてアンケートに答えてもらいました。 アンケートは、今までの物理カンバンボードとの比較という観点で答えてもらいました。

誰が何をやってるかわかりますか?

f:id:zacky2:20200415181332p:plain

評価はぼちぼちという感じでした。

アイコンが表示されるのでわかりやすいという意見が多いです。 物理カンバンボードではタスクに手書きで名前を書いていたので、それよりはわかりやすいと評価されています。 一方で、column(フェーズ)とassingneeが設定されてないとわからないという意見もありました。 これは仕組みの問題というより運用の問題なので、忘れずに更新できるようにしたいです。

f:id:zacky2:20200415185309j:plain

図 タスクにAssigneeのアイコンが出てる例

タスクの一覧性はよいですか?

f:id:zacky2:20200415181327p:plain

比較的ネガティブな評価でした。

どのくらいタスクが進行しているかはわかりやすい。という点が高評価で、 未着手(TODO)のissueがたくさんあり、スクロールしないと見れないので一覧性が悪いという点が悪評価でした。

f:id:zacky2:20200415185911p:plain

図 TODOがいっぱいあって見辛い!(ブラウザでズームアウト80%しててもこれ)

また、検索ができないという意見もありますが、GitHub Projectsには検索機能もついており、タグをクリックしたり、フォームに文字列を入力することでカジュアルにフィルタすることができました。 まだ使用して2週間なので、機能を使いこなせてないユーザーが多いのかもしれません。

f:id:zacky2:20200415185609j:plain

図 検索フォームあるよ!

UXよいですか?

f:id:zacky2:20200415181322p:plain

評価が別れました。

高評価な点

  • ページ遷移せずに詳細を見られる(画面右に表示される)
  • クローズすると自動で移動
  • 詳細を記入できる
  • PRと紐づけられる

低評価な点

  • issueをカンバンに追加するのがめんどくさい
  • タスクをまとめて移動できない

デザインはイケてますか?

f:id:zacky2:20200415181317p:plain

ぼちぼちという評価。

シンプルで良いという意見が多いように感じました。

あなたの思うメリット

f:id:zacky2:20200415181313p:plain

ラベルのフィルタ機能がメリットとして上がっていました。回答者のフィルタがないと回答していた人もいるので、この辺は使い方の周知をした方が良さそうです。 また、GitHubを使って開発してるので、issueやアカウントをそのまま連携できるという点がメリットとして挙げられていました。

あなたの思うデメリット

f:id:zacky2:20200415181308p:plain

操作性の悪さ、一覧性の悪さが指摘されました。

総合評価

f:id:zacky2:20200415181602p:plain

総合評価は、ぼちぼちという感じです。 平均すると 3点/5満点 という結果になりました。

いくつか不満はあるものの、このまま使用を続けられるレベルかなという印象です。

その他

f:id:zacky2:20200415183852p:plain

最後にフリーコメントで、いい意見がありました。

弊社は今後もエンジニアをどんどん増やしていく予定です。 コメントにあるように、一覧性や操作性を考えると、エンジニア10人くらいまでなら一つのカンバンで運用できそうですが、 人数が多くなった時には、チームごとにカンバンを分けたり、別のツールを使う必要が出てきそうです。

逆に言えば、6名程度であれば一つのカンバンで十分に使えます。

まとめ

  • GitHub Projects 総合評価 : ★★★☆☆ (3点/5満点) ※弊社エンジニア調べ
  • GitHubのIssueやPRと連携できる
  • 使い勝手はそこそこ

以上、参考になりましたら幸いです。

PHPでnullを減らす取り組み

こんにちは、M&Aクラウドのかずへいです。

M&Aクラウドの開発チームでは、スプリントごとにKPTを行い、その中でProblemとして出た課題を技術的に解決する方法を考えるMTGがあるのですが、そこで以下のような方針を決定しました。

「nullを使わず、未定義を表すクラスをちゃんと自分たちで定義しよう!」

なぜこのような方針になったかということと、やってみてどうなのかということを以下似紹介します。

経緯

あるページが特定条件で変数の中身がnullで表示の箇所で落ちるという不具合が発覚しました。

PHPerの皆さんからするとあるあるですよね。

目の前のバグはすぐ解決しましたが、その問題がProblemとして上がり、改善策をみんなで議論しました。

  • そもそもnullは何を意味しているのか
  • 表示するときにnullだったら、項目ごと表示しないのか?「未設定」などと表示するべきなのか?
  • nullにはロジックが書けないから末端のview側でnullチェックしなければならず、nullのときの表示方法もぶれてしまうのではないか

このような議論から、

「nullを使わずに、未設定に当たる部分をクラスとして自分たちで定義することで、未設定な値についてのロジックをクラス側に書くことにより、view側にロジックが散らばらないのではないか。」という結論にいたり、試してみることにしました。

結果

結果として、今までただnullとしていたものが「削除済み」だったり、「未定義」だったり、「非公開」だったり、ちゃんとした意味を持つクラスだったということが浮き彫りになりました。

例えば、アクションを行ったユーザーが削除済だった場合、今まではnullが入っていたが、削除済のユーザー(DeletedUserクラス)を入るようにしました。UserクラスとDeletedUserクラスは同じinterfaceを持っているので、view側では全く同じメソッドが呼ばれるようになり、条件分岐がなくなります。

いままでnullに押し込めていたロジックがクラスとして現れ、それにロジックが書けるようになり表現力が上がりました。 表示に関わる処理もview側からドメイン側に移すことができ、コードの重複が減るようになるはずです。

まとめ

今までnullだったところに一つ一つクラスを定義していくことは正直に言って面倒な作業ではありますが、nullableであるということが条件分岐そのものなので、そこをクラスに置き換えていくことはとても意義があることだと思いました。

Nuxt.js化計画vol.1

f:id:kubotak:20200317182842j:plain

こんにちは、M&Aクラウドの久保田です。 現在弊社ではPHPフレームワークであるLaravelで作られたWebサイトをJavaScriptフレームワークのNuxt.jsへのリプレースを実施中です。 全てのページをNuxt.jsに置き換えるかどうかは現時点では未定ですが、多くのページで置き換えが行われる想定です。

移行経緯

まずは移行経緯についてお話したいと思います。 弊社のサービスでは3つの種類のユーザーがいます。

  • 会社や事業を買ってもらいたい、もしくは資金調達したいユーザー
  • 会社や事業を買いたい、もしくは出資したいユーザー
  • 弊社の管理者ユーザー

これらのユーザーが一つのアプリケーションを利用している状態です。 現在の利用を考慮すると一つのアプリケーションのままでも問題有りませんが、将来的により多くの要望を答えるためにはアプリケーションの肥大化は避けられません。 おそらくはマイクロサービスアーキテクチャなどを導入して利用者(アクター)毎に独立したアプリケーションを作成することが望まれるかもしれません。 また、UIと機能も密接に関わりすぎるとロジックが複雑化するなどが考えられます。

そして、よりリッチなユーザー体験を行えるようにするためにはSPAなどの導入も必要になってきます。 今回弊社ではその第一歩としてUIと機能の分離を行うために画面の生成処理をNuxt.jsで行い、ロジックはLaravelのHTTP APIで行うようにリニューアル・リプレースを進めています。

現在ではトップページと資料請求ページがNuxt.js化が完了しています。

macloud.jp

macloud.jp

開発技術

今回のリプレースでは以下の技術を利用しています。

  • TypeScript
  • Nuxt.js
  • Vue Composition API
  • Vuex

型安全の恩恵を受けるためTypeScriptによる開発を行っています。 また、Vue.js version3で導入されるComposition APIはTypeScriptによる型システムとの親和性が良いことから先行で導入しています。 これに関してはRoppongi.vue #5にてお話させていただきましたのでそちらを御覧ください。

弊社津崎・久保田がYoutube配信のオンライン勉強会で登壇しました。 - M&Aクラウド開発者ブログ

今後について

リプレース完了したページに関しては本ブログで紹介するようシリーズ化したいと思います。 また、別稿ではサーバーアーキテクチャやHTTP APIの設計などについても紹介できればと思います。

サイト速度改善の取り組み - SpeedCurveの使用 -

こんにちは。エンジニアの鈴木(@yamotuki)です。

サイトの速度改善のとっかかりとして定期的に速度を計測するために SpeedCurve というSaaSを導入しました。 この記事では「SpeedCurve で何をやれるのか?」「どういう数値を見ているのか?」ということを共有したいと思います。

実際にそのデータを使って改善をどのようにやるか、というのは後続の記事で書いていければと考えています。

SpeedCurve とは

speedcurve.com

At SpeedCurve, we focus on measuring the interplay between design & performance to help you deliver a great, enjoyable and fast experience to your users.

機械翻訳すると ⬇️

SpeedCurveでは、デザインとパフォーマンスの相互作用を測定することに重点を置いており、ユーザーに優れた、楽しくて速い体験を提供するのに役立ちます。

SpeedCurveは単なるサーバレスポンス速度だけでなく、画像のサイズやアクセサビリティの改善ポイントなども見ることができます。

具体的に何ができるの?

以下の二つの導入方法があります

  • Synthetic Monitoring : 特定の環境からアクセスして測定する(Syntheticは「人造」や「人工」)
  • Real User Monitoring: 実際のユーザ行動をモニタリングする。LUXと表記されているパターンもある

弊社の最初の導入としては一つ目のSyntheticを中心に使っていきます。
Real User Monitoring は便利そうですがお金が結構かかりそうなのと、まずは理想的な環境でのチューニングからということで導入していません。

以下では Synthetic でできることの一部を紹介します。

Site

一番ベーシックなところは ”Site” の項目。 以下の項目を設定しておくと、選択して見れる。グラフの大きさは個人的にはMediam Chartsくらいが直感的でおすすめ。

  • Site
  • Url
  • Browser
  • Region

f:id:yamotuki:20200312111622p:plain
Syntheticの一番ベーシックなところ

Responsive

スマホで見た場合とPC Chromeで見た場合との違いを出している。 Responsiveのところでスマホの方がかなり遅くなっていたら要注意。 このスクショは改善前のもの。

f:id:yamotuki:20200312112210p:plain
responsive

Benchmark

他社サイトとの比較。

ページ名を同名で(例えば TOPmain_contents_list)とつけておくと比較できる。 見るときに全て大文字にされてしまうので、名前はsnake_case でつけた方が見やすい。

最初の測定対象は以下のページとしました。

  • topページ(top) vs 競合
  • 募集一覧(main_contents_list)vs 競合
  • 募集詳細(main_contents_detail)vs 競合

どのような指標をサイト改善に使うか?

以下は弊社サイトTOPページのリニューアルの時に使用した数値です。

  • SPとPCが同等の速度を実現(Responsive の項目で判断)
    • コンテンツサイズを同等にする
    • リクエストブレイクダウンを同等にする
  • PCでTTFB (backend)
    • before 1.59s => 目標1.0s以内 => 実際 0.7sくらい
  • speedindex
    • before 2.99s => 目標1.5s以内 => リニューアル直後は 1.6sくらい。その後ファーストビューだけでなくUX考えてやや下のコンテンツも同期的に取るようにして1.9sほど。鋭意調整中です。
  • Lighthouse performance score について(レンダリング過程のキャプチャ画像をタップすると詳細が見れるものです)
    • SEO, Best Practice, Accessibility, Performance にそれぞれ目標を立てて作業しましたが、細かいので略
    • Perfomance以外は満足のいく結果が取れたので良いのですが、Permanceについてはまだ頑張っているところです。
  • リニューアルしたページについて benchmarkで speedIndex で同業他社サイトよりspeedIndexで勝るようにする

speedIndex 以外にも指標となるデータは沢山あります。今後、弊社のユーザ体験としてこうあるべきでは?という議論が深まっていくと他の指標を使うこともありえるかと思います。speedIndexはユーザの体感と近いと言われているので、とっかかりとしてまずこれを見て最低限の改善をしていくことにしました。(speedIndexの詳細については後述)

speedIndexとは何か

https://developers.google.com/web/tools/lighthouse/audits/speed-index?hl=ja

ページのコンテンツが目に見える状態になるまでの時間

というわけでユーザ体感に近いと言われている数値。

もっと詳細の計算ロジックとかはこちら。 https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/metrics/speed-index

要するに、数字と表示領域をパーセントのグラフをとった、上側の領域の積算のようです。

お高いのでしょう?

高いイメージがあって弊社でも導入が進んでいませんでした。

先に以下の二つの測定方法があることを紹介しました(再掲)。

  • Synthetic Monitoring : 特定の環境からアクセスして測定する(Syntheticは「人造」や「人工」)
  • Real User Monitoring: 実際のユーザ行動をモニタリングする。LUXと表記されているパターンもある

実際にはSyntheticについてはそこまで高くなく導入できます。 Real User Monitoring また違う料金体系です。ここでは説明を端折ります。

SpeedCurve | Pricing

料金表のうちSYNTHETIC MONITORING ONLYの方を確認します。この中でもプランはいくつかあります

  • Starter でも年額 $3600 => 月額日本円で3万円とかかかります
  • Pay-As-You-Go という使った分だけプランだと、最低 $20/month で始められます

Pay-As-You-Goだと 1チェック $0.01 なので、以下のような設定だと料金は $20 で収まります。

  • iPhone と PC Chrome の2端末
  • 1回のチェックで3回叩いて平均をとる
  • region は一つだけ
  • 自社サイトと競合サイト2つでそれぞれ 3 url

これにより 2端末 * 3回 * 1region * 3url * 3サイト = 54 checks/day = 1620 checks/month = $16.2/month

同じ設定で自社のだけ 1url増やすと6checks/回 * 30日 = 180 checks 増えるので、自社サイト 5 url くらいまでは $20範囲内。

終わりに

SpeedCurveの導入により以下の効果がありました。

  • いつでもサイト速度に関する推移が見れるので、何か変更が有った時にカジュアルに見れる。また、バジェットを設定しておくと定期的にメールが来る。それによりエンジニアが改善する意欲が湧きやすい
  • アクセサビリティやベストプラクティスの項目で、DOMの数や画像サイズや非同期読み込みについて可視化されるので、マークアップするデザイナさんともコミュニケーションが取りやすい
  • 同業他社との比較で弊社サイトが早くなっていることが可視化されると、社内のモティベーションが上がる(気がする)