Slide 1

Slide 1 text

レガシーチームでテストを書いた話 2018/12/17 ⾕⼝ 英司 1

Slide 2

Slide 2 text

⽬次 レガシーチームとは︖ 背景 転機 テスト駆動開発の勉強会 製品コードへの適⽤ 今後の課題 まとめ 2

Slide 3

Slide 3 text

レガシーチームとは︖ レガシーチームとは、レガシーコードを書いているチームのこと レガシーコードとは、テストのないコード (※) のこと ※「レガシーコード改善ガイド」より 3

Slide 4

Slide 4 text

背景 4

Slide 5

Slide 5 text

私とテスト 2014 年頃まで C/C++ でコンシューマ向けアプリのライブラリ開発 テストは CppUnit を利⽤して⼿元で実⾏ テスト対象は書き易いところだけ 2015 年頃から JavaScript でサーバの API 開発 テストは Mocha を利⽤して⼿元と Jenkins で実⾏ テスト対象は基本的にすべてのコード 5

Slide 6

Slide 6 text

プロジェクト概要 プロジェクトは モバイルアプリチーム サーバチーム: ⾃分が所属 ゲートウェイチーム: 今⽇の主題になるレガシーチーム の三つのチームで構成されていた。 それぞれの関係は以下のようになっている。 エンドユーザ <-> モバイルアプリ <-> サーバ <-> ゲートウェイ <-> 周辺 機器 6

Slide 7

Slide 7 text

ゲートウェイ ゲートウェイは、 周辺機器の情報を集めて、サーバに通知する サーバからの通知を受けて⾃⾝や周辺機器の設定を⾏う といったことを⾏う組み込み機器で、⾔語は C/C++ を⽤いて開発され ている。 7

Slide 8

Slide 8 text

これまでのゲートウェイの開発⼿順 ⼿順 およその時間 コードを書く 内容による コンパイル ⼗数秒から⼗数分 ファームウェア転送 1-2 分 ゲートウェイ再起動 1 分程度 動作確認 内容による このように書いたコードのフィードバックが得られるまでとても時間が かかっていた。 8

Slide 9

Slide 9 text

課題に感じていた部分 実装した内容を⼿元の PC ですぐに動作確認できない 実際のサーバや周辺機器と結合するまで動作確認できない まとまった分量の機能を実装するまで動作確認できない 途中経過が確認できないまま進むので不安がある 動作確認時にログ出⼒の書式ミスでクラッシュなどのつまらないミ スがあるとやり直しが⾟い 最終的には結合試験が必要だが、当時は結合試験以外の確認⼿段がなか った。 9

Slide 10

Slide 10 text

転機 10

Slide 11

Slide 11 text

新しい機器への対応 ゲートウェイが新しい機器に対応する要望があり、その機器との対話部 分は 新規に開発が必要 そこそこの開発ボリューム になることが解っていた。他の部分との依存関係が相対的に少ないた め、テストを書き易いと考え画策を始めた。 11

Slide 12

Slide 12 text

作戦 本や資料を紹介してテストを書くように指⽰しても途⽅に暮れるだろう と考え、 勉強会で座学と実践を⾏いテストになれる 製品コードでテストを書く際にフォローする という⽅針で進めることにした。 12

Slide 13

Slide 13 text

テスト駆動開発の勉強会 13

Slide 14

Slide 14 text

勉強会 全体で 2 時間 最初の 30 分でテスト駆動開発の導⼊ 残りの時間はテスト駆動で開発していた⼈間とペアを組ませて簡単 な問題をテスト駆動で解かせた ⾔語はなじみのある C/C++ テストフレームワークは Google Test 14

Slide 15

Slide 15 text

テスト駆動開発の導⼊ 「テスト駆動開発/Kent Beck」を下敷きにして下記を伝えた 最初に失敗するテストを書く テストを通す最短の実装を書く Red, Green, Refactoring のサイクルを素早く回す Fizz Buzz を題材にして実際にテスト駆動開発を実演して⾒せた かなり愚直にテスト駆動開発の⼿順をなぞった 題材が簡単だったので直ぐに正しい実装が解り、あまり良い題材 ではなかったかもしれない 15

Slide 16

Slide 16 text

テスト駆動開発の実践 題材として下記の課題を⽤意しておいた。 階乗 (factorial) フィボナッチ数列 ( bonacci) 素数判定 (prime) 三⾓形の判定 (triangle) 三辺の⻑さを与えた時に三⾓形の種類を判定する ※ 課題に使った問題を下記に置きました。 https://github.com/eijit/tdd 16

Slide 17

Slide 17 text

勉強会の振り返り 会議室に⼈数分の PC を⽤意できなかったため、テスト駆動開発の実践 時には、⼀部のペアは各⾃の席に戻ってコーディングを⾏った。 (Good) 疑問点をその場で聞いてくれた (Bad) 様⼦を⾒に時々巡回する必要があった (Bad) 巡回の際に私のペアを⼀⼈で放置することになった (Bad) ⼀体感が薄れてしまった 課題を多く感じた。テスト駆動開発を体験してほしい⼈は 4 ⼈だったの で、モブプログラミングで取り組んだら良かったと今になって思う。 17

Slide 18

Slide 18 text

製品コードへの適⽤ 18

Slide 19

Slide 19 text

経験者の参加 開発ボリュームの都合もあり、サーバチームで⼗分にテストを書いてき た開発者が、ゲートウェイチームに参加してくれることになった。 テストの書き⽅のお⼿本 Google Test/Mock の使い⽅ 設計やコードのレビュー などテストに限らず様々な助けとなってくれた。 19

Slide 20

Slide 20 text

ペア作業 勉強会の課題と製品コードではかなりのギャップがあるので、しばらく ペアで作業して⼀⼈で進めるようになるまで⾒守ることにした。 2-3 ⽇の間は半⽇ほどつきっきり 開発対象について対⾯で説明してもらう 開発対象を、テストを書ける粒度まで複数のタスクに細分化する 解らないことがあったら聞いてもらう コーディングの様⼦を⾒て変なところがあったら⽌める という点に気を付けた。 20

Slide 21

Slide 21 text

タスクの細分化 やったことのない作業だったためか最初は⼾惑いがあって 粒度が⼤きすぎ、⼩さすぎ 粒度がそろっていない 書いていいこと、書かなくていいこと といった振れ幅があったが、何度か繰り返すうちに落ち着いた。 完了したタスクを消していくと達成感があってよかった。 21

Slide 22

Slide 22 text

テストのためという割り切りの判断 テストを通すために割り切った判断や汚い実装を⾏う必要があったが、 ⼀⼈では悩むことがあった。必要な割り切りである、と前置きして解消 ⽅法を伝えた。 別ファイルで宣⾔されたグローバル変数のリンクが解決できない テストファイルで別の実体を宣⾔する 別ファイルで宣⾔されている定数を利⽤したいが include が困難 同じ値をテストファイルで定義する 練習⽤の課題とは違って綺麗な世界ではないので、妥協する場⾯もあっ たが、理由を説明して対処⽅法を伝えるうちに慣れてくれた。 22

Slide 23

Slide 23 text

どう変わったか たまたま後ろを通りかかったときに Google Test の結果がディスプレイ に表⽰されていたので、ある程度は定着したと思う。単体テストを導⼊ したことによりこまめに動作確認できるようになった。 ⼿順 およその時間 コードを書く 内容による コンパイル ⼗数秒以下 単体テスト 数秒 書いたコードのフィードバックを得られるまでの時間が⼗分に短縮され た。 23

Slide 24

Slide 24 text

今後の課題 24

Slide 25

Slide 25 text

今後の課題 今回は新規開発に近い部分だったため、適⽤しやすかった⾯がある。 既存のレガシーコードでどうやってテストを書くか テスト駆動開発がよい設計を導く、とはいかなかった 妥当なテストをどうやって書くか を今後の課題と感じている。 25

Slide 26

Slide 26 text

既存のレガシーコードでどうやってテストを書 くか 既存のコードもテスト可能領域を広げられないかと少し取り組んでみた が 全体をリンクすると PC で実⾏可能でないコードやライブラリを含む ⼩さく始めようとして、テスト対象が依存しているコードを追加し ていくと終わりが⾒えなかった と、今の⼿持ちの道具では太⼑打ちできそうになかったので「レガシー コード改善ガイド」を読み始めた。 26

Slide 27

Slide 27 text

設計 「テスト駆動開発」のように徐々にいい設計が導かれていく、というわ けにはいかなかった。開発のサイクルが早く回せるようになった分、経 験の浅いメンバは⾼速に間違った⽅向に進む可能性があるので、チーム でフォローしていく必要がある。 以前からレビュー会の習慣があったおかげもあり 難しい部分や情報を共有したほうがいい部分については、レビュー 会を開く レビュー会で設計について議論する ということが⾃発的に⾏われていたのはよかった。 27

Slide 28

Slide 28 text

妥当なテスト 設計とも似た課題で 無駄なテスト 重複したテスト そこで調べるべきではないテスト ⾜りないテスト モジュールの責務を表現しきれていない といった妥当なテストを書く難しさがあったが、レビュー時に経験豊富 なメンバの指摘で徐々に軌道修正されている。 28

Slide 29

Slide 29 text

まとめ 今⽇は (組み込み開発でありがちな) レガシーコードで開発する際の課題 課題への対処の⼀例としてテストを書く⽅法を挙げた テストを書くことを習慣づける⽅法 簡単な課題でテストを書く練習を⾏う 製品コードでテストを書く⼿助けをする を紹介した。 29