EurekaMoments

新米エンジニアが一人前を目指す修行の日々を記していくブログです。

オブジェクト指向プログラミングについて学んだ事のメモ

目次

背景・目的

良いプログラムを作るには「オブジェクト指向設計をする」とよく言われていますが、正直なところ具体的にどういう書き方をするのがオブジェクト指向なのか、といのがよくわかっていませんでした。
そこで改めて調べていたところ、以下の記事が大変参考になったので、それらを読んで学んだ事をメモしておきたいと思います。

参考文献

オブジェクト指向という概念について分かりやすく説明してくれています。

eng-entrance.com

ソフトウェア開発において、オブジェクト指向設計をするとどういうコードになるのか、というのをまとめてくれています。

プログラミング中級者に読んでほしい良いコードを書くための20箇条 | anopara

プログラミング中級者に読んでほしい20個の心得の補足 | anopara

オブジェクト指向のイメージ

「テレビ」という”モノ”を操作するのに、中でどんな処理が行われているか知る必要はない。リモコンで操作すれば動く。「こういう”モノ”を作ろう」「そしてその”モノ”を使おう」というのがオブジェクト指向という考え方。

大変な作業を無くせる

レーシングゲームを作るとして、○○車、△△車、□□車を定義するとする。このとき、まずは「車」というモノ(クラス)を定義しておいて、「走る」「止まる」といったように全車種に共通する操作(メソッド)を持たせる。あとは、この車クラスを継承することで再利用すれば各車種を別々に一からクラス定義するよりもずっと効率的にプログラミングができる。

f:id:sy4310:20180808202156p:plain

バグをなるべく混入させないための基礎

コードは書けば書くほどバグが混入し、保守性が悪化する。オブジェクト指向設計すると再利用性、保守性が向上し、コードを書く量が減らせる。

これを読んでまずハッとさせられました。確かにと思いながらも、自分が今の仕事で実装しているソースコードは完全に真逆でした。。めっちゃ頑張ってコードを書いている感が否めないです。

クラス中のメソッド数を少なくする

1クラスが持つ平均メソッド数は6.5くらい、全体の8割にあたるクラスのメソッド数は10以下になる。

これも完全に自分の現状とは真逆ですね。メソッド数は10なんかよりはるかに多いです。各クラスの役割分担を見直した方が良さそうです。

メソッド中のステップ数を少なくする

各メソッドの行数を計測すると、90%くらいは20行未満、どんなに多くても30行には満たない。IDEで1画面に収まるくらい。

メソッドは小さい粒度の処理にするのが良さそうですね。自分のコードは、一つのメソッド内にいろんな処理を詰め込みすぎている気がします。

クラス中の行数を小さくする

大体は500行以内に収まることが多い。1000行を超えるようなクラスはない。

ネストを小さくする

ネスト数は小さければ小さいほどいい。深くなると読みにくくなり、メンテが大変になる。大体、3以下になるように気を付けるべき。

これは一応守れていると思います。でも、正直なところ上記のことは意識していませんでした。

変数をむやみやたらに作らない

prevCntとかnextBit, xxxFlagなどという多種多様な変数を定義して、あっちに入れてこっちに入れてなどということをしない。変数を定義した分だけ管理するコストも増える。

これはバリバリ当てはまります(汗)。逆にどうすればこうならずに済むのだろう?

ライブラリ、コンポーネントを使う

全てのプログラマは、自分が実装するよりも、優れたフレームワークやライブラリが既に利用できるのではないか、とググってみるくらいの謙虚さを身に着けるべきである。

メモリ使用量とループ回数を考える

ループ処理を書くときは、自動的にオーダーいくつのアルゴリズムになるのかを考えることが望ましい。

IOアクセスは最小限にとどめる

メモリに乗らないくらい大きなファイルサイズであれば、1度のシークで全て済むようなアルゴリズムにできないか検討するべきである。

同じことを書かない

同じ事を2回以上書かない。2回書いたらメソッド化/クラス化として抽出できないか検討する。同じ事を二か所以上に書いてしまうと、そこで変更やバグが発生した場合にコードの修正がとても面倒になる。

なるべくテスト可能なコードを書く

テスト可能であるとは、ユニットテストフレームワークから全ての操作を触れるということである。
ポイントは、クラス間、モジュール間の依存性をいかにして小さくするか、である。

これはかなり難しいですね。オブジェクト指向設計により上手くクラスを分割できていればこそできることのような気がします。

送り出すデータは厳密に、受け取るデータは寛容に

送り出すデータは定められたインターフェースに厳密に従った形式にすべきである。データを受け取る場合は、インターフェースから多少ずれたデータが来ても寛容に処理してあげるという気持ちが大事。

シンプルなインターフェース

メソッドやコンストラクタの引数、送受信するデータは必要最小限の情報をもっとも簡潔な表現で表した形であるべきだ。

複雑な内部状態を定義しない

変数を増やせば増やすほど、そのクラスの取り得る内部状態は増えていく。管理の手間もテストの手間も指数関数的に増えていく。
クラスの内部変数が多くなったときは、むやみにスコープを広げてないか、複数のオブジェクトを一つのクラスとして表現していないか、などを検討する。

コメントをなるべく書かない

コメントがたくさん必要になったときは、遠回りして複雑なことをしていないか?と疑ってみるべきだ、という意味になる。「コメントを書かないと分からないようなコードを書いているのがそもそも問題」。
ただし、何か事情があって特殊なコードを書かなければならない場合は理由を示すためにコメントを書いた方がよい。

コメントアウトしない

エディタ上で邪魔だし、変更を繰り返した後だとコメントを外してもそもそも動作しないコードになっている。なんの利点もないし、害悪だらけである。

良い名前を付ける

例えば「~Flag」なんていう変数は最悪。変数名、クラス名、メソッド名は誰が読んでもよくわかる名前にするべき。書き込み中ならisWriting、書き込みが完了したならhasWritten。