プログラミングの基本、共通化 / Don't Repeat Yourself. | 熱脳しゃちょのブログ

熱脳しゃちょのブログ

おせっかい焼SE兼プログラマ兼……の辛い日々と、思う事なぞ

同じ(ような)処理はまとめて再利用できるようにする。

 

というのは、多分プログラミング講座の最初の方で教えられるありがたい「お言葉」の一つだ。

確かにそれは正しいのだが、いついかなる場合も正しいとか、ぱっと見まとめられそうなものはまとめ「なくてはならない」というわけではない、という大事なことが教えられてないか、教えられているとしてちゃんと理解されていないのではないだろうか、と思う(DBの正規化とか、同じような構図は中小規模の瀕死プロダクトではかなりの割合で見られると思う)。

この「同じような処理はまとめる」原則が声高に主張されるようになったのは、安易にコピペして小改変を施された亜種が大量に繁殖して、バグが発見された場合に除去しきれない、という事態が蔓延していたというのが1番の理由なのではないかと思うのだが、これはそのような当時の状態に対する警鐘であり、この例として挙げられるものは、当然ながら「まとめられる」「まとめた方がいい」ものだけのはずだ。

なぜなら、そのための例示だから。

そこでは「まとめたら後で地獄」な例は、多分紹介されていないだろう。

これをやると機能追加やら仕様変更の時に想定外の工数がかかるし、テストがない場合は高確率で「不具合」が発生する。

今ヘルプに入っている現場がまさにそれで、この大量のスパゲッティーを生産したプログラマが逃げ出して困っている。

ので、少し解説する。

 

1.形式的にパラメータ化できそうだが、処理のコンテキストが異なる処理

今の現場はこれが多用されていて、かなり難儀している。

開発当初は機能も少ないので、いろんな機能で同じような処理が現れることがある。

だが、処理のコンテキストが異なる場合、開発が進むとそれぞれのコンテキストで特有の変更がかかる可能性が高い。

なぜなら「コンテキストが違うから」。

共通化するのは「何があろうと(処理コンテキストによらず)この部分は絶対に同じ」という「論理的共通処理」でなければならない、ということだ。

ここら辺、理解している人にはごく当たり前で、判断できる人には自明なんだけど、そうでない人の中には区別がつかないっぽいのだが、もし区別がつかないのであれば、悲劇を繰り返さないために転職を検討していただきたい。

とにかく、今の現場はこれが二重三重四重に張り巡らされていて、しかもテストがないときて、かなり難儀している。

 

2.疎結合にしようとしている境界を越える共通化

これは一つ前の現場で、何回説明しても理解できない技術者がいてうんざりした問題だ。

今流行りのマイクロサービス()は、マイクロサービス間で疎結合にしないと意味がない(意味がわからない人がそれなりの数いるなら、別途記事を書く)。

なので、各アプリ間で共有されるのは、インフラ周りくらいに留められるはずだ。

インフラ周りとは、そのクラウドサービスの各サービスを利用する共通設定部分と、汎用的な便利クラスくらいかな? 頑張って、そのサービスの根本要素くらいまで。

DRYの原則に従って、ドメイン層を共通化(1ライブラリ化)しなくてはならない、という声があるとしたら、マイクロサービスの理解ができていないカーゴカルト信者である可能性が高い。

ましてやapp_baseとかいう、全てのInfra層、Domain層を取りまとめた「神のLibrary」を、ほとんど全部のAppから参照するとかいうチョークポイントを自ら作り出しておいて、「DRYを知らないんですか?」とか嘲笑ってくるとか、もうね。

これをするということは、どこを変更しても全マイクロサービスを一括してデプロイしなくてはならないという、モノリスを割って運用の手間を増やしただけという事態を招くというのは自明だと思うのだがな。

実際、一つ前の現場は、小さなバッチひとつ変更するだけで、全アプリケーションサーバを、「え?こいつも?」というくらい無関係そうなものも、デプロイし直さなければならないとかいう馬鹿らしい運用になってしまった。

しかも、「これが正しいマイクロサービスの運用法だ」とか、件の技術者は胸を張る始末。

おかしいとの指摘にも「熱脳しゃちょの言うようなことが書かれたWebページを見たことがない!」と言いふらす上に、他の技術者も「Webページがないのなら正しくないんじゃないか」とか、もうね……。

理解できる人には自明だし、理解できない人には書けないからWebページで紹介されないだけだと思うんだ。

マイクロサービスでやるなら、初期はコピペで、更新は「下位互換を保って(例えばDBの変更なら、Default値をつけておくとか)」、「自動テストで健全性を担保して」開発を進めるのが正しい手法です(もちろんライブラリの参照バージョン厳密指定を使うこともするが)。

DRYの法則ガー、って、そもそもDRYの法則によって巨大モノリス化したプロダクトに対するアンチテーゼがマイクロサービス(とDI)なんだから、DRYの法則を持ち出すのは論理的におかしいことに気づくべきではないだろうか?

 

ちなみに、このような背景から、マイクロサービスとDIの相性は良くないと思っている。

最近の現場は大抵この両方を採用しているのだが、手間が倍になって、しんどさが2^2で4倍になっている気がする。

DIはテストの時に……とか先任技術者が言うんだけど、そもそもそのテストがろくに存在しなかったり、ぱっと見、テストの項目数は十分あるのだが、「カバレッジ100%は神話」「モックは神」が「実際にはほとんど何もテストしてないテスト」を生み出し、テストは全部通ってるのになぜかデータ不整合や消失、デプロイのたびに新種の障害発生とかいう、アリバイ工作の意味すらない現場というのもあってだね……(モックは擬態先の仕様変更に合わせてメンテし続けなければならないから本当はむっちゃ大変なんだよ。マイナーバージョンアップにすらついていけなくなったりね)。

 

 

 

正式な教育を受けなくてもプログラマになれる、と言われる。

Web上に情報は唸るほどあるから。

それは一面的に正しいが、少なくとも最低限の論理的思考能力は必須で、それには大部分の人にとっては「正式な教育」が必要だろうし、正式な教育を受けても全く不十分、ということも少なくない(ざっと見て、IQの壁があるような気がする)。

Web上の記事は、歴史的推移などのバックグラウンドが乏しく、しかも頻繁に劣化再掲載が行われているため書かれた日付は根拠たりえず、ある手法と食い合わせの悪い手法というのが並んで表示されることも少なくない。

その全てを「教科書に書かれた通り正しい」と無批判無条件に取り入れると、まず間違いなく「プログラマ逃散悲劇的プロダクト」に育つので、マジでやめていただきたい。

全ては論理的に考えれば明らかで、そこが捻れたプロダクトの運命は、やはり捩れるものなんだよね。