【高速開発】開発環境のバグをチームSlackに垂れ流してノンストップ開発

# この記事の概要・目的

みなさんは、バグレポートツールを使っていますか？

この記事では、バグレポートツールを使って、開発環境のバグもslackに垂れ流すことの恩恵についての話をします。

弊チームでは、ファーストコミットから今に至るまで**ソースコードの7割をインターン生が書いている**のですが、どうやってそれが実現できたか？ということの一つのポイントがバグレポートツールでした。
Git/GitHubその他、slack等のコミュニケーションツール、CI（継続的インテグレーション）については、いわゆるWeb系のみならずSIerでも自然に使われるようになってきているかと思いますが、バグレポートツールはあまり導入していないところも多いのかなと思います。また、バグレポートツールを導入しているところであっても、開発環境のバグまで全て垂れ流している、という事は少ないかなと思っています。
しかし、**作業の行き詰まりを解消できる**という大きな利点があるので、多くの開発チームに積極的に紹介をしたいと思っています。この記事では、弊チームの実際の事例を通して、そのメリットを説明します。

## 概要図

<img width="924" alt="スクリーンショット 2018-12-09 19.08.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/94255/b59f48ae-fac4-6a59-25cd-f4d23b7e6ff8.png">

# バグレポートツールとは

この記事は「Bugsnagというツールを使ってSlackにバグを垂流す話」なんですが、そもそもBugsnagって大分類としてはどういうツールなんだっけ、と思いました。（私はわかってなかった）
「バグ管理ツール」という言葉を使うのかな、と思ったのですが、そうするとBugzillaとかバックログみたいなのがかかってきて、どうも違うっぽい。確かに、バグを管理するというよりは、報告・監視するのが目的なので、大分類としてはバグレポートツールというものに相当するようです。

バグレポートツールは、文字通りバグを報告してくれるツールで、Webアプリではサーバー側のエラーはもちろんのこと、クライアントのエラーも捕捉して勝手に通知をしてくれます。
Bugsnagとは：
https://techblog.lclco.com/entry/2017/01/31/233000

類似のサービスにはSentryなどがあります。

参考：Bugsnagのalternative
https://www.slant.co/options/9134/alternatives/~bugsnag-alternatives

# slackと連携するとどのようになるか？

Bugsnagでは、デフォルトではエラーを補足するとBugsnagのサービスに記録＋メールで連絡してくれますが、通知をslackに連携することもできます。詳細手順はBugsnagのページにあるのでそちらを参照頂くとして、slackに連携すると、このようになります…

<img width="779" alt="スクリーンショット 2018-12-09 9.58.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/94255/44c1d62d-6004-0cf0-5807-19017d5b68c4.png">

このような通知のdetailsをクリックすると、BugsnagのWeb画面で詳細を表示することができます：

<img width="1124" alt="スクリーンショット 2018-12-09 10.02.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/94255/2e1ab2cb-a637-8db8-3edc-c745869d6a93.png">

これは、本番やステージング等で意図せぬエラーの捕捉にも当然便利ですが、開発環境にも使えます。
実際、このエラーのRELEASE STAGESはdevelopとなっています。これが実は作業の効率化につながるのです。

ということで、最近（といっても実際に"分析"を行ったのは8月ですが…）の弊チームのバグを分析してみます。

# よくあるバグの紹介・分析

## よくあるバグ

**以下のような頻発系バグは、全部見て5秒（≒slackで通知が来て5秒）で仮説が２〜３個立ちます。**
※具体的なバグの内容についてはこの例ではPythonのエラーですが、他の言語・環境でも同様かと思います。

### １．★ ReferenceError: Uncaught ReferenceError: foo is not defined

→fooを使っているところでfooが未定義のエラーだね（当たり前）

### ２−Ａ．★ Neither 'BinaryExpression' object nor 'Comparator' object has an attribute 'selectable'

→（要するに）期待する型が違うね（当たり前）

### ２−Ｂ． 'NoneType' object has no attribute 'strftime'

→ぬるぽのPython版みたいなものだね
※strftime以外もあります。

### ３−Ａ． sqlalchemy.orm.exc.NoResultFound: No row was found for one()

→SQLAlchemyでデータを取ってくるところのエラーだね（当たり前）
→多分データの不整合か、存在しないデータを取得しようとしているね

### ３−Ｂ． sqlalchemy.exc.ProgrammingError: 1054 (42S22): Unknown column 'foo.bar' in 'field list' ...

→SQLAlchemyでデータを取ってくるところのエラーだね（当たり前）
→だいたいの場合はalembicを実行してないね

### ４．★ jinja2.exceptions.UndefinedError: 'foo' is undefined

→Jinja2（テンプレート）で使っている変数fooが未定義のエラーだね（当たり前）

## Bugsnagにより作業者が受ける恩恵

まず、これらのエラーは、上で実際に見たように、すぐに問題点を指摘できるエラーです。多くの場合は、すぐに解消するのですが、もしこれらが繰り返し起こっているような場合には、**作業者に直接声をかけて解消する**ことができます。
また、バグが出る頻度は概ね作業に比例するので、あまりバグが出ていないと、**この人の作業は止まっていないかな？というようなチェックもできる**ようになります。
これはリモートでも有効なので、時差がなければ**進捗や詰まりを見にくいリモートでも作業を進めやすく**なります。
冒頭の概要図のとおりですね！
（再掲）

<img width="924" alt="スクリーンショット 2018-12-09 19.08.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/94255/b59f48ae-fac4-6a59-25cd-f4d23b7e6ff8.png">

現在、うちのチームでPythonの開発中に出るバグの８割以上は上記のいずれかに該当するので、つまり8割以上は即座に解決できるというか、ある意味で作業中に出て当然というバグですね。（実際、上のスクリーンショットのエラーも、invalid syntax以外は全てここに挙げたエラーなのでした。）

また、残りの「難しいバグ」についても、普段に見ないバグが流れてきたということで注意することができます。いずれにしても、画面に向き合って作業をしている今の状況をリアルタイムに流すツールとして、**一種のコミュニケーションの道具としての価値もある**のです。
私はシャイなのでペアプログラミングとかはつらいのですが、これなら自分のタイミングで見てアドバイスをすることができます。作業の妨げにならずにサポートができる、便利ツールですね。

これは大きな恩恵が得られます。


と、ここまでで話を終えてもよいのですが、せっかくバグをまとめたので、もう少し教訓じみたことについて突っ込んで考えてみます。

## エラーの突っ込んだ解説

### 感想

- エラーの英語は単刀直入に事実を述べていて、読むとそのまんまだね
- 静的型付けがあるとランタイムエラーはけっこう無くなるよね
- FW的なものの仕様を理解しているかいないかで原因を瞬時に判断できるかどうかが変わるものが結構あるよね

### （主に型の観点からの）ランタイムエラー防止に向けた解説

まず、前提というか当然の事ですが、**エラーの説明は事実を端的に正確に述べています。**エラーの文章を読むのはとても大事ですね。英語で書いてあっても身構えず、普通に日本語に訳して考えるとかなり親切な事を言っています。まずはそのことに注意しましょう。

その上で、エラーをコーディング時にどれぐらい防げるかということについて、（Pythonは型宣言を必要としない言語ですが）型や変数定義の観点で考えてみます。１は変数定義を強制すればこのタイプは無くなります。型を付けると２−Aのパターンもだいたい消えます。
4も、Jinja2（テンプレートエンジン）に渡すインターフェイスの定義という意味では、だいたい消えます。
型によって、やはりランタイムエラーをある程度防止することが可能であることがわかりますね。

一方で、３−Ａや３−ＢはDB起因なので、残念ながら型ではどうにもなりません。（例えばJavaでも類似の例外はよく出ます）

３−Ｂで自分のスキーマが古い事をすぐに疑えるかどうか？はSQLAlchemyの慣れ・経験かもしれません…というのも、このエラーは、（少なくともうちの書き方では）modelが間違ってないと出ない例外で、queryする側で取得するアトリビュートが間違っていてもこのエラーにはならないからです。（クエリだけでモデルと合ってないフィールド書くと２−Ａが出ます）
でも、経験と言っても、一ヶ月ぐらいずっと触っていればだいたいわかります。
ただ、インターン生を中心に回すには、自然に慣れるまで待つよりも、最初にひっかかったタイミングでこういうバグだよと教えて、学んでもらった方が効率がよくなるので、それをslackで捕まえて説明しています。

※スキーマ云々について…弊チームでは一人一インスタンス（以上）渡して作業をしており、他の人がPythonのソースコードを更新すると各々のスキーマとソースの間にずれが発生します。migrationをalembicで管理しているので、alembicを実行すると直ります。

# 「Bugsnagのおかげ」だけではないんだけど…

ここまで、slack×Bugsnagを通して、運用だけでなく開発の現場においてもやれる事の可能性を示しました。
実際、これでどれぐらい効率が改善しているのか？という事を直接示すのは難しいのですが、弊チームの一つのサービスのコード量スタッツを以下に示します。
ファーストコミットから約1年半です。

![lines_of_code.png](https://qiita-image-store.s3.amazonaws.com/0/94255/126f7e13-3a3d-03b5-eb58-5d0a07ef3d7a.png)

途中ぼこっと上がっているタイミングは、一部の不要なtsファイルやuglifyされていないwebpackのファイルなどによるものなので無視すると、概ね線型の進捗であることがわかります。
これまでインターンを中心に回していて、**コミッターは20人**おり、去年の春・去年の秋・今年の春・今年の秋でメンバーがざっくり4回入れ替わっていますが、継続的に開発が進んでいます。
メンバーが入れ替わったり、あるいはそれぞれの人が週１〜２回しか参加しない場合でも開発を止めない為には、コーディングを止める微妙な障壁の解消が必須で、弊チームの場合ではslack×Bugsnagが管理や作業進捗の把握まで含めて非常に重要なツールになっています。

一日250バグまでは無料で使えるので、大変おすすめです。
チームの開発環境を改善しましょう！
https://www.bugsnag.com/

おしまい。