リリースタグとリリースノート作成の半自動化でリリースサイクルを改善した話

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

近年 DevOps の文脈で開発生産性の指標としてリリース頻度が注目されています。 DevOps Research and Assessment が提供している State of DevOps Report 2019 ではハイパフォーマンスな開発チームに顕著なメトリクスとして、リードタイムや復旧時間などと並びリリース頻度が紹介されています。 またリリース頻度の向上や付随する障害リスクの低下を図るためのプラクティスについて多くの議論が行われています。

M&Aクラウドでもリリースを高頻度かつスピーディーに実施するため、リリース作業をできるだけ自動化するように工夫しています。 以前にデプロイの半自動化の事例について鈴木から紹介しましたが、今回はリリースタグおよびリリースノートの作成などのリリース準備作業の半自動化を行った事例について紹介したいと思います。

リリース準備作業で抱えていた課題

M&Aクラウドの開発チームにはリリース準備の作業効率に関わる二つの問題がありました。

手作業に伴うミス

弊社ではブランチ管理の手法として Git Flow を採用しています。 Git Flow は gitflow コマンドを利用することで比較的簡単に実践することができますが、それでも作業時のミスは発生しがちです。 例えばローカルの develop ブランチの内容が古い状態で release ブランチを切ってしまったり、 release と hotfix の作業手順を混同してしまったり、タグ名の形式を誤ったり1など、数え上げたらキリがありません。。

また初めてリリース作業を行うメンバーの場合、ローカル環境で gitflow のインストールや初期化が済んでいないといった別の問題も発生していました。

このようにリリースの準備作業は全体的に注意が必要な心理的ハードルの高い作業になっていました。

作業時間

リリースブランチの作成、リリースに含まれる PR のリスト化、リリースブランチのマージ、タグ作成までの一連の作業をマニュアルで実施するとそれなりに時間が掛かります。 特にリリースノートの作成に関してはどの PR が含まれているかコミット履歴を辿らなければならず、面倒な作業でした。 これらの作業によってリリース作業の担当者は普段の開発に掛けられる時間が大幅に減ってしまうことも問題でした。

スクリプトによる作業自動化

これらの作業手順はほぼ定型化されていたため、大半の作業をシェルスクリプトで自動化することで課題解決を図りました。 幾つかキーポイントとなる部分をコードスニペットと共に見ていきたいと思います。

事前要件のチェック

function checkRequirements() {
  if [[ ! "$OSTYPE" == "darwin"* ]]; then
    echo "MacOS を利用してください。" >&2; exit 1
  fi

  if ! type git > /dev/null; then
    echo "Git をインストールしてください。" >&2; exit 1
  fi

  if ! brew ls --versions git-flow > /dev/null; then
    echo "Git Flow をインストールしてください。" >&2; exit 1
  fi
}

function checkoutAndPull() {
  git checkout master
  git pull upstream master
  git checkout develop
  git pull upstream develop
  git fetch upstream
}

checkRequirements() では Git や gitflow など必要なツールがインストールされているか確認しています。 見て分かる通り MacOS に限定した実装にしていますが、これは現時点で開発者全員が Mac ユーザーであるためです。 複数の OS に対応した汎用性の高い実装にすることも可能でしたが、直接的に事業価値に貢献するコードではないので少ないコストで実装できる仕様を採用しました。 YAGNI です。

さらに checkoutAndPull() ではリモートリポジトリの pull を行い、ローカルリポジトリの内容が古いまま作業してしまうことを防止しています。

リリースに含まれる PR のタイトルとリンクの抽出

function printPullRequestToBeReleased() {
  local repositoryName
  local prevRelease

  repositoryName=${1}

  read -r -p "${repositoryName} の前回のリリースタグを指定してください: " prevRelease
  echo "${prevRelease}"
  git log "${prevRelease}".. --merges --first-parent --reverse --pretty=format:"* %b %s" | \
    REPO="${repositoryName}" perl -ple 's/Merge.*#(\d*).*$/(https:\/\/github.com\/your-organization-name\/$ENV{REPO}\/pull\/$1)/' | \
    perl -ple 's/\*\s(.*)\(h/\* [$1]\(h/'
  printf "\n\n"
  read -r -p "上記のリストをコピーしておいてください"
}

