matobaの学んだこと

とあるPythonエンジニアのブログ

クラス設計できた方がいいのか

「もっとクラス設計できたほうがいいよね」と思っていた時期がありました。 それを思い出したので、今思っていることを書こうと思います。前置きとして、全然まとまってないです。

クラス設計できたほうがいいよね

そういえば、なんか知らないけど、「 クラス設計できたほうがいいよね」と思ってたことがあった。 今は、どちらかというと、「クラス化するべきところでクラス化したい」とかそういうふうに思ってる。その間にある話を書こうと思ってる。

前に、「クラス設計できた方がいい」とか思ってたけど、どんな時に思ったんだっけなーと思い返してみる。すると、趣味でアプリケーションを作っている時にそんなふうに思ったな、と思い出した。

趣味でアプリケーション作ってる時

趣味でアプリケーションを作ってる時、あんまり深く考えずに、端から作ろうとしてた。

そして、端から思いつくままに、動くように作っていくと、「なんだこれ。いろんなところを直さなきゃならなくてめんどくさい」みたいになった。

「初めからクラスを検討できていたら、こんなめんどくさいことに直面せずに済んだんだろう」と思った。

「はじめにクラスを検討していないことが、問題なはずだ!作り始めた時にクラスをきちんと検討しておけば、後からプログラムを書き直すとかめんどくさいことをせずに済んだのに!」と思った。

そう。趣味でやってる開発の場合、プログラムを書き直すのはめんどくさかったのだ。

プログラムを書き直すのはめんどい

プログラムを書き直すのはめんどい。特に趣味でやってる場合、なおさらめんどくさいと思ってた。

なぜか。

まず、プログラムを書き直すと動作確認しないといけない。 動作確認するのがめんどくさい。僕は、自分が欲しいアプリが作りたくて、動作確認したいわけじゃないと思ってる。だから嫌だなと思ってた。

趣味で書いてるプログラムのユーザーは、基本的に自分でユーザーが開発者の真横にいるような感じだから、ユーザーが常に開発者に向かって、「それ、無駄じゃね?」と言ってるような感じだ。

じゃあ、どうするのか

今、振り返ってみて、どうすればいいのか、という話を思い出してみると、とりあえず、「ユニットテストをかけ。」という話になるなと思った。

僕は、テスト駆動で開発するのか、後からユニットテストを書くのかは、どっちでもいいと思ってるけど、とりあえず、ユニットテストが必要だ。

ユニットテストがあれば、動作確認はしなくて済む。というか、大体の動作確認はユニットテストでするから、手作業でやる動作確認はすごく減る。だからストレスフリーになる。

そもそも、クラス設計できてないことが問題なの?

そもそもの話を思い出してみる。 書き直しが発生するのは、クラス設計ができてないことが問題なのだろうか。

今思い返すと、それは微妙な感じがしてる。わからないけどなんか違う気がする。

書き直しが発生するのは、アプリケーションだけの問題ではないので避けられないと思う。

書き直しが発生するタイミングについて考えてみよう。

書き直しが発生するタイミング

書き直しが発生する、、、というか「クラスにしておけばよかった。」と当時思っていたタイミングは、同じような役割の塊をいろんなところで使うことになった時だった。

例えば、アプリを作っていて、外部APIを実行するとしよう。APIはたくさんの値を返してくる。

  1. 一つ目に作った機能は、返された値のうち2つ使えば作れたので、直接取り出した。
  2. 二つ目に作った機能は、返された値のうち3つ使えば作れたので、コードをコピペして、直接取り出し方を修正した。
  3. 三つ目に作った機能は、返された値のうち4つ使うので、、、あれ?最初からクラスにしとけばよかったのでは?失敗した!!

こんな風に思ってた。でも、これ、実は失敗してない。

別に失敗してない

この三つ目までの流れは、別に失敗してない。 一つ目の機能を作った時は、本当に返された値の2つだけを使っておけばよかった。 この時点で、全ての値を持つようなAPIの応答をまとめるクラスを作るべきかとかは、微妙な気がする。 だって、その時点では、二つ目の機能や三つ目の機能を作るかどうかはわからないから。

先走ってクラスを作ると

もし、一つ目の機能を実装する時点でAPIの応答をまとめるクラスを作ったとする。

