初めまして。Atrae Tech Blogでは初めての投稿となります。
転職サイト「Green」でバックエンドエンジニアをしている櫻井啓裕です。
2019年に新卒入社をして3年目になりました。普段はrailsを書いています。
今回はGreenチーム内で行ったバグ・不具合対応(オンコール対応)の改善について書こうと思います。
・オンコール担当だが、一向にバグが減らない。
・ビジネスサイドとのやりとりが多く、問題解決への時間がなかなか取れない。
・あまりに発生する不具合が多く、管理が曖昧になりつつある。
といったようなお悩みの方には少しでも有益となる様なブログになればと思います。
改善する際に意識したこと
オンコール対応で一番重要なことはシンプルですが発生した問題をいち早く解決することだと思います。
そのために、必要なことはそれぞれの立場において以下だと思います。
・エンジニアサイドはシステムにおける問題を発見して解決すること。
・ビジネスサイドは状況を把握して、不具合が出てしまった顧客へ適切なコミュニケーションをとること。
それぞれの役割を全うするのにエンジニアからの現状共有を円滑に行うことは欠かせませんがそのコミュニケーションは問題発見・開発の妨げになると思います。
自分がオンコール対応をチーム内で任された際は社内で使用しているチャットツール内でタスク管理・状況報告等が行われていました。
多くのバグや不具合が発生した際はそれぞれの状況報告やビジネスサイドからの確認が相次ぎ、問題解決に集中できる状況を確保するのに苦戦していました。
そこで、発生した不具合がどの様な状態になっているかを可視化できる状態を作り、そのステータスがエンジニアの開発工程に応じて自動で変わる方法を模索しました。
使用したツール
slack ・・・ 社内で利用しているチャットツール。普段からここでコミュニケーションが発生しているので、今回もコミュニケーションのメインはslackで行う。
glitch ・・・ slackのチュートリアルでも紹介されているサードパーティのweb上で動くIDEです。使用しているツールを繋ぐAPIをここで開発しています。
clickup ・・・ タスク管理ツール。無料で人数やタスクの上限がなく、カンバン形式やリスト形式でタスクを一覧化できたため採用。apiのドキュメントもわかりやすくドキュメント画面でテスト送信できるのが開発しやすかった。
Github ・・・説明不要だと思います。今回はGithubのwebhookを利用します。
不具合対応の流れ
以下の様な流れで問題の報告を受けてから解決するまでのワークフローを作成しました。
①Slackでビジネスチームから報告を受ける(slackのワークフローを利用して提供してほしい情報を統一)
②slackから受けた情報をclickupに自動送信
③開発ブランチ名にclickupのタスクIDをつけるとclickupのステータスが開発中に変わる
④GithubにてPRをオープンにすると、clickupのステータスがレビュー中に変わる
⑤GithubにてPRをマージすると、clickupのステータスが本番反映待ちに変わる
⑥本番反映が完了したらslackにてビジネスチームに報告
それぞれのステップについて説明していきます。
①Slackでビジネスチームから報告を受ける(slackのワークフローを利用して提供してほしい情報を統一)
ビジネスチームからの報告をslackで受けます。 slackワークフローで入力されたものをチャットとして表示します。そのスレッドでその問題に対するコミュニケーションを基本的に行います。 報告内容はこちら
工夫した点としては、優先度とカテゴリです。
優先度を正しく決めることは非常に難しく、ほとんどが一番重要や緊急となってしまうと思います。 そのため、チームでは優先度を希望完了期日に対する遅延の許容度として定義しています。
・ Urgent: 全てのタスクを投げ出していますぐ対処してほしい
・ High: 期日を絶対ずらさないでほしい
・ Normal: 期日をずらすことは交渉次第で可能
・ Low: 期日をずらすことが可能
こうすることで、いつまでに何を対処できていないといけないかがビジネスサイド・エンジニアサイド共に共通理解が生まれます。
またカテゴリについては、対応するカテゴリを分けておくことで期やQ毎に振り返り、根本的に対応するところの洗い出しに役立ちます。
②slackから受けた情報をclickupに自動送信
slack api, glitchを利用して先程の情報をclickupに送信します。
slackで自分のアプリを作成し、以下の画面でアプリの起動条件を設定します。
認証周りのキーやアクセストークンを設定し、Glitch内でclickupにデータを送信できる様にデータ整形を行い、click up apiのドキュメントに従ってタスクを作成します。
glitchの一部コードをお見せします。
app.post('/create_task', async (req, res) => { console.log(req.body); // SlackEventsAPIの初期認証処理です。APIを有効化する際の初期設定に必要になります。 if(req.body.type === 'url_verification') { // リクエストbodyのchallengeという項目を返却します。 const json = { 'challenge': req.body.challenge } res.json(json); } // 自分のSlackアプリ以外からのリクエストを無視します。 if(!signature.isVerified(req)) { console.log('Signature is not verified.'); res.sendStatus(404); // 認証失敗時には、404 not found を返却します return; } // Slackからのリクエストに対して、処理を行います。 else { res.sendStatus(200); // Response Code: 200 をSlackに返却します。返却しないとSlackから複数回、同じリクエストが送られてきます。 // SlackEventsAPIで送られてくるリクエストの中から、不要なリクエストをフィルターします。 // bot以外のMessageの時、処理を中断。 if(req.body.event.subtype !== "bot_message") { return; } const json = format_clickup(req.body.event); //slackからのデータをclickupに送信する様にデータ整形するメソッド const postURL = process.env.CLICKUP_POST_TASK_BUG_URL; //環境変数でclick upのURLを指定しています。 axios.post(postURL, json, clickupHeader).then(response => {}).catch(error => { if (error.response) { console.log(error.response.status); // 例:400 console.log(error.response.statusText); console.log(error.response);// 例: Bad Request } console.log('Error', error.message); }); } });
③開発ブランチ名にclickupのタスクIDをつけるとclickupのステータスが開発中に変わる
clickupにはGithubとの連携機能があり、使用しているリポジトリとの連携をONにすると、commit,pull requestにタスクIDをつけることで自動でタスクとブランチor プルリクエストを紐付けてくれます。
詳しい連携方法についてはclick apiのドキュメントに譲ります。
④GithubにてPRをオープンにすると、clickupのステータスがレビュー中に変わる
こちらについては実現方法が2通りあります。
1.Clickupのautomation機能を利用する。
clickupには条件に応じて特定のアクションを自動で行ってくれるオートメーション機能があります(なんでも出来過ぎです。。)
Githubとの連携が可能なので、色々なことができます。
ここでpull requestを作成すると、ステータスを変更するを選択するといった条件を設定すると変更できます。
ただし、automation機能は無料アカウントだと回数制限があります。月10回しか起動しないため、無料アカウントではあまり現実的にワークしません。なので、次の方法で実現します。
2.GithubのWebhookを利用する。
おそらく、1のclickupのautomation機能はGithubのwebhookを自動で作成し、click upで特定のアクションを実行しています。(実際にGithubのwebhookを確認するとwebhookが作成されていました。)
そのため、Githubのwebhookとclick up のapiを利用するとautomation機能を自作することができます。
Githubでwebhookを作成します。送信先はglitchのURLです。
glitchでclick up の特定のタスクのステータスを変更するapiを利用します。 Githubの認証はこちらを利用しています。
app.post('/update_task', async (req, res) => { var xhub = require('express-x-hub'); app.use(xhub({ algorithm: 'sha1', secret: process.env.GITHUB_SECRET })); app.use(bodyParser()); if(!req.isXHubValid()) { console.log('Signature is not verified.'); res.sendStatus(404); // 認証失敗時には、404 not found を返却します return; }else{ res.sendStatus(200); if(req.body.action == "opened" && req.body.pull_request.title.indexOf('CU-') > -1){ const title_split = req.body.pull_request.title.split('CU-'); const task_id = title_split[1].substr(0, 6); // タスクIDを取得 const putURL = process.env.CLICKUP_GET_TASK_URL + task_id const putJSON = { "status": "5.REVIEW" } axios.put(putURL, putJSON, clickupHeader).then(response => {}).catch(error => { if (error.response) { console.log(error.response.status); // 例:400 console.log(error.response.statusText); console.log(error.response);// 例: Bad Request } console.log('Error', error.message); }); } } });
マージなども同様な手順で行います。
この様な方法を用いることで、エンジニアは基本的には開発工程を進めることで進捗共有もできる状態を実現しています。
今後の発展
共有方法にはまだ実現できていませんがもう一段階レベルアップすることができると思っています。
click upではwebhookを自作することができます。 slackからpostが飛んできた際にそのチャットのurlを取得することができます。(チャットのURLがhttps://#{スペース名}.slack.com/archives/#{チャンネルID}/p#{タイムスタンプ}で、タイムスタンプが情報として送信されるからです。) 従って、ステータスが変わるたびにそのスレッドへステータスが変わったことを自動で報告することが可能です。
ここまでくれば、わからないことや理想像をすり合わせるために発生する必要なコミュニケーションや問題解決に集中でき、進捗共有については自動化できると思っています。 click upをビジネスメンバーに見てもらうことや終了報告をすることでこの開発をせずにオペレーションがまわっていますが、slackで解決するとコミュニケーションとしては最適かなと思っています。
アトラエでは、この様に自分たちで課題と感じたことを自分たちで変えていき、理想の開発スタイル・開発体制・組織・事業・会社を探究し続けています。今回のケースは例としては大きなスケールのものではありませんが、僕たちはまだまだこれから大きなスケールのものを開発していきます!!
そんなアトラエに少しでも興味を持ってくださったら、是非カジュアル面談でお話しましょう!詳細は下記のスライドや採用サイトで確認できます!