printPullRequestToBeReleased() では前回のリリースタグ名を指定するとそこから最新のコミットまでに含まれる PR のタイトルと URL をコミット本文から抽出して Markdown のリスト形式で出力します。 出力されたリストをそのまま利用するだけで簡単にリリースノートが作れます。

release ブランチの作成、マージ、タグ作成

function startRelease() {
  local repositoryName
  local currentRelease

  repositoryName=${1}

  read -r -p "${repositoryName} の「今回の」リリースタグを指定してください。空なら今日の日付が使われます: " currentRelease
  if test -z "${currentRelease}"; then
    currentRelease=$(date "+%Y-%m-%d")
  fi
  echo "${currentRelease}"

  git flow release start "${currentRelease}"
  git push upstream "release/${currentRelease}"
}

function finishRelease() {
  local repositoryName
  local releaseBranch

  repositoryName=${1}
  releaseBranch=$(git branch | egrep -o "release\/[0-9]{4}-[0-9]{2}-[0-9]{2}.*")

  if [[ -z "${releaseBranch}" ]]; then
    echo "リリースブランチが存在しません。" >&2; exit 1
  fi

  git checkout "${releaseBranch}"
  git pull upstream "${releaseBranch}"
  git flow release finish "$(echo "${releaseBranch}" | perl -ple 's/release\/(.*)/$1/')"
  git push upstream master
  git push upstream --tags
  git push upstream develop
  git push upstream --delete "${releaseBranch}"
}

startRelease() で release ブランチの作成を行います。 特に指定がなければブランチ名は release/YYYY-MM-DD のような形式で作成され、忘れがちなリモートリポジトリへの push も自動化しています 2

また finishRelease() で release ブランチのマージ、タグ作成もスクリプト化しました。

スクリプト導入の結果

スクリプトを作成したことで前述した課題を次のように解決することができました。

  • 事前要件を満たせていない場合はスクリプト実行不可とすることで環境依存の問題を防止。
  • Git 操作をスクリプト内で完結させることで手順の誤りによるミスを解消。
  • リリースノートの作成なども含め、自動化した部分の作業時間は1-2分にまで短縮。

まとめ

リリースタグおよびリリースノートの作成をスクリプトで半自動化することで、環境依存や手作業によるミスを軽減し、作業時間も短縮することができました。 作業効率に加えて DX も向上させることができましたが、まだ幾つかマニュアル作業も残っているので今後もリリースサイクルの効率化を適宜進めていきたいと思います。


  1. 弊社ではタグ名を特定のフォーマットとした場合に CircleCI のリリース専用ワークフローが実行されるようにしているため、名前を間違えるとタグを切り直さなければならない場合があります。

  2. ちなみに hotfix のフローに関してもほぼ同様にスクリプト化してあり、リリースフローによって使い分けています。

施策の効果測定のためにRedashを導入しました。

f:id:kazuhei0108:20200804104002p:plain

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

弊社では5月頃から、開発の施策立案と効果測定のためにRedashの導入を進めているので、その活用方法を紹介します。

Redash導入前の課題

そもそも、開発チームとして以下のような課題がありました。

  • 開発チームの成果が事業貢献ではなく、リリースした機能の数で評価されがち。
  • リリースした機能の貢献が分からない。
  • リリースした機能が、開発されっぱなしで、その後ユーザーに受け入れられているかどうか確認するサイクルがなく、その後の細かいチューニングもされたりされなかったりしている。

これらの問題は、

  1. 事業上の目標(売上等)が数値ベースでプロダクトの指標(PV、UU、登録数、クリック数)に落とし込めていないこと
  2. 指標を継続的に計測する手軽な仕組みがないこと

が原因です。

1が出来るようになるためにも、とりあえず2の計測の仕組みが必要になります。計測の仕組みが整備されてようやく事業の数字とプラットフォーム上の指標がどう連動しているかが見えてくるようになるからです。

このために導入したツールがRedashでした。

Redashとは

RedashはオープンソースのBIツールで、SQLを使って様々なデータソースからデータの取得、整形、可視化ができます。

github.com

Redashの導入

RedashはAWS上で構築しました。 Setting up a Redash Instance こちらからAMIを選択して起動すると設定無しでログインするところまで行けます。

