ホントは教えたくないキレイなコードの書き方
1.はじめに
競技プログラミングではなく、エンタープライズ向けコードの話です。
業務で、リファクタリングリファクタリングとうるさいけど、結局キレイなコードにならないといった悩みをお持ちの方向けの、い・ろ・はです。
長年エンジニアを生業にしてきた人にとっては再復習みたいな形でみていただけると嬉しいです。
もちろん、世の中にはビューティフルコードなど、綺麗綺麗する本など多数でてますが、この記事はより実践的な記事にしようと思います。
対象は、日本人向けに書いているので、ネイティブでアメリカ語(英語とは表現しない)が喋れる人にとっては、参考にならない部分はあります。
2.メンタリティ
キレイなコードは、エンジニアのメンタルが必要
特に、綺麗とは、とてつもなくメンタルをすり減らす繊細な作業である。
そのために、持っておきたいメンタリティについて、説明をしておく。
怠惰であれ
コードは少なければ少ない方が読みやすい。
特に、複雑な if elseif なんて書いたら明日の自分が読み直すのには、かなり疲れてしまう。
めんどくさい。書きたくない。読みたくないものは書かなくていい。
とにかく、自分が何故それを書かないといけないのかを意識することがとても大事になる。
もしかしたら、他人がかいてくれているかもしれない。そう、思うことが、キレイにつながるのである。
自分は天才ではない
コードが書けるだけで、結構ちやほやされるだろう。だが上には上がいる。まず、天才とは思い上がっていなくても、自分のコードが最強と自負してしまう瞬間は誰しももつときがくるだろう。
ただ、凶悪な質問をつきつけておく。
あなたは、アメリカ語がネイティブではない。
あなたは、数学科を履修したわけではない。
あなたは、カリフォルニアやシリコンバレーで働いているわけではない
あなたは、研究室で研究をしているわけではない。
あなたは、OSSに対してPRを投げたことはない。
あなたは、OSSのメンテナーではない。
あなたは、競技プログラミングで優勝はしていない。
あなたは、MENSA会員ではない。
さて、何個あてはまっただろうか?
少なくとも1つ否定できるだけでも、素晴らしいことではあるが、それでも頭に乗ってしまうと、キレイなコードからはかけ離れてしまうのだ。
筆者が思う、キレイとは、プログラミングでの文脈でいうと、世の中の8割のエンジニアが読解可能であるということを指す。
怠けるための努力はおしまない
先ほど、怠惰でいろといったが、怠惰だけでは、職を失ってしまう。
まぁ無職がいいというのであれば構わないが、残念ながらサラリーマンだ。
給料分の仕事はしなければいけない。
というわけで、最低限の仕事をしよう。
それは、自分に仕事を預けるわけではなく、コンピューターに仕事を代替させることである。
Linterの構築、DEVOPSの採用、コードジェネレータの採用、古臭いところなら、バッチでの構築など、自動化に対して強く興味をもつことが重要だ。
3.腐るコード
さて、メンタリティについては話したが、これらを踏まえて、コードの改善をしていきたいと思う。
実践に移る前に、どんなコードが腐ってしまっているのかを、自らの現実をみて語っていく。
腐りやすいコードには、傾向がある。
緊急度別に腐るコードを分けていきたい。
筆者の思想はあるが、宗教戦争がしたいわけではないので、批判はしないでほしい。ただ、事実として述べているのである。
互換性のないコード
バージョン互換のない記法は、とにかく腐る。
deprecatedなどは、絶対に使用してはいけない
Rubyなどバージョン互換が危ういプログラミング言語は、腐りやすい未来性を想像できなかったコードは、腐っていく
未来性を想像できなかったコード
もはやCTOのせいであるとは言えるが、CTOの練度が低いと誤った技術選定をする。もし、自分がCTOに意見する立場にあるのであれば、W3Cの動向や、ビッグ5の後ろ盾、GitHubのスター数などを根拠に誤った技術選定を止めよう。
結局、覇権を取る言語・技術選定がキレイを生むのだ。
車輪の再開発コード
独自型の実装、Wrapperなどが怪しい。
車輪の再開発するくらいなら、もしも、フレームワークにバグがある等でやむなしでWrapperを書いてしまった場合には、ちゃんとタグやアノテーションで警告しておくことをオススメしておきたい。
オレオレフレームワーク
プログラマーは上記のように、コードを書くのが仕事というわけではない。最適な技術を選定して、最短ルートでお客様に目的を達成させることが仕事だ。
今はもう、たいていのことはフレームワークが存在する。
試験的機能の実装
フレームワークに試験投入される機能は存在する
試験機能は、趣味プロで満たして、Stableまで待つことがよい
チーム不理解の機能を利用した実装
技術的な探究心自体は評価したいが、チームにまで波及しないと意味はない。チーム開発において、チーム理解は不可欠であり、全員の意思疎通がとれていないコードは、結局のところ独りよがりで書き換えられてしまうのだ。
長い、でかい、山脈が多い
これはもう、直感に近いがそう感じたコードは大体死ぬ。
読みたくない。読めない。捨てよう。となってしまう。
副作用モリモリ
副作用とは、名前に対して、実際にはやってはいけないことをやってしまっている作用と考えてもらって問題ない。薬でいうと、下痢薬がホントは頭痛にするとかこういうことだ。
その頭痛にエンジニアの頭は痛くなっていくだろう。
上記は、今までみた実装の例をあげた。
リファクタリングを経験したことがあるなら、見たことはあるであろう。
実際に言語化するのは難しかったが、大別すると大体は上記にあてはまるのではないだろうか。
コードクローン
コピペコードが大量にある場合には、かなり細心の注意が必要だ。
4.実践するキレイなコード(技術選定編)
そもそも、一発目からキレイに書くための方法を考えていく。
リファクタリングについてはさんざん本がでているので、本読んでくれ。
該当する本については、巻末で紹介する
後方互換性がないモノを利用しない
エンタープライズコードは自分が思っているよりも、プロダクト・ライフサイクルが長い。
開発者が優位に立って、すぐにドラスティックに変化するフレームワークや言語を利用すると、本来は仕事ではないバージョンパズルを永遠と実施する羽目になる。同じ動きをしているのにだ。
これは、ひとえにエンジニアの仕事の目的を忘れて、技術に全振りしている活動だ。
すでに存在する場合には、どうしても実施が余儀なくされてしまうのであるが、目をつむるわけにはいかない。盲目的にバージョンパズルするぐらいであれば、書き直しも一つの検討として正しくCTOにエスカレーションするべきである。
未来性を予測して技術選定をする
5 Programming Languages That Are Probably Doomed
こういう記事は、しっかりと着目しておいたほうがいい。
言語を批判しているわけではない、需要が消失しているという事実が書かれているのである。
Rubyに関しては、周辺ツール、Ruby on Railsでかなり利用が多いので即座に消えてなくなることはないだろうが、ホントに2年以上Rubyの相手をしているとバージョンパズルの多さに辟易とすることだろう。
フレームワークの選定も後押しが誰であるかが、とても重要となる。
はっきり言って、企業の後ろ盾がないフレームワークの利用はいかに先端的であったとしても危険きわまりない。
具体例でいうと、Fuel(PHP)とかである…
メンテナーの人間関係についても、もしアメリカ語が読めるのであれば敏感になっておいてもいいかもしれない。
GitHubの★が多いからといって安堵していてはいけない。
GitHubのコードは結局メンテナーがへそを曲げればそこで終焉をむかえるのである。
フレームワークをフル活用する
フレームワークを熟知して、フレームワークをできる限り活用する。
それには、やはり、フレームワークの理解が非常に重要であり、ミーティングを開催して、まずはフレームワークの勉強会などを行って使うモノを選定しておくといいかもしれない。
個々の学習に委ねると事故が起こる。
フレームワークにバグがあった場合、予期しない動作がある場合には、Wrapperを利用するか、本家にPR(ないしはMR)を送ることを検討しよう。
Wrapperを利用する場合には、いつか修正されることがあるかもしれないので、PRとセットで書くことも検討したほうがいいかもしれない。
フレームワークを利用しろと言っているのは、天才でもなければアメリカ語を話すわけでもない我々が、精一杯に、サボることができるのはこの点にある。
オレオレフレームワーク・車輪の再開発
※ あなたが、Google、Apple、Microsoft、Amazon、Facebook、Meta、Apache、その他名だたるオープンソース企業に属していない場合に限る
そもそも、作るな・・・
間借りしろ。
5.実践するキレイなコード(実装編)
実装手法については、以下の本や資料が参考になる。
リーダブルコード
エリック・エヴァンスのドメイン駆動設計
リファクタリング
デザインパターン
ここでは、実装する上での心持ちについて、補足しておく。
ネストは2段、いってしまっても3段
とにかく、ネストすることを嫌ってほしい。
ネストをみると、読み手はうっ頭がっってなってしまうことを意識してほしい。
if ネストはガード節や、関数書き出し、条件の見直しなどで大抵は対応可能であるはずだ。
Ctrl +Cは、破壊せよ
Ctrl +C(つまりはコピー)なのだが、ソフトウェア工学的に再利用性が重要なのでコピーするぐらいなら関数書き出しをしたほうがいい。
現在の高級言語においては、Classの継承やジェネリックなど、コピーに対する対策機能がいっぱいはいってるはずだ。
もし、コピーしたいモチベーションになったとしても、コピーせずに写経してみよう。なにかコピーしない手法が思いつくかもしれない。
責任の所在を考える
責任を考えるモノは多数ある。
クラス
関数
利用するフレームワークのクラス
利用するフレームワークのクラス
変数
上記すべてに対して、責任は存在すると考えて実装することだ。
また、単一責務であればあるだけよい。
複数の役割を持たせてしまうと、その時点で、読み手の頭は混乱する。
その他
多くのことを書いても、本書くレベルになるので、とりあえず、筆者がとくに意識していることだけを書いた。
この3点だけでもかなりコードは改善されるはずだ。
詳細に方法を見たい場合には、上記にあげたような本を読み直すことをオススメする。
最後に
正直、こういった記事に需要があるかどうかわからなかったので、自分の思いをぶつけてみました。
AIに比べたらエモさはないかとは思いますが、商業エンジニアのあなたならわかってくれると思います。
ただ、最後に一ついいたいのはキレイに書くはあくまでも目的ではない。とは言っておきます。
キレイに書く目的は、保守性をあげて、長いプロダクトサイクルに対応することであって、すぐ捨てるプロダクトにおいては、キレイである必要などはないのである。
目的は見失わないように…