「読みやすいコード」を考える

読みやすいコードというと、

「何をしているのか分かりやすい。」

という回答を得る場合が多い。

だが、それだけで果たして本当に読みやすいと言えるのだろうか。

今回は、本当に「読みやすいコード」とは何かを考えていきたい。

まず最初に、コードを読む必要があるケースをあげる。

1.そのコードを保守する時

2.そのコードを利用する時

特に前者の例が多いのではないだろうか。

以前書いたコードをデバッグしたり、他人が書いたコードをデバッグしたり、仕様変更に対応したり。

そして、次になぜコードが書かれているかといえば、

要求されている仕様を実現するため

だろう。

ということは、「読みやすいコード」とは、「どんな仕様を実現しているのかわかりやすいコード」である必要が出てくる。

例えば以下のような断片的な仕様を実現してみよう。

仕様:

商品区分の上2桁が”BB”のものと、”CC”のものはシステム対象外とする。

ただ、「何をしているか分かりやすい」シンプルなだけのコードの場合、以下のようになる。

Private Sub 何らかのメソッド(商品コード As String)
Select Case 商品コード.SubString(0,2)
Case Is = "BB","CC"
'システム対象外とする処理
Case Else
'処理
End Select
End Sub

確かに、上記の例は簡潔だし、そこだけを見ればよいので手っ取り早い。

だが、後々、このコードを見たときに

「何で、”BB”,”CC”の時だけ、この処理を行っているのだろう。」

「この分岐は、どんな仕様を実現しているんだっけ?。」

と、疑問に思わないだろか。

他人のコードだったらなおさらである。

そこで、もし、このコードが

Private Function システム対象(ByVal 商品コード As String) As Boolean
dim システム対象外判断部分 as String = 商品コード.SubString(0,2)
If システム対象外判断部分 = "BB" Then
return False
EndIf
If システム対象外判断部分 = "CC" Then
return False
EndIf
return True
End Function
Private Sub 何らかのメソッド(商品コード As String)
If Not システム対象(商品コード) Then
'システム対象外とする処理
Exit Sub
Endif
'処理
End Sub

だったとしたら、どうだろう。

前のコードと比べると明らかに冗長ではあるが、

「”BB”,”CC”の時はシステム対象外である。」

という仕様がコード上に残っているため、その分岐がどんな仕様を実現しようとしたのか、一目瞭然である。

また、その分岐の詳細仕様に興味が無い場合は、そこを見るだけで充分である。

そして、どんな時にシステム対象外なのか詳細仕様を知りたくなったら、その時に初めてその先のメソッドを見ればよい。

このようなコードは、一見冗長に見え、読む範囲が広がり追いづらくなるように見える。

だが、実際は、目的に応じて詳細レベルをコントロールできることで、より簡潔に目的にマッチした読み方ができる。

ぜひ、一度、

「コードに仕様を残す。」

という事に留意して、コーディングしてみてはどうか。

きっと「読みやすい(保守しやすい。)コード」になるだろう。

Share

コードは能弁であれ。コメントは謙虚であれ。

コードは能弁であれ。

コメントは謙虚であれ。

これが、私が思うコーディングのベストプラクティスです。

あくまでコードが主役です。

コードに喋らせてやってください。

コードに喋らせられずにコメントに逃げてばかりいると・・・

コメントが暴走するか、

コードに置いてきぼりにされてしまいます。

(つまりコードとコメントの整合性が取れなくなる。)

コメントはあくまで注釈程度にするべきで、謙虚にひっそりとコードを支えてやってください。

Share

名前をつけてやれ

変数名、関数名、クラス名、メソッド名・・・

あらゆるモノは、名前が付いていることで存在が認められる。

だから、そのモノの存在理由を名前であらわしてやる必要がある。

より、存在理由が明らかな名前ほど、より明確に、より有効に働いてくれる。

そして、存在理由が明らかであるということは他者との違いも明確になる。

だから、ちゃんとした名前をつけてやれ。

Share

できるだけコードに仕様を埋め込む努力をしよう

例えばこんな仕様がありました。

鼻毛を処理する道具があれば鼻毛処理ができる。
道具には、鼻毛抜き、鼻毛カッターがある。

これに対してこんなコードがありました。

001 If 鼻毛抜きの在庫 > 0 OrElse _
002    鼻毛カッターの在庫 > 0 Then
003    鼻毛処理()
004 End If

これでも、確かに仕様を実現していますが、より仕様を埋め込んだ方が後から読んだ時に分かりやすいので

001 If 鼻毛処理の道具がある() Then
002    鼻毛処理()
003 End If
004 
005 
006 Private Function 鼻毛処理の道具がある() As Boolean
007     If 鼻毛抜きの在庫 > 0 Then
008               Return True
009     End If
010 
011     If 鼻毛カッターの在庫 > 0 Then
012               Return True
013     End If
014 
015     Return False
016 End Function

こんなコードにします。

仕様がよりコードに埋め込まれ、

また

鼻毛処理の道具がある から 鼻毛処理 ができる。

と、より自然に読むことができるようになりました。

どうでもいいですが、後から、道具の種類に電動鼻毛カッターが増えても安心です。

Share

仕様書と同じ言語でコーディングをすること

件名:メソッドや変数に日本語を採用したい

メソッドや変数に日本語を採用したい – Insider.NET

最近、@ITにこんなスレッドが浮かんできたので、過去にもブログで書いていますが、

もうちょっと書いてみます。

以前書いたとおり

■[IT雑感]日本語でコーディング

最近、開き直ったように日本語でコーディングしている。