マネージドのRedashについて

redash.io

こちらでRedashを簡単に試すことが出来ます。料金もそれほどではないので、インスタンスのお世話をしない分こちらの方が楽なんじゃないか?と初期はこちらを検討しました。

しかし、少し試してみたところ、

  • 外部のサービスをRDSに直接繋がなくてはいけない
  • redash.ioのリージョンがアメリカ?にあるので、日本にあるRDSにつなげると地味に遅い

などの問題があったため、自前でインスタンスを設定することにしました。

Redashのログイン周り

RedashにはGoogleログインがあり、弊社では全てのメンバーがGSuiteのアカウントを持っているため、とても簡単にログインの設定をすることが出来ました。また、GSuiteのアカウント自体に多要素認証が設定されています。

また、Redashではデフォルトユーザーの権限が大きいのですが、社員誰でもなんでも見られるというようにはしたくなかったので、デフォルトの設定を変更しています。

詳しくはこちらの記事を御覧ください。

qiita.com

Redashの活用

データへのアクセスは

  • 手軽であること
  • 即時性があること
  • 1箇所にまとまっていること

がとても大事だと実感しています。 Redashでは簡単にこれらを達成することが出来ます。

どんなサービスと連携させているか

弊社ではRedashでいろんなデータソースからデータを取っています。 Redashの便利な機能として複合クエリーという複数のデータソースから取ってきた結果に対して更にクエリーを書くという機能があるのですが、それを活用すればGoogleAnalyticsのデータとMySQLのデータをJoinしてグラフ化するといったことも可能になります。

主に以下のようなデータソースと連携させています。

どんなダッシュボードを作っているか

弊社では

  • 定期的に数値を確認するためのダッシュボード
  • 施策の結果を見るためのダッシュボード

の2種類に分けて運用しています。

定期的に数値を確認するためのダッシュボードは、目標として置いている数字を追いかけるのに使ったり、サービス上の異常を検知するのに使います。

施策の結果を見るためのダッシュボードは、最上段にどんな施策をいつ実行して、どの指標がどれくらい向上するのを期待するのかというリストがあり、その下に実際の計測指標があります。

f:id:kazuhei0108:20200804100037j:plain
施策ダッシュボードの例

リリースした機能を週次で確認し、ユーザーに受け入れられているか、期待した効果が出ているかを確認しています。

どうやって運用しているか

RedashをSlack連携することによって、定時にRedash内の指標をSlackに通知してもらようにしています。

これはGunosyさんのブログを参考にしていて、手軽にSlackで定期的に数字を見るようになります。

data.gunosy.io

社内布教活動について

Redashの導入とともに布教活動を行いました。

  • エンジニア向けRedashの使い方
  • 非エンジニア向けデータベースの構造とSQLの書き方
  • 非エンジニア向けRedashの使い方

エンジニア向けのものはもちろんですが、これを機に非エンジニアにもSQLに触れてもらうことにしました。

導入した結果と今後

Redashの導入により、指標を継続的に計測する手軽な仕組みを手に入れることは達成できたのではないかなと思います。 目標の数値が毎日更新され定期的にSlack通知される事により、メンバーの数値への意識も向上しました。

また、開発メンバー以外にもSQLを書くメンバーが出始めたのはとても良い兆候だと思っています。

これからは、Redashでの可視化をより精緻化するとともに、より事業理解を深めて、事業の目標とサービス上の指標の紐付けを進めて行くことで、事業貢献が見える開発が出来るようにしていきます。

プロダクト開発で重要なことは兎に角ユーザーヒアリングをすること

f:id:yokotinnn:20200712185252j:plain

こんにちは。M&Aクラウドでプロダクトマネージャーをやっている横田です。 先月シリーズBの投資ラウンドで2.2億の資金調達のプレスリリースを終えて従業員も約30人にまで増え、2年前に僕が入社を決めたときにはまだ社員が4名しかいなかったことにとてもなつかしさを憶えています・・・

prtimes.jp

そんな絶好調のM&Aクラウドですが、今日はプロダクト開発においてどんなサービスでも必ず直面する「使ってもらえる機能開発をするためにはどうすれば良いか?」という命題について、「ユーザーヒアリングがとても重要」だという話をします。

