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の数や画像サイズや非同期読み込みについて可視化されるので、マークアップするデザイナさんともコミュニケーションが取りやすい
  • 同業他社との比較で弊社サイトが早くなっていることが可視化されると、社内のモティベーションが上がる(気がする)

【hamakou108】中途入社しました。

みなさん、こんにちは!

先月からM&Aクラウドにジョインしました濱田です。 ネット上では hamakou108 という id で存在してます。

今回は自分が入社するまでの経緯と、実際に入社して分かったM&Aクラウドの良さについて紹介したいと思います。

入社まで

前職ではインターネット回線接続サービスを提供する会社で WEB エンジニアをしていました。

ユーザーの生活インフラに関わることもあり、堅牢なシステムを開発・運用する上で必要な技術が身につく環境でした。 一方で基準を満たしたドキュメントやエビデンスの作成など開発プロセス上の制約も多く、モダンさやアジリティを追求することは難しい環境でした。

そろそろ後者のスキルを伸ばしていきたいと考えていたとき、 Wantedly 経由で CTO の荒井さんからお誘いいただき入社する運びとなりました。

入社してみて

技術やプロセス、コミュニケーションの取り方まで様々な点で変化がありました。 自分にとって特に印象的だった点を3つ挙げてみます。

リリースサイクルの速さ

M&Aクラウドでは週に2、3度のペースでリリースを行っています。 不具合や仕様漏れが入り込まないように、自動テストやレビューは勿論、大きな機能追加の際にはチーム全員で確認会を行っています。

前職では数週間〜数ヶ月に1度のリリースが普通だったので、刺激的でしたね!

アーキテクチャに対するこだわり

速いサイクルで継続的に開発を行うためには、変更に強く、理解しやすいアーキテクチャが必要不可欠です。 M&Aクラウドは DDD や CQRS などの考え方をシステムに取り入れており、レイヤーごとの責務や依存関係に注意を払いながら開発を進めています。

また定期的に勉強会を行い、何か取り入れられそうなプラクティスはないか日々探求しています。

UX について全員で考える

M&Aクラウドの開発チームでは週に一度 UX 会議というものを開いており、世の中の色々な UX を取り上げてサービスに活かせる要素がないか議論しています。 また機能追加にあたってユーザーインタビューを行うなど、プロダクトアウトを避けるための取り組みも行っています。

会社としても『全員UX』というバリューを掲げており、開発チームの外からも積極的にサービス改善提案を受け付け、一丸となって UX の向上に努めています。

今後は

技術的なスキルに限らず、ドメイン知識も膨大な事業領域であるため学ぶことは尽きません。 これから次第に事業の規模も大きくなっていくと思うので、必要な情報を効率良くキャッチアップして事業の成長を支えられるように頑張りたいと思います!

弊社津崎・久保田がYoutube配信のオンライン勉強会で登壇しました。

新型コロナウイルス感染症(COVID-19)による影響で勉強会が自粛されるなか、Youtubeによるオンライン配信を行うケースがあります。 今回は弊社の津崎が2/27 スタートアップ×AWS オンラインLT大会 Coral Developers Night、久保田が2/25 Roppongi.vue #5Youtubeライブ配信でLT枠登壇をしました。

M&Aクラウドにおける
AWS ElasticBeanstalkの活用


津崎からは、弊社のサービス開始時から利用しているAWSのElasticBeanstalkを採用した事例の紹介です。 現在ではElasticBeanstalk以外にもLambdaとAPI Gatewayを利用したページへの移行なども進めています。

Nuxt.jsでCompositionAPIを使う

久保田からは、先述したLambdaとAPI Gatewayへの置き換えを実施しているアプリケーションであるNuxt.jsで、Vue.js version3から導入されるComposition APIを利用して開発をする話です。 現在はトップページをこのNuxt.jsにリプレースしていて、今後も順次Nuxt.jsによるページを増やしていく予定です。

最後に

AWSによるインフラやNuxt.jsによる開発に興味のある方はぜひご連絡ください!

www.wantedly.com

www.wantedly.com

社内勉強会で「現場で役立つシステム設計の原則」を読了しました。

こんにちは、M&Aクラウドのかずへいです。今日は弊社の勉強会の取り組みについて紹介ます。

勉強会について

M&Aクラウドでは、現在週に2度勉強会が行われています。水曜日にはフロントエンド勉強会と題して、主にTypeScriptやNuxt.js周りについて勉強していて、金曜日にはアプリケーション設計勉強会と題して、「現場で役立つシステム設計の原則」の輪読を行っていました。

弊社の提供するM&Aマッチングプラットフォーム「M&Aクラウド」はこの本に一部影響を受けて設計されている箇所があるので、メンバー全員に読んでもらっています。

一人で読むだけではなく、開発チームみんなで輪読することによって、「うちのコードのこの部分ってこの考え方で設計されているよね」「いまはこの設計になっているけど、こうしておけばもっと良かったかもしれないね」といった話しで盛り上がり、実際にその場でプログラムを一緒に読んだり書き換えたりということが起きるのでなかなかに有意義です。

本の内容の実践

実際にM&Aクラウドでは以下を実践しています。

  • ファーストクラスコレクション
  • 画面とオブジェクトの設計を連動させる
  • サービスクラスを分ける

ファーストクラスコレクション

ファーストコレクションクラスは配列などのコレクションを独自のクラスとして定義する考え方です。配列をそのまま使ってしまうと、その配列に大してロジックを書くことが出来ません。

同じ配列でもListとListで持つべきロジックは当然違うはずですよね。それをHumanList、ItemListとしてそれぞれクラスを作り、そこにロジックを書いていくという方法です。

qiita.com

このサンプルコードでは\IteratorAggregate, \ArrayAccess, \Countableを実装してクラスが配列として振る舞えるように実装しています。isEmpty()のような関数は配列にはありませんがファーストクラスコレクションにすると自分で足すことが出来ます。

M&AクラウドPHPで書かれていて、PHPにはGenericsが無いのでこういうコードを書くとロジックが重複しやすいという問題もありますが、そこは継承やtraitでうまく避けています。

画面とオブジェクトの設計を連動させる

どこまでがオブジェクトの知識でどこからが画面の知識なのかというのは、設計でよく議論になることかとは思います。M&Aクラウドでは、部分的にはありますが、この資料のような方法でオブジェクトの値を利用して画面が切り替わるように設計しています。

speakerdeck.com

サービスクラスを分ける

M&AクラウドではApplication層に

  • QueryService
  • CommandService
  • ScenarioService

という3つのサービスを作っています。ScenarioServiceクラスは買い手、売り手といったユーザー属性ごとに作られていて、ScenarioServiceがControllerに対してAPIを提供しているような形になっています。ControllerはScenarioServiceしか呼びません。

ユーザー属性ごとにScenarioServiceを作ることにより、Controllerは呼ぶべきScenarioServiceが決まっているので、本来そのユーザーが呼べない関数を呼ぶというようなことが無いのが良い点だと思っています。

まとめ

設計についての本をチーム全員で読むことにより、共通の認識が生まれます。 今の設計も人が考えたものも誰かが考えたものであって、より良い設計があればそれに変えていけるというふうにメンバー各人が理解して、今の設計を神格化しないというのが重要だし、そのためにも共通の認識づくりは大事ですね。 輪読するとたくさんのアイディアが出て良いです。

次の題材

次回からはこちらの本を読み進めていこうと思います。