Kandoの日記: リファクタリング負債 6
あるエラい人は言った
「リファクタリングしないまま変更を繰り返したコードは負債(=借金)と同じだ。」と(言い回しの詳細は違うと思うが)。
そう、部屋の掃除と同じくコマメにやっとかないとプログラムは容易に魔窟と化すのだ。
そして今、職場の私の目の前には異動したかつての同僚が遺していった開発開始以来3年間殆どリファクタリングされてこなかった(と思われる)約15万行のモジュール(パッケージ複数)のJavaコードがあった。
・・・リファクタリングをやってもやっても終わらねー!!!!11!!!1!
* 一個しかインプリメントがないインターフェース、そしてそのインプリメントが抽象クラス(で、その抽象クラスの具象クラスも1個だったり。)
* パッケージを越えて入り乱れる依存関係
* 長大なメソッドが1個しかないクラスの氾濫。そのうえそういうメソッドの名前が(クラス同士は何の親戚関係もないのに)全てexecute()
(使われ方は 殆ど全てが(new XXX()).execute()だった。)
* ファクトリと名前がつきながらファクトリ・オブジェクトでもなんでもないただのファクトリ・メソッドの集まり
* 結果が使われてないのに何故か呼ばれるgetXXX()メソッド、その上呼び出しを取り除くとバグる(=見た目getterのくせに何か副作用があるらしい。)
* 見た目getterなのに渡された引数のオブジェクトの中身を書き換える(上記の謎の副作用のあるメソッドとは別の)getXXX()メソッド
* 明らかに足りないテスト・ケース。数十個もクラスがあるパッケージにテスト・クラスが一個?
(まぁ6つくらいのクラスのテスト・ケースが詰め込まれたテスト・クラスもあったけど、それでも全然足りてない。)
* 意味深なXXX2とかいうクラスの蔓延(対応するXXXやXXX1とかはない。どうも要するにVer.2ってことらしい。)
etc.
ある意味、15万行規模のコードがこの状態で今まで曲がりなりにも(若干バグの出やすい脆弱なモジュールではあったが)機能が維持されてきたことが奇跡。
まぁviユーザにリファクタリングしろといってもピンとこないのかもしれないがー。私もIDEに組み込まれるまでリファクタリングといわれてもあんまり有難そうには見えなかったからなぁ。
「リファクタリング」なんて用語は飾りです。IDEを使っている人達はそれが判らんのです (スコア:1)
いや、言ってみたかっただけ。
リファクタリングはかなり重要ですが、昔の人はこういったものです。
「いいか、奥山。
お前のプログラム能力は低い。恐ろしく低い。
だから。あるプログラムを1回で完成させようと思うな。
同じプログラムを2回書け。しかも異なるプログラミング言語で2回書け。
一回目、組んでみるとうまく表現できない部分とか、えらいややこしい事になる部分が出るはずだ。
それはデザインが腐っている証拠だ。だからデザインをやり直せ。
で、何度かデザインをやり直したら、別の言語でそのデザインで組んでみろ。
すると、今まで「当たり前」だった事が当たり前じゃなくなる。
そこもデザインが腐っている部分だ。デザインをやり直せ。
ま、こうして大雑把に2回ぐらいコーディングをやり直せば、まともなデザインと、まともなコードになる。
それに合わせてドキュメントを書け。
一見、遠回りのように見えるが、こうすることでデバッグサイクルを回す必要性がほとんどなくなる。
同じ事を2度書く手間なんぞ、デバッグサイクルを回す回数が3回減れば十分お釣りが来る。」
.
同じ言語で再デザインなんて駄目です。違う言語を使わないと。
そして違う言語を使えば判りますが、それはリファクタリングとは呼びません。
書き直し と素直に言います。
そうすれば気分すっきり。過去との互換性なんでバッサリ。
というわけで、 emacs 使いは「リファクタリング」などという表現でやっていることを誤魔化さないのです(^o^)。
.
ま、どう表現しようが。一度コーディングをしてみないと、見通しが立たないことってたくさんあるんだから、デザインにまで立ち戻るって大事だよね。
fjの教祖様
Re: (スコア:0)
IDEのリファクタリング機能は半端ないよ。
再デザイン&再コーディングとか、時間が有り余ってれば別にいいけどさ。
その際の無駄を省くようにリファクタリング機能があるんだから。
Re:「リファクタリング」なんて用語は飾りです。IDEを使っている人達はそれが判らんのです (スコア:1)
IDEの(具体的には例えばEclipseの)リファクタリング機能は、それ以前に比べれば驚異的です。
だけどあくまで小規模リファクタリング限定です。
>* 結果が使われてないのに何故か呼ばれるgetXXX()メソッド、その上呼び出しを取り除くとバグる(=見た目getterのくせに何か副作用があるらしい。)
>* 見た目getterなのに渡された引数のオブジェクトの中身を書き換える(上記の謎の副作用のあるメソッドとは別の)getXXX()メソッド
>* 明らかに足りないテスト・ケース。数十個もクラスがあるパッケージにテスト・クラスが一個?
こういった部分は比較的小規模(中規模?)のリファクタリングでありながら、これさえも
「IDEで自動的に」というわけにはいきません。
また使える言語が限られるのも問題です。動的で型付けの甘い言語だと、
IDEのリファクタリング機能はほとんど実現不可能です。
Re:「リファクタリング」なんて用語は飾りです。IDEを使っている人達はそれが判らんのです (スコア:1)
まぁでも小規模リファクタリングを利用すると中規模リファクタリングも楽になるのが助かります。
(今回インターフェースとインプリメントを統合する際に多用したプルアップとか結構Eclipseがギブアップすることが多いけどそれでもないよりは作業は楽だった。)
手作業でコピペしたり書き直したりもあるけどかなり減らせるのがありがたい。
Re:「リファクタリング」なんて用語は飾りです。IDEを使っている人達はそれが判らんのです (スコア:1)
再デザイン&再コーディングをやったことがない人に限ってそういう事いうよね。
でも、そういう奴に強制的に書き直させると、頭の中で整理されなおした問題点などがコードに反映されるのですっきりとしたコードになります。当然、すっきりしたコードにバグは少ないし、無駄も少ない。
結局この後のユニットテスト・結合テストでも問題がほとんど発生しないので、精神衛生上も楽。で、トータルで見ると、再デザイン & 再コーディングの方が時間が余る。
.
時間が余ってるから再デザインしてるんじゃないんです。再デザインしているから、時間が余るの。
因果を取り違えちゃ駄目。
fjの教祖様
言語はちょっと変えられません (スコア:1)
再設計に関する理想はわからなくもないのですが、そのモジュールだけでシステムが完結してるわけでないので言語は変えられません。
利用しているライブラリ、フレームワーク、問題なく動いている他のモジュールが存在します。
教育目的というわけではないので全部ご破算にして書き直しというわけにはいきません。
あと複数人でやっててコード引き継ぎなんで、引き継いだ部分の設計は現時点で私の頭の中にありませんから、
私が1から書き直す場合は新規設計1周目をもう一回になってしまいます。
で、書いた人はその部分に関する論文も書かずに異動し、ドキュメントもなくはないものの十分とは言い難いので
引き継いだ私がメンテナンスと論文のためにコード読まないといけないのですが、なにせそのコードが魔窟なので、
まず形式的な書き直しである程度整理してからじゃないと読む気にもならないという状況なのです…。
その彼のプログラムに関しては私自身の過去の絶叫体験から、日記に書いた部分はまだ魔窟ではまだほんの入口に過ぎず、
内部にはもっと想像を絶する、動いているだけで奇跡を感じられるようなエキゾチックな設計が隠れていることを私は恐れています。
かつてC++で書かれた大量のDLLをトップレベルのRubyへロードするというそれ自身がアレなコード内で
独自のミニ言語で書かれたスクリプトに従いSQL経由でDLLを取り出すようになっているのを見たときは正直そのあまりの過剰ップリに悶絶しました。
彼はかなり過剰な抽象化により過剰な柔軟性を作りこむ傾向がある上に、手がやたら早く、かつプレゼンがわかりにくいので
ちょっと目を離した隙にどんなエキゾチックな設計が実現されていることか…。
(私も自分でしばしば過剰に作りこみすぎると思っていましたが、まったくもってその比ではなかった…。)
例えば今回もコンパイラ内部、バックエンドにほど近いちょっと普通みかけない部分、
フロントエンドでも設定読み込み部分でもアセンブリをエミットするためのパターンマッチ部分でもないと思われる、
普通に考えて外部から何も読み込んでいないと予想される部分に
パーサ・ジェネレータで生成されたパーサが合計3つも見つかっていて、
なおかつ実行時に動いてなにかやっているらしいのを見かけているので油断なりません。
(多分何かの内部インターフェースに独自のミニ言語がつかわれていると予想される。)