で、一つ目の機能を作った後、そのAPIを使う機能を作らなかったらどうだろう。 そのクラスは、ただの邪魔なコードになる。なんのために存在しているのかわからないし、強いて言えば、一つ目の機能を無駄に複雑にしている。

コードは読みにくくなるし、一つ目の機能の開発コストも上がってる。

じゃあどうすればいいのか

同じようなコードが複数出てきた時点で、まとめればいい。

いわゆるリファクタリングがそれ。

最初から、作るんじゃなくて、同じようなコードが複数出現したら、まとめる。

コードを修正したら、動作確認が、、、

確かに、過去のプログラムを修正したら、動作確認しないといけない。

それは最もな話。リファクタリングしたのに、動作確認せずに、実装完了とするとおかしい。後から何かが動いてないことに気づいて、どこが動いてないのかを確かめるのに時間を食うことになる。

だから、回帰テストをしよう。

手作業で動作確認をやってたら、そんなのテストを割きたくないから最初に設計したい、という話になる。リファクタリングを簡単にやるために、ユニットテストを書く。

そうはいっても手作業でテストせねば

そうはいっても手作業でテストしなきゃならない時もあると思う。

例えば、外部のハードウェアを制御するとか。外部のサービスを使うとか。 ユニットテストで何回も叩きまくるのが望ましくないとか、できないものは、手作業で回帰テストせざるを得ない。

でも、そういう場合は、テストパターンをmockしてユニットテストしておくとかになるのかな。 あと、外部の何かが仕様と違う動きをした場合は、どうするか、とかはわからない。

とりあえず、外部の何かは想定外の動きをする可能性があると思って、コードを書いて、想定外の動きをしたとしても気づけるような仕組みを作っておくのが大切なように思う。

そうは言っても最初にクラス設計する方が

そうはいっても最初にクラスを設計する方が、コーディングの量が少なくなるでしょ。という話がある。

まあ、わかる。

最初に全ての機能を洗い出すことができて、そのユースケースとかもfixさせることができるのであれば、それらをきちんと考慮してクラスを設計して、コーディングすればコーディングする量は少なくなる。

でも、作りたい何かはそういう作り方ができるものなのだろうか?という疑問がある。

作る目的はなんなのか

本当に作りたいものに到達するためには、誘導ミサイルみたいにどんどん設計が変化させられるように進める必要がある。なぜなら、最初は、何が作りたいかわからないし、作りながらそれらは変わっていくのがよくあることだから。

作りたいものは、作りたいと思っている人がどれくらい知識を持っているかで変わる。周辺の状況や時代背景とかでも変わる。

だから、設計をfixしてコーディングすると設計した時点では最高の構造も、実装して実装が終わったらすでに劣化してる。

とはいえ、fixするメリットもある

とはいえ、設計をfixするメリットもある。

設計をfixすると何を作るのか、は明確になる。

作ったものが、最終的に、欲しかったものじゃないかもしれないけど、出来上がる。

でも、コーディングの量は最小限に抑えられる。

設計を変化させるためには圧倒的なコーディングが必要

誘導ミサイルみたいな作り方をするためには、ユニットテストを厚くする必要がある。

ユニットテストもぼーっとしてたら出来上がるわけではなくてコーディングして出来上がる。

要するに誘導ミサイルのように設計が変化するように作りたかったら圧倒的にコーディングの量が増える。

コーディングを自分たちでできなくて、他の人に頼むしかない人は、コーディングの量を絶対的に下げたがる。

じゃあコーディングできる人に設計は不要?

じゃあ、コーディングができる人に設計は不要なんだろうか。

これはまた微妙な話だなと思う。「設計とは、正しく作るために行う」と書いてあるのをどこかの本で読んだ。

どちらかというと、どこのユニットテストをどれくらいにして、どこは変化しなさそう、だと想定するか、は設計の範疇なのかもしれない。

あまり細かくユニットテストしすぎると、あれだから、もっと外から見た振る舞いをテストするべきなのかもしれない。わからない。

終わり

とりあえず、思いつくままに書きなぐって見た。 僕もよくわからないなと思いながら書いてる。 でも、書いてるとそのうちなんとなく考えがまとまったり、他の人の意見が聞けたりするので、書いて置いとく。