gallu’s blog

エンジニアでゲーマーで講師で占い師なおいちゃんのブログです。

おいちゃんがプログラムで気にする所

まぁつまり「気にしないところ」も少なからずあるのですが。
「規約がある所では、書いてある範囲で規約を重視しましょう / 書いてない規約は"既存のコード"に出来るだけあわせましょう」とかいう最低限のお話とか、さらにもっと最低限未満のお話として「syntax errorとか脆弱性あるコードとか書いてくんなボケ*1とかあるのですが。

その辺は押さえた上で、じゃぁおいちゃんが「何を気にしていて」「それはなんでなの?」ってのを、自分自身の内面の整理を兼ねて書いてみようかなぁ、と。

多分、おいちゃんが一番気にするのは

YAGNI(You Aren't Going to Need it.):それ、要らないよね?
・DRY(Don't Repeat Yourself.):同じ知識を2箇所以上書くな

この2つ。
YAGNIのほうは割と簡単(な、はず)で、「まだ使わないけど使うかもと思ったので書いてみました」は大体ペケぽんの対象。
ただ、突き詰めていくと少しゴリゴリしてきて……その辺は

・KISS(Keep It Simple,Stupid):シンプルにしておけ

とも関連するんだけど、「いらんループがある」とか「無駄な中間データを作ってる」とか、色々と出てくる。
昔、とある友人のエンジニアさんから「おいちゃんのコード、なんでそんなに短いの?」って聞かれた事があって、その言葉がずっと気になってたんだけど、多分、この辺を意識していたんだと思う。

少しかみ砕くと。
多分、何割かの人は「簡単"に"コードが書ける」のをよしとしているように思うんだけど。
おいちゃんは「簡単"な"コードが書ける」のをよしとしているんだろうなぁ、と思う。

「簡単なコードを書く」のは、試行錯誤もあるし書き直しもあるし考察もあるし色々あるんだけど、その辺の手間はあんまり惜しまないかなぁ、的な。
アルルの女」あるいは職人の片思い( https://gallu.hatenadiary.jp/entry/2018/12/03/003823 )とか 職人がかける手間暇( https://gallu.hatenadiary.jp/entry/20081118/p1 )とか参照していただければ幸い。
そういう手間をかけるのか、それとも「とりあえず書けたし動いてるしいいじゃん」で片付けるのか、の違いなのかもしれない。

なので、その辺まで考えると、YAGNIとかKISSとかって「結構深いお話」になるんだけど。
その辺の深さを「どれくらいまで追いかけていくか」ってのは、とても面白いんじゃないかなぁ? と思うんだけどどうなんだろ。

とりあえずお仕事でコードを見る時は
・「同じ配列をなんどもぶん回してる」コードとかは一端気にする(無理でなければ、1つにまとめてもらう)
・「今は不要なコード」は削除してもらう
ってあたりが気になる所かなぁ。

で、次にDRY。……こっちのほうがより気にするかもしれない。
「同じコードを二度かかない」って勘違いするケースがあって、そこを起点にしちゃうと色々と「スカポンタンな異論が出てくる」。
そうじゃなくて「Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.(DeepL訳:すべての知識の断片は、システム内で単一の明確で権威のある表現を持たなければならない。)」なの。
この辺は DRYを勘違いしてたお orz( https://gallu.hatenadiary.jp/entry/20120410/p1 )を参照してくださいませ。

この話をすると

・PIE(Program Intently and Expressively):意図を表現して!!
・SLAP(Single Level of Abstraction Principle):抽象度は揃えろ!!

の話が絡んでくるんだけど。
「抽象度を揃えた状態で」「意図を表現して」「同じ意図の記述が二箇所以上あってコピペしている時」に、100tハンマーが飛び交います。

んで。この辺を前提にすると
・ここのコードもあっちのコードも「引数の10%の値を端数切り捨てでreturnしてる」から、1つにまとめよう
は、これがDRYにかなってるかは「わからない」んだよ。
だって「意図が見えない」んだから。

もしその処理が
・どっちも消費税計算
なんだとしたら、思考するまえに脊髄反射で共通化しつつ、コピペした人間を洗い出しましょう*2

でも
・片方は消費税計算
・もう片方は手数料計算
だとしたら。すくなくとも「SLAPに従って"処理を書いてある"レイヤーの実装」は、それは「混ぜちゃ駄目」なんだよ。
だって「消費税計算」と「手数料計算」なんだもん。混ぜてどうすんのさ?

だから、まず「SLAPとPIE」なんだよ。
PIEとちょりとずれるかもしれないけど「意図をコメントで書いてよ」なんだよ。まぁこれくらいなら「コメントじゃなくて関数名でちゃんと」でもよし。
んで、その「意図」が「同じ(=同じ知識の断片)」なのか「違う(=異なる知識の断片)」なのか、を判断したいし、しなきゃいけないんだよ。

ちな、じゃぁ「違う意図だけど同じ実装を書いている場合の、実装レイヤーをどうする?」ってのは、まぁ議論としてはあって。
つまり「抽象度を揃えて"一番具象のレイヤー"の実装」の場合。
おいちゃんなら

public function 端数切り捨て計算(float|int $元値, float|int $百分率)

とかって具象関数切って、とりあえず処理はここに集約するかなぁ。入り口は別々にして。
例えばこれで「手数料だけ端数切り上げ」になったら、切り上げ用の関数(メソッド)切って、そっちに処理移せばよいし。


この辺までは「1つのメソッドだったり処理だったりの書き方」の部分で。
ここからもう少し広域なお話。

基本的には

・単一責任の原則:1つのプログラムには1つのことをうまくやらせる@UNIXという考え方

を尊ぶので。
1つのクラスは「そのクラス(≒1インスタンスの意味)を20~30文字くらいで語れる」くらいの粒度で切るのが好きかなぁ。
なので「複数の役割(責任)が1つのクラスに渾然一体となっている」のは大変にお好まない感じ。
ただ「1つの責任の処理内容がそもそも割と膨大」な時は、程度問題でもあるんだろうけど「でっかくなっても、いいんじゃない?(とりあえず)」とは思う。
分解する必要性が見えてから分解すりゃいいんだし(ここもまた、レイヤーが違う YAGNI である。つまり「必要になってから分解する」)。

この辺が出来てくると、大分おちついてくるかなぁ。
後は、自分が書いたコードにしても人が書いたコードにしても、気になるところはあるか、と思うので。
コードリーダーとかにちゃんと相談してから、なんだけど

ボーイスカウトの規則:来た時よりも美しく

ってのも大事だと思う。
っつか定期的なリファクタ、大切だよねぇ。 明日になったら「明日」になるから、多分、綺麗にならない( https://gallu.hatenadiary.jp/entry/2019/04/17/220708 )辺りを参照していただければ幸い。

最後に。

・驚き最小の原則:自然な書き方にしようよ

ってのがあるんだけど、これ、割と難しいと思う。
おいちゃんは端的には「既存のコードを読んで出来るだけ"近い書き方"をする」ようにしてるかなぁ。
あと「同じ処理」の時は「同じ書き方」をするようにしてる。

ここから先「この言語だとこの書き方がよりよろし」とか色々あるんだけど、とりあえずざっくり、こんな事を考えながらコードをチェックしている気がする。
こーゆーのはまた色々、文章化してから後で読み返すと気づきがあったりもするので、一端まず、文面化してみませう。

突っ込み歓迎なので、なんかあったらコメントくださいませ。

*1:……どっちも実務上で実話 orz orz orz

*2:その後どうするかはしらにゃい