こんにちは。
私は、これまでに多くのシステム開発に携わってきました。
その中で、たくさんのプログラマが書いたソースコードを読んできました。
ソースコードの書き方は、プログラマによって様々です。
長いソースコードもよくあります。
でも、長いソースコードって、とても読みづらいんですよね。
なので、機能の追加が発生すると、コーディングがすごく大変なのです。
今回は、読みづらくなったソースコードを、読みやすくする方法について書いていきます。
読みづらいソースコードに潜むバグ
読みづらいソースコードとは、どのようなソースコードでしょうか?
それは、以下のようなソースコードです。
- 1つの関数に、多くの処理が入っている。
- 同じような処理が何度も登場する。
- if文やfor文のネストが深い
- 関数名や変数名がわかりづらい。
このようなソースコードは、読みづらく、潜在的なバグが含まれている可能性があります。
おそらく、コーディングした当初は、テストも十分に行っていると思います。
しかし、その後のバグ修正や機能の追加などで、テストに不十分な箇所が生まれ、結果として潜在的なバグが含まれてしまうのです。
このようなソースコードを整理することを、”リファクタリング”と言います。
リファクタリング (refactoring)
“リファクタリング”とは、「外部から見た動きは変えずに、プログラムの内部構造を整理すること」です。
つまり、関数を呼び出した時の挙動は一緒だけど、ソースコードを見ると、関数の内部は整理されていると言うことです。
ここで大事なのが、「外部から見た動きは変えずに」というところです。
外部から見た動きが変わってしまうと、関数の呼び出し元も変更する必要があります。
「壊れていない物を修理するな」と思う人もいるかもしれません。
私も昔は、「壊れていない(正常に動いている)のだから、プログラムを修正する必要ない」と考えていました。
しかし、機能の追加でデグレやバグが頻発してしまいました。
原因は、プログラムの内部構造が整理されていなかったからです。
なので、リファクタリングは、プログラムにとって必要なのです。
メリット
リファクタリングを行うメリットは、以下の3つです。
- 設計の劣化を防ぐ
- コードを理解しやすくする
- 修正や機能の追加を早くする
設計の劣化を防ぐ
開発をしている時は、設計方針にしたがい、きれいにコーディングされていると思います。
しかし、改修や機能の追加が重なると、ソースコードは劣化していきます。
劣化したソースコードは、改修や機能の追加が難しくなっていきます。
リファクタリングは、そのような劣化したソースコードを改善する効果があります。
コードを理解しやすくする
また、劣化したソースコードは、処理の理解が難しくなっています。
そのため、新しく参入するプログラマには、処理を理解するのに時間がかかってしまいます。
リファクタリングすることで、理解しやすいソースコードに整理することができます。
修正や機能の追加を早くする
そして、リファクタリングされたソースコードは、修正や機能の追加がしやすくなります。
そのため、修正や機能の追加にかかる時間が少なくてすみます。
デメリット
リファクタリングをするデメリットは、以下の2つがあります。
- 工数がかかる
- デグレが発生する可能性
工数がかかる
リファクタリングには、工数(時間)がかかります。
「外部から見た動きは変えない」ので、サービスを利用する顧客から予算をいただくことが難しいです。
デグレが発生する可能性
「プログラムの内部構造を整理する」ために、処理が共通化されてしまい、結果、デグレが発生することもあります。
長年、改修と機能の追加が行われてきたプログラムには、共通化できない動きもあります。
そのような仕様が引き継がれていない場合に、デグレとなることが多いです。
リファクタリングの方法
リファクタリングの方法は、いろいろあると思います。
私は、よく以下の順序でリファクタリングを行っています。
- 関数や変数の名前をわかりやすくする
- 使用されていない処理を削除する
- 重複した処理をまとめる
- ネストを浅くする
関数や変数の名前をわかりやすくする
まずは、関数や変数の名前をわかりやすくしていきます。
関数や変数の名前の付け方は、人それぞれです。
そのため、多くのプログラマが関わってくると、関数や変数の名前が分かりづらくなってきます。
なので、分かりやすい関数名や変数名に変えます。
こんな時に命名規則があると、ブレが少なくなります。
使用されていない処理を削除する
改修や機能の追加が長年行われていると、使用されなくなった処理があります。
何かあった時のためにと、過去の処理をコメントアウトして取っておくことはよくあります。
しかし、コメントアウトされた処理が多くなると、ソースコードが読みづらくなってしまいます。
なので、リファクタリングのタイミングで削除してしまいましょう。
重複した処理をまとめる
同じ処理が何度も出てくると、改修で漏れが発生する可能性があります。
なので、同じ処理は関数にして、その関数を呼び出すようにします。
この時、共通の処理は、クラスにまとめられないかを検討します。
基底クラスにすることで、ソースコードが、より分かりやすくなります。
ネストを浅くする
ネストが深い処理は、不具合の原因となります。
なぜなら、ネストが深くなることで、処理のパターンが増えるからです。
なので、ネストをなるべく浅くするようにします。
私の個人的な意見を言うと、ネストは2つまでが言いと考えています。
タイミング
では、リファクタリングを行うタイミングはいつでしょうか?
リファクタリングするタイミングは、以下になります。
- 同じ作業を3回繰り返した時
- 機能を追加する時
- バグ修正の時
同じ作業を3回繰り返した時
コーディングしている時に、同じ処理が出てくることは、よくあります。
もしも、同じ処理が3回出てきた時は、リファクタリングした方が良いでしょう。
同じ処理が3回出てくると言うことは、今後、何度も同じ処理が出てくる可能性があります。
なので、その時点で、リファクタリングできないかを検討しましょう。
機能を追加する時
機能の追加が発生したときも、リファクタリングする良いタイミングです。
処理が整理されていた方が、機能の追加は、しやすくなります。
ただし、機能の追加を行いながら、リファクタリングを行うことは、避けた方が良いです。
なぜなら、不具合の原因を切り分けるのが難しくなるからです。
なので、リファクタリングは、機能を追加する前に行うようにしましょう。
バグ修正の時
バグの修正をする時も、リファクタリングの良いタイミングです。
バグの修正で、デグレが発生することは良くあります。
そのような、デグレを発生させないためにも、リファクタリングした方が良いでしょう。
しかし、この場合も、バグ修正の前にリファクタリングを行うようにしましょう。
理由は、機能を追加する時と同じで、不具合が発生した場合、原因を切り分けるのが難しくなるからです。
注意点
リファクタリングを行うときの注意点は、以下の3つです。
- バックアップを取っておく
- 小さな規模で行う
- テストを十分に行う
バックアップを取っておく
リファクタリングを行う時は、必ずバックアップを取っておくようにしましょう。
元の処理を見直す時や、リファクタリングに失敗した場合に、戻す必要があるためです。
私がよく使うのは、gitと言うバージョン管理ツールです。
gitを使う場合は、こまめにローカルにコミットするようにします。
そうすることで、ソースコードを戻す必要がある時でも対応できます。
小さな規模で行う
リファクタリングは、できるだけ小さい範囲で行いましょう。
ある程度、理解しているソースコードの場合、大きくリファクタリングを行いたくなります。
しかし、大きくリファクタリングを行うと、デグレが発生する可能性が高いのです。
また、大きくリファクタリングを行ってしまうと、テストに時間がかかってしまいます。
なので、できるだけ小さい範囲でリファクタリングするようにしましょう。
テストを十分に行う
そして、リファクタリングを行った場合は、必ずテストを実行し、既存の処理と同じかを確認するようにしましょう。
1箇所リファクタリングを行ったら、そのテストを行い、動作が変わっていないかを確認するようにするのがベストです。
テストには、RPAやUnitテストを使用すると、同じテストを繰り返し行うことができます。
まとめ
今回は、読みづらいソースコードに潜むバグを防ぐ方法として、リファクタリングを紹介しました。
リファクタリングは、「外部から見た動きは変えずに、プログラムの内部構造を整理すること」です。
そのメリットとしては、以下の3つがあります。
- 設計の劣化を防ぐ
- コードを理解しやすくする
- 修正、機能追加を早くする
そして、デメリットとしては、以下の2つがあります。
- 工数がかかる
- デグレが発生する可能性
リファクタリングの方法は、いろいろありますが、私は、経験より以下の順番で行っています。
- 関数や変数の名前をわかりやすくする
- 使用されていない処理を削除する
- 重複した処理をまとめる
- ネストを浅くする
リファクタリングを行うタイミングは、以下になります。
- 同じ作業を3回繰り返した時
- 機能を追加する時
- バグ修正の時
ただし、機能の追加やバグの修正の前に、リファクタリングを行うようにしましょう。
リファクタリングを行う際の注意点は以下になります。
- バックアップを取っておく
- 小さな規模で行う
- テストを十分に行う
読みづらいソースコードには、必ずと言って良いほど、バグが潜んでいます。
長期でシステムを運用するには、タイミングを見てリファクタリングを行うようにしましょう。
では、今日はこの辺で。
コメント