49976


現在、Pythonで簡単なWEBアプリケーションを作ろうとしています。

しかし、このプログラムを作成する上で、関連領域の処理をクラスでまとめてしまうか、それとも関数で対応してしまうか、どちらが良いのかということが気にかかっています。

今作ろうとしているWEBアプリケーションは、WEBアプリフレームワークに毛が生えた程度のものなどで、クラスか関数かはそんなに大きな影響はないと思うのですが、ベストプラクティスなどに沿ったプログラミングをする際の「型」を初期段階からできるだけ身に付けたいと思っているので、クラスか関数かについても判断軸などについて知ることができればなと思っています。

Pythonでのクラス、関数の作成方法については一通り理解できているつもりです。

何か教唆いただければ幸いです。


CC BY-SA 4.0
2018-11-04T16:16:29.513
49965
2018-11-06T06:43:12.997
2018-11-06T06:43:12.997
754
29884
question
python
オブジェクト指向型のプログラミング言語でクラスを使うとき


Pythonは、関数型言語としてもオブジェクト指向言語としても使える汎用的なプログラム言語です。それだけに、関数型言語としても、オブジェクト指向言語としても、完全ではなくて欠陥を持つ言語です。Pythonの強みはどのようにでも使える柔軟性があるということだと思うので、クラスか関数かという「型」を身につけるのではなくて、課題によって柔軟に対応した方がいいと思います。

PythonでWebアプリケーションを作りたいという場合、Pythonが得意なデータサイエンスや機械学習のライブラリーを使いたいというケースも多いと思います。そういう場合には、自分でクラスを作るのではなく、ライブラリーの既成のクラスを使うケースが多いと思います。クラスの例としては、Pandasの`DataFrame`やMatplotlibの`figure.Figure`,`axes.Axes`等があります。クラスになっているとプロバティやメソッドが纏まっているので使うのには便利です。

Pythonには、このように優秀なライブラリーが多いので、グルー（糊）言語として使うケースが多いと思いますが、そういう場合には、クラスは使うものであって、自分で作るメリットはないと思います。

クラスは使うのは便利ですが、作る側の方で手間もかかるし、コードも複雑になります。そういうことを考慮した上で、クラスにメリットがあると思えば、関連領域の処理をクラスでまとめてしまえばいいのではないでしょうか。


CC BY-SA 4.0
2018-11-05T01:59:14.147
49969
2018-11-06T01:22:37.130
2018-11-06T01:22:37.130
15171
15171
49965
answer


# 一般論のお話

  * 他の方もおっしゃられているように、設計はケースバイケースです。
  * _システムに与えるべき理想的な構造_ を目指すのが望ましいでしょう。

# では理想的なシステムとは？

しかしそもそも、このような質問をしたくなる理由を想像します。  
すると理想的な構造を目指そうというときに  
「関数や、クラスを使い分けるメリット・デメリットの判断には、どんな **観点** があるの？」  
という疑問が隠れているように思います。

またその観点自体を理解できれば、この問題に **あなた自身** が考えはじめることができるでしょう。  
(これを考えられること自体が、プログラマとして大事なわけですね。)

そこで、この疑問にある程度の範囲で、お答えします。

# 大域的に持つべき観点

まず改めて強調しておきたいことは、現実の状況、たとえば

  * ビジネスや行いたいことの内容 
    * 数学の科学計算を１回だけ行いたい物
    * ウェブサービスとして長期的にずっとアップデートを繰り返してプログラムを提供したい物
    * 原子力発電所などの事故を起こすととても致命的な状況が生じる物
    * ……など
  * チームメンバーの構成 
    * あなた一人？それとも複数人いるの？
    * メンバーのスキルはどれくらい？
    * プログラマ以外にデザイナさんとかもいたりする？
    * ……など

などに合わせて、「どのようなコードであるべきか」は、変わっていくものです。  
この **大域的な** 観点は忘れないようにしてほしいです。  
決まりきった方法はなくて、あなたの現実を見つめないといけません。

# この場合の個別の観点

その上で、プログラムを設計する上での有名な **観点** が、いくつかあります。

ご質問の内容は、関数やクラスの使い分けでした。  
そこでここでは関数やクラスの使い分けで変わってくる観点の有名所をいくつか紹介します。

## 共通の対象を取り扱っていますか？

全く同じデータを引数に受け取って動く関数がたくさんありませんか？  
逆にメンバ変数に全然アクセスしていなくて、将来的にもアクセスしそうにないメソッドがクラス内にありませんか？

同じデータを引数に受け取って動く関数たちは、そのデータをメンバ変数にもったクラスにまとめることで上手く行くことが多いです。  
一方でメンバ変数に全然アクセスしていないメソッドは、もしかしたらただの関数として切り出せるかもしれません。

## テスト可能ですか？

そのプログラムは、自動ユニットテストなどにより、簡単に動作を検証できますか？

関数の中で別の関数を呼び出すけれど、そこでログデータを書き出したりしているとします。  
すると、テストプログラムからその関数を呼び出すたびにログデータが出来てしまい、テストがおかしくなってしまいます。  
このときにその２つの関数をクラスにまとめて、片方の関数を呼び出したときに、もう片方の関数はオーバロードすることでログ書き出しを止めるという手段がよく使われます。

また逆に、インスタンスを作るのがとてもむずかしいクラスを作ってしまうと、  
その中にあるメソッドのテストが大変になってしまうことがあります。  
この場合は、そのメソッドを切り出して関数にし  
そちらでテストをして、クラスの中からは呼び出すだけにすることがあります。

## 上手く"モジュール"になっていますか？

そのプログラムについて、よくある変更を入れるとき、影響範囲は関数やクラスの中に収まり、  
その局所的なコードだけ(関数内だけ、クラス内だけ)を書き換えれば十分でしょうか？  
それとも、関連する事柄を書き換えるのに、もっと広い範囲を書き換えないと行けないでしょうか……？

よくある書き換えの影響範囲が１箇所にまとまっていることで、見通しが良くなる傾向があります。

これについてはもしかしたらクラスにまとめる以外にも  
ソースコードの単位で分割してimportして扱う、といった対策もありえます。

## YAGNIですか？

YAGNIというのは "You ain't gonna need it" (多分必要になることはないよ！) という言葉の略語です。  
いまやろうとしている簡単なことに対して"やたらとややこしいこと"をやるよりは、案外愚直で簡単な手段を使ったほうがいいことが多い。  
ということを言うのに、プログラマの間で、標語的に使われているものです。

問題に対して一番シンプルなコードで結果を得ていますか？  
多くの場合、ややこしすぎる手段を使ってしまうことで、後から「ああ！あの解決策、当てはまりが悪かった！」みたいな後悔をすることになります。  
このことから、最初は単純な関数で作って、共通の対象などを扱ってるなあと思ったらクラスにする、などの指針が得られます。

# 改めて「状況によるよ！」

ただし、覚えておいてほしいのは、 **観点は、これ以外にも本当にたくさんある** ということです。  
ぜひ「こっちのほうがいい結果になるかもしれない、それはこういう理由だ」と、ご自身でも考えるようにしてみてください。

状況に応じて理想的なコードとは何かは変わっていきます。そのため

  * 「今扱っている問題をしっかり見定める」方法を自分の中に組み立てていること。
  * 「どういった観点でコードを見るか」を自分の中にもっていること。

といったメタな視点が、プログラマとして成長する上で重要になります。


CC BY-SA 4.0
2018-11-05T07:25:36.167
49976
2018-11-05T13:52:45.500
2018-11-05T13:52:45.500
30827
30827
49965
answer