特に、今年の2月にリリースをした「クローズドプラン」というM&Aクラウドの新機能ができるまでのプロダクト開発の過程(特にヒアリングについて)をご紹介したいと思います! macloud.jp

このブログで伝えたいこと

  • ユーザーヒアリングを軽視してプロダクト開発をするとひどいことになる笑
  • ユーザーヒアリングは「事前準備」と「試行回数」につきる
  • オペレーションの構築まで考え抜いた開発を行う

1分で分かる背景

M&Aクラウド「会社を売りたい起業家が買い手に直接アプローチすることができるプラットフォーム」という新しい体験を売りにしているベンチャー企業です。 「買いたい」という企業(一流・優良企業ばかり)がまるで「リクナビ」のようにM&Aニーズを掲載しているところがポイントなのです。

macloud.jp

しかし、「M&Aニーズを掲載する」というのはいままでの日本の商習慣では存在せず、「顔出しNG」という理由で、M&Aクラウドへの掲載を断られることがとても多いのです。
※とはいえ、徐々に世間の認識を変えられてきているのか、M&Aクラウドの掲載社数は順調に成長しており、2020年6月は過去最高の掲載売上を記録

そこで「買い手が掲載せずともM&Aクラウドのサービスを利用できる機能を開発したら、もっとプロダクトが成長するのではないか」という仮説のもと、このプロジェクトはスタートしました。

クローズドプランの前身である「トライアルプラン」の"失敗"

f:id:yokotinnn:20200713173336p:plain

実はクローズドプランを開発する前に、営業チームの日々の営業活動の報告結果から「顔出しNG」でお断りされるのは体の良い方便で、本当は「もっと気軽にM&Aクラウドのサービスを利用できるようになれば利用社数は増えるのではないか?」という仮説を持っていました。

そこで、「トライアルプラン」という、従来のM&Aニーズを取材してプロのライターが掲載記事を書く方法ではなく、買い手企業が自らM&Aニーズを書き宣材写真等を準備する代わりに、初期費用が無料になるプランを立案して開発をしました。

f:id:yokotinnn:20200712211522j:plain ※料金体系等は当時のものなのでご注意ください。

このプランはWantedlyのように、求人の募集記事を自ら運用するUXがワークしていることをヒントに立案をしました。 しかし、実際に機能をリリースしてみると、申込企業数は月に数件あれば良いところで、かつ実際に利用を表明した企業も、ほとんどが掲載までは至らず、途中の掲載記事作成の時点で歩留まりしてしまいました。
実際に掲載を開始しても、ほとんど売り手企業から売却打診をされず、また無料でスタートしているためかモチベーションがそこまで高くなく、売り手への返信が遅いなど、プラットフォーム全体のUXを損ねる結果ばかりを生み出しました。
トライアルプランは見事に、作ったけど「使ってもらえない機能」でした。

この機能開発での失敗点は以下だと内省しています。
* 課題に対する仮説を正しいと信じ込んでしまい、いわゆるProblem/Solution Fit(プロブレム・ソリューション・フィット)を疎かにしてしまった * 課題に対するソリューションの筋が良くなかった(特にビジネスオペレーションを軽視してしまった)

致命的だったのは、実際に作ったプロダクト(もしくはモックアップやプロトタイプ)を実際にユーザーが使ってくれそうかどうかヒアリングすることなくリリースをしてしまったことです。
Wantedlyは人材サービスであり、M&Aとは異なる性質であるのにも関わらず、「そこまで大きな負担ではないから、これぐらいならやってくれるだろう」とタカをくくってしまったのです。
また、プロダクトとオペレーションの作り込みも甘く、実際に作り始めたユーザーへのサポートも出来ていませんでした。
結果として、「使ってもらえない機能」になることは必然だったのです。

新たに開発をした「クローズドプラン」

f:id:yokotinnn:20200714143439j:plain トライアルプランの反省を踏まえて、ユーザーにとってのソリューションは、気軽に掲載まで無料でできることではなく、純粋に「顔出しNG」であることが多いのを解決する機能なのではないかとふりだしに戻りました。
そこで、次なる機能開発では、買い手企業が"会社情報を一般公開せずに"売り手企業に直接アプローチすることができる機能が、買い手企業のペインを解決するソリューションであるという仮説を持って取り組みました。
M&Aクラウドのビジネスモデル上、一見従来の「掲載プラン」の持ち味が失われてしまう機能ではあるもの、まずはプラットフォーム自体を使ってもらうことでM&Aクラウドの満足度を上げ、そこからのアップセルで「掲載プラン」を利用してもらおうと考えたのです。

また、同様にプロダクト開発面での反省を活かして、以下を心がけました。

  • 仮説の確からしさをきちんと検証するために、ユーザーヒアリングを徹底して行うこと
  • プロダクトリリース後のオペレーションとモニタリング基盤を構築すること

ヒアリングの「事前準備」

サービス自体の新規開発を行うときはリーンスタートアップに倣いユーザーヒアリングを当然のように行うと思いますが、新規機能の開発(しかも規模の小さいスタートアップ)ではユーザーヒアリングを簡易に済ましてしまうことは多いのではないでしょうか。

クローズドプランは、買い手企業が"会社情報を一般公開せずに"売り手企業に直接アプローチすることができる機能です。
実は、クローズドプランのような買い手企業が匿名の売手企情報(業界用語でノンネームと呼ばれる)を見てスカウトをするというサービスは、すでに競合他社で前例があったのですが、トライアルプランと同じ轍を踏まないよう、M&Aクラウドだからこそ「使ってもらえる」機能を開発できるようにヒアリングに精一杯取り組みました。

M&Aクラウドのクローズドプラン」のペルソナは誰で、どういうペインを抱えているのか、その課題を解決できるようなソリューションは何で、考えているもので本当に合っているのかを明確にする必要がありました。

まず、ペルソナ像を3パターン作り、そのペルソナのすべてのパターンにヒアリングができるように営業チームと協力してヒアリングを行いました。

f:id:yokotinnn:20200712232758p:plain

さらには、毎回ヒアリングをする買い手企業を事前に調査して、企業毎に質問を変えて(ヒアリング対象企業の業種、インタビュイーの役職等を考慮)ヒアリングに臨みました。

<参考>ユーザーヒアリングシートのFMT

docs.google.com

ユーザーヒアリングの「試行回数」にこだわる

結果としてですが、クローズドプランの機能開発では、以下の企業数に1ヶ月間かけて徹底的にヒアリングをしました。

  • 買い手企業15社
  • 売り手企業6社

合計20社程度にヒアリングをしたことで、ヒアリング前に立てたペルソナやソリューションに自身が持てるようになりました。
よく、「ヒアリングは最低6社程度したほうが良い」と書籍等では書かれていますが、6社で止めていたら、アウトプットの質は変わっていたかもしれません。
また、人気の案件にスカウトを送ることができる「オプション機能」は他社にはないM&Aクラウド独自の機能であり、これはヒアリング結果からアイデアを得ることができました。

オペレーションの構築

トライアルプラン時にはとりあえず作ってしまった機能も、クローズドプランではしっかりとオペレーションを組んで、「何をどこまでやるか」ということを明確にして取り組みました。

各部関係者を巻き込んでオペレーションを構築し、事前に念入りに擦り合わせをした上でリリースを迎えることが出来ました。

<参考>オペレーションの整理 f:id:yokotinnn:20200712234712p:plain

クローズドプランの成果

結果として、クローズドプランはトライアルプランの20倍以上の利用社数を記録しており、毎月一定以上の安定した利用率で推移しています。
また、ヒアリングを基に開発した「オプション機能」も安定して申込がされており、アップセルや従来の「掲載プラン」へのアップグレードへのおためし機能として活躍し始めています。

最後に

このブログで記載した通り、機能開発時のユーザーヒアリングは非常に重要です。
そもそもすでに出来ているスタートアップ企業が大半だと思うので、当然のことを記載しただけのように見えると思いますが、今回は非常にわかりやすく「使ってもらえない」機能の開発→「使ってもらえる」機能への昇華を行えた貴重な体験だったので、共有をさせてもらいました。
引き続き、よいプロダクト開発をしていきます!

うっかりミスを防ぐ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と連携できる
  • 使い勝手はそこそこ

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