また過去に参加した勉強会のメモ。今回のは3/11ともはや半年以上前...
まあもう諦めても良かったのだけど、9月頭 (これも1ヶ月近く前...) にあったprivate methodの件だったり職場で最近あったお話だったりがこの講演で扱われた話題に関連している気がするなあと感じたので、折角だしと思って掘り出してまとめることにした。
connpass.com
togetter.com
www.slideshare.net
転送サーバおけるテストの自動化 · GitHub
メモは最後に貼るとして、講演の内容の内2点について、この記事を書いている時点までにあったことも含めて思っていることをまとめる。これらを書いていて、半年以上前の講演で、それもスライドに残されていることではなくその場で話されていたようなことやそれについてその時感じたことなのに、今でもこうやって覚えていてそれなりな量の文章を書けるのは、自分にとってこの講演がそれほど感銘を受けるもので、その後の自分の考えや行動の指針となっているのだなあとしみじみ思ったのであった。
スライドにおける「リファクタリングのジレンマ」の部分。スライドにはこれだけしか書かれていないがこの会ではここを掘り下げた話があった。
リファクタリングを独立タスクにすると、そのタスクは着手されない
どういうことかというと、リファクタリングそれ自体はプロダクトに新たにビジネス価値を付与するものではなく、振る舞いを変えることなく内部を改善する「だけ」なので、「〇〇のリファクタリングを行う」とタスクとして独立してしまうと、他の新機能開発や機能追加・改修といったタスクに対して短期的な視点からエンジニアの自己満足とみなされたり早く顧客に新たな価値を提供したいというビジネス判断をされたりして後回しにされ続けてしまい、ついぞ着手されることなくTODOリストの奥底に沈み込んでしまう、ということだそうだ。
ではリファクタリングのビジネス的価値とは何かというと、中長期的に見て同様のタスクをこなすのにかかる時間を一定以内に保ち続けられるようにすることであるとのことで、つまりビジネスの進行に対するブレーキをプロダクト内に作らないようにすることと言える。
リファクタリングされないまま開発を進めてしまった場合どういうところに行き着くのか、というのは、最近だと以下の記事の「コードの乱れが生むもの」がイメージしやすく書かれていると感じた。
d.hatena.ne.jp
この記事によれば、行き着く先とは最早リファクタリングどころではなくなってまた一から同じシステムを作り直すという、開発にもビジネスにも多大なコストを支払わざるを得ない状況となる。計画された再構築でなければ実施しようとする頃にはそれをするにも心許ない、最悪実施すらできないような状況に陥ってしまっているというのは恐ろしい話である。
短期的には後回しにされがちだが、かと言ってしないままだとその内まずいことになるのでやらねばならないリファクタリングを、じゃあどうやって実施したらいいのかと言うと、日々の開発タスクの中に小さなリファクタリングをまぶして、日々の業務に改善を組み込んでいきましょう、とのことだった。
これは言われてみればなるほどその通りで、規模の小さい内に問題を潰せることができればその後起こりうる大きな問題 (大規模なリファクタリング) を未然に防げるだろうし*1、結局開発もリファクタリングもソフトウェアエンジニアとしてはどちらもコーディングタスクと見做すことができるので、あえて別タスクに分離して実施しなくても一緒にやってしまえばいいよな、と思う。
とは言うものの中々実行はされないもので、今の職場では割とカジュアルにリファクタリングを独立タスクにしていく傾向があり、見かねて一度「そういうのは良くないよ、こういう風に日々の開発タスクの中で少しずつリファクタリングしていきましょう」ということをプルリクエストで実例を紹介しつつ訴えかけたことがあった。その時はあまり注目されてないなーと思ったのだけど、2, 3人ほどそれ以降実践してくれているのを観測したので、文化を作るきっかけにはなったのかなと考えている。
この講演でも話されていたことなのだけど、本当は上記のように大勢に呼びかけるような方法というのは戦術的には筋が良くなくて、一人ずつ伝授していくようにできる人を増やしていくという方法が紹介されていた。確かに、考え方や実践のためのスキルなど習得すべきことの性質や量を考えると個別にみっちり指導していく方がよく定着するだろうなと思う。とはいえ現実問題としてはそんな気長に構えていられないような状況もあるだろうし、まだ小さくリファクタリングする習慣を会得していない人のタスクに対してもどうにか改善を適用したいという思いがないこともない。
これに関してはプルリクエストによるコードレビューを行うとそれなりにカバーできるのかなあと考えている。講演でも戦術としてコードレビューが挙げられていて、人に見られるコードを書いているという意識を植え付けることで、コードの品質を向上させられるというような話があった。そのためには、単に実施するだけではダメで、レビュイーに自分の書いたコードやどのような変更を行ったかが見られ、その内容が評価*2されるということを認識させるように、レビュアーはきちんと見なければならないし、見ているという姿を表さないといけないが。
それで、どうやってコードレビューで日々の改善をカバーしていくかと言うと、レビューの際に改善ポイントをがあったら、普段からこういうのを見つけたらこういう風に直していきましょうねー、というのを指摘・解説しつつ、改善を適用して (してもらって) からmergeするようにする感じ。はじめの内はレビュアーのコストがかかるのは仕方ない。いわゆる投資というものである。人によってはこれでレビュアーが見つけてくれるからと完全に甘えてしまって改善を行わない人も出てくるかも知れないが、そうしたら素直に張っ倒して (比喩表現)、自らやるように導いていくなりする必要がある。
これも全体に〜という話だとレビューするプルリクエストの量が多くなって大変になってしまうが、改善活動を日々の開発に取り入れるならば、それの啓蒙や教育も日々の活動の中にまぶしていくのが良いのではなかろうか。
「設計の可動域を確保した」テストについて
前半の方で品質を上げるのはテストではなく設計とプログラミングという話があって、品質改善のために再設計を、それによって実装の変更を行うとして、その際にテストが実装に寄り添ったもの (= 実装をテストしているテスト) になっていると、これらの活動の足を引っ張るようになってしまう。なので、設計や実装の変更を後押しするような、実装と距離を持ったカバー範囲に遊びのあるようなものにして、カバー範囲内で変更を行う分には落ちないようなテストを作りましょう、という話だった。
それから時間が経って9月になって、private methodのテストと設計についての話が以下の記事を発端として話題になった。
su-kun1899.hatenablog.com
private methodにまつわる設計の是非は置いておくとして、この記事に対してt_wadaさんが紹介したQ&A記事において、質問者がprivate methodも実装した瞬間に実装のテストがしたいという発想のもとテストを書いてしまいたいな、と述べており、それに対してt_wadaさんは「プライベートなメソッドのテストを書く必要は 無い と考えています」と先に結論した上で、以下のように説明している。
繰り返すと、プライベートなメソッドや関数をテストする必要は無いと考えています。プライベートなメソッドは、実装の詳細であるからです。 (中略) プライベートメソッドに対するテストは内部の実装に対するテストになってしまうことが多く、そして内部の実装に対するテストはリファクタリングの妨げになりがちです。自動テストの助けを借りて積極的にリファクタリングを行いたいのに、その自動テストがリファクタリングの妨げになる。これはとても皮肉な状況です。避けられれば避けたいものです。
テスト「できる」ことと「するべきである」ことは異なります。リフレクションを使えばプライベートなメソッドのテストは「できる」のですが、そのテストはやがて実装改善の邪魔になりかねません。
Q&Aの記事がちょうどこの講演 (再演) の3年前くらいで、その頃からリファクタリングを後押しするための実装に対して距離を保ったテストという考えがあって今日まで一貫してきてるんだなあという感動があったのはさておき、実装のテストを書いてしまうと実装を変更するたびにテストも改修しなければならないためリファクタリングのコストを無闇に上げてしまうことや、リファクタリングが振る舞いを変えずに実装を改善することだというところから、リファクタリングによって継続的にコードを改善できるようにするために実装に対して遊びのあるテストを書きましょうということについては私も同意したのだが、「実装のテストを書くべきではない」というのはちょっと違うのでは、という考えを話を聞いた当時に持った。
それについて、講演後に呟いた以下の一連のtweetが上記の話を受けての実装のテストに対する考え方を表している。
まとめると、この講演では書くべきでないとされた「実装のテスト」について、私は実装をしているまさにその時はそれぞれの部品が正常に動くことを確認するための一時的な、目的を達成したら (部品が期待通りに動くことが確認できたら) 捨ててしまう「寿命の短いテスト」としてであれば別に書いても良いと思っていて、実装後も再設計やリファクタリングできるように残すテストは設計・実装に関してカバー範囲に遊びのある「寿命の長いテスト」にする、というように使い分ければ良いのではということである。
ここでいう「寿命の短いテスト」= 「実装のテスト」は役割的には補助輪のようなものだし、書くべきではないというより書かなくてよい、言い方としては「後に残すべきではない」の方が適切かな? というのが私の意見となる。
まあ時間軸の視点を持ったところで、結局「寿命の短いテスト」は書かずに済むに越したことはないし、「寿命の長いテスト」だけ書きながら書き上げられるようなプログラムがいわゆる良い設計のプログラムと言えるのかも知れない。
以下当日のメモ (当日若干遅刻したので途中から)
Read more