クラス名、メソッド名等も含めてである。

NAL-6295の舌先三寸 – 今やっと山の麓に辿り着いたのだと気づいた

仕様書とコードは同じ言語で書いたほうが

開発時の効率もその後の保守性もあがる。

というのが、私の主張ですが、

発想は簡単です。

・メソッドのヘッダコメントに日本語を使うなら、

それをメソッド名にすれば良いのにと考えます。

・処理に記述するコメントに日本語で記述するなら、

そのコメントに現れる日本語の単語を、

変数名にしたり関数名にしたりすればよいのにと考えます。

・保守の度に記述された処理とコメントの両方を

メンテナンスしなくてはいけないとしたら、

そこにはヒューマンエラーがひそんでいそうです。

(実際にコメントに騙された事が多々あります。)

・英語と日本語の対応辞書を作るなんてめんどくさいし、

 それこそヒューマンエラーを招きそうです。

 

また、実績として、

・開発したことない新人でも、構成を理解してくれました。

 簡単な修正もやって貰えました。

・一般的なレベルの他人に保守して貰ったら、

 実績より早く修正されました。

・1年前の自分は他人ですが、1年前の自分を理解できました。

・IMEのON/OFFは思ったよりめんどくさくありませんでした。

・最初はメンバもとまどいましたが、少したつと分かり易いという

 利点に気づきました。

webアプリケーションの開発をしていますが、

オブジェクト名は別に日本語でも問題ありませんし、

SEOを考えないので良い社内システムであれば、

URLも日本語で定義しておいて、URLEncodeすれば良いと思います。

勿論、仕様書そしてエンドユーザの第1言語が日本語だったらの話ですが。

Share

省略してはいけない。(VB6)

VB6の話。

VB6はメソッドの引数につけるByVal,ByRefを省略するとByRefでした。

そこで、こんなコード。

(良いサンプルが思いつかなかった・・・)

Private Sub やってはいけない(hoge As String,RecordCount As Integer)
RecordCount =  なんらかを実行して件数を返すらしい(hoge)
End Sub

引数として渡されたQueryを実行し、

RecordCountに実行結果を返しているらしいが、

やるなら、

Private Sub やってはいけない(ByVal hoge As String,ByRef RecordCount As Integer)
RecordCount =  なんらかを実行して件数を返すらしい(hoge)
End Sub

と書いておかないと、

Queryは値渡しで使われるだけ

RecordCountは参照渡しで、やってはいけないサブプロシージャ内でセットされる。

という事が読み取れない。

実際は、参照渡しは、それが回避不可能な時のみ利用するに限るので、

下記のように引数で値を返さないように修正する。

Private Function やってはいけない(ByVal hoge As String)  As Integer
Dim recordCount As Integer
recordCount =  なんらかを実行して件数を返すらしい(hoge)
やってはいけない = recordCount
End Function

値渡し、参照渡しの宣言を省略しないでね。

参照渡しは回避できるなら回避しようね。

ということ。

Share

疑うのは環境から

昨日と今日で同じプログラムが動いているのに、

今日突然動かなくなった。

そんな時、疑う順番は

昨日と今日の環境の差異からだ。

これをすっとばして、デバッグしたところで多分解決には辿り着けない。

Share

参照型と値型の値渡しと参照渡しについて

型は大別すると参照型と値型にわけられる。

だから引数として渡すパターンとして、

参照型の値渡しと参照渡し

値型の値渡しと参照渡し

がある。

参照型と値型のそれぞれが何を値として持っているかに着目すれば、

参照型と値型で値渡しと参照渡しの動作は変わらないのだけど、

そこに着目しないと参照型と値型で動作が変わる様に感じるかもしれない。

とはいえ、着目しなくても4パターン知ってればよいわけだから、

そんなに難しい話でもない。

値型は実体そのものが値である。

参照型は実体への参照が値である。

値渡しは保持しているものは変更できないという事。

(値のコピーを渡しているに過ぎないから、呼び元の変数の値に影響は与えられないという事)

だから、参照型が参照している実体の中身は変更が可能。

参照渡しは保持しているものを変更できるという事。

(値の参照を渡しているから、呼び元の変数の値に影響を与えてしまうという事)

だから、参照型が参照している先を変更できてしまう。

より自由度が高く、そして殆どの局面で利用する必要がない。

参照型の参照渡しが必要な設計は殆どの場合、あまり良い設計とは言えず、

(殆どの場合であり、全てが良い設計ではないとは思わない。

 必要な局面も確実にある。)

一度、戻り値で返す設計にできないか検討するべきだと思う。

過去にこんなエントリもありました。

メソッドを定義するときに、refキーワードを参照型に付けたときと付けなかったときの違いは、簡単に言えば・・・

・ref付きは参照する場所を変更出来る。

・ref無しは参照する場所を変更出来ない。

・両方とも、参照先のオブジェクトが持った値を変更する事は可能。

NAL-6295の舌先三寸 – 参照型にrefキーワードがついている時とついていない時の違い

Share

int iとかint jとか・・・

ループカウンタだからって、i,j,kは許されない。(私的には)

配列のインデックスを表すならindexで良いと思う。

思わず、

i(いまいちだ)

j(自嘲しやがれ)

k(くそーすめ)

とあいうえお作文してしまうので、勘弁して欲しい。

DataRowだから、drね。っつーのも止めて欲しい。

そのdrには、どんな意味があるんだ。

サンプルに書いてあるからって、それが綺麗なコードとは限らない。

もっと名前に気を使って欲しい。

Share