へっぽこびんぼう野郎のnewbie日記

けろけーろ(´・ω・`)! #vZkt8fc6J

『こうあるべき』だけど、実際はそうなっていない設計[技術的負債]を解決しなければいけないときにどう動けばいいのか

まえがき

「こうあるべき」という思想

プログラミングにおいて『こうあるべき』という事態はとてもたくさんある。
それはもう『こうあるべき』とだけ発言する声帯モジュールを、すべてのエンジニアに実装したほうがいいのではないかと思うほどとてもたくさんある。

クラス設計もそうだし、テストを書くのもそうだ。
コードの書き方もそうだし、そんなの標準ライブラリにあったんだという見落としや、
すでに誰かがオープンソースで開発してくれていたのに知らなかったとか、
自分の技術力が低かったせいとか、いろいろある。

 『最初からやっていれば、簡単だったのに』

という状態は、日常茶飯事だ。

なお、ここでいう『こうあるべき』には、
『バグのせいで、そうなっていない』というものは入らず、設計に関するお話だけだ。

なぜあるべき姿にならないのか

知識不足だったり、
リリースに追われていたり、
そもそもこの先どうなるかわかっていなかったりが、
大きな原因だと思う。

でもそんなのかんけーねぇ

『こうあるべきだった』ということは把握した。
じゃあどうするのか?

どちらかと言うとそちらのほうが難解な問題だ。
この記事では、そこに言及しようと思う。

具体例

20代で童貞の人に、
「高校生のうちにセックスしておいたほうが絶対よかったのに」
と言うのはすごく簡単だ。

でも、いま20代で童貞の人がまた高校生になってセックスするためには、
まず時間遡行技術を開発しなければいけないのだ。

現実的な選択肢としてあげられるのは、

 『高校生のうちは無理だったけどセックスするためにナンパでも始めるか』
 『風俗に行くお!!!』
 『セックスなんかしなくても人間は生きていけるんだ! やったー!』

などのようなものだ。
つまり、あるべき姿と解決方法というのは、実態と離れれば離れるほど違うのだ。

解決方法として考えられる選択肢

方法1: つくりなおす(≒ リファクタリングする)

ソースファイル as 文字列の集まり

方法の説明の前に、まず次の概念を説明しておきたい。

ソースファイルも、やっぱり単なる文字列の集まりにすぎない。
ぼくたちが文字列の集まりに対してできることは、

 『追加』『読み取り』『更新』『削除』

で、CRUD [Create, Read, Update, Delete] だ。

実際のところ『更新』は

 『更新』 ≒ 『読み取り→削除→追加』

なので、そこまで重要ではない。

なぜこんなことを言うかというと、
基本的に、これ以外にコードを扱う方法はないということを言いたいからだ。

リファクタリング概要

つくりなおすべき範囲(スコープという)は以下のようにさまざまある。

 プロジェクト全体
 モジュール(ライブラリ・パッケージ)単位
 1つのクラス
 いくつかのメソッド
 1つの関数
 データベース設計
 システムアーキテクチャの変更
 プロビジョニングファイルの書き方
 使用ツールの変更
 ... etc

つくりなおすということは、技術的方面から解決できる唯一の方法である。
これ以外の方法は存在しない。

『挙動の変更はしないが、内部を変更する』
という概念こそがリファクタリングだからだ。

厳密にいえば、
リファクタリングではない『UI変更』などの単なる『変更』もあるけれど、
それも『プロダクトを使う目的・得たい結果』を『引数・返り値』として考えれば、
リファクタリングのようなものだ。

ここでは「つくりなおす」において大部分を占めるリファクタリングについてはなす。

// 『変更』とはCRUDでいう『更新』のことだ。

リファクタリングのやりかたの概要

王道なやりかたは、

 『既存のコードに対してリファクタリングのためのテストコード書く』
 →『リファクタリングする』

だけど、そもそもテストコードが存在しないレガシーコードが、この世の中には多い。
あと尋常じゃなく長いメソッドとか、まじげきおこ。

このやりかたは、
『テスト文化』『テストとかしたことないけど導入できる雰囲気的文化』
が根付いていないような

 『いまちゃんと動いているのに、ソースかまうとかなにそれこわい』

的な会社では、まず会社をリファクタリングしなければいけなくて、
会社にいきなり導入はできない。
もし導入するならば、高いコミュニケーション能力、そしてカリスマ性が求められるはずだ。

実際こっそり自分1人だけで使ってみて、良さそうな感じになれば、
それを実績として提案することもできるだろう。
でもちゃんとテスト書いてる会社に転職したほうが絶対いいよ。

テストコードが必要な理由

『テストコードを書く』というのは、簡単に言うと『自動テスト』を作ることだ。
人間が『ちゃんと動いているかな〜』と確認することも『テスト』と言うが、
これは『手動テスト』と呼ばれる。
手動テストは、何度も同じ操作をしないといけないので、めんどくさくて、だるいのだ。
何度も同じことをやるなら機械にやらせたほうがいい。
そのためのテストコードだ。

開発中『ちゃんとこのメソッド動いてるかな〜』と適当に値を入れて確認しながら、メソッドを作っているのは
テスト駆動開発を導入していない会社でもやっていることだと思うのだが、

実は『ちゃんとこのメソッド動いてるかな〜』という確認こそが
単体テストそのものであり、

その『ちゃんとこのメソッド動いてるかな〜』の部分を自動化した開発方法を
まさにテスト駆動開発と呼んでいるのだ。

とどのつまり、テスト駆動開発とは、それだけのことだったのだ。
まぁ細かくいうと、もっといろいろ嬉しいことがあるんだけど、コア部分はこれ。
みんなそれをむずかしく言っているだけ。

『騙されたと思って使ってみなさい。便利だということがわかるよ』
という解説があまりにも多くてぼくはおどろいた。

『テストというと学校のテストを思い浮かべる人もいるでしょう。それとは違います』
という解説記事すらもある。

違わない。

 『生徒がちゃんと因数分解を理解できているか』という中間テスト
 『うちの大学で学ぶ能力があるか』という大学受験
 『弁護士として働ける知識があるか』という司法試験

これらと同じ。

 『因数分解わかると100点とれて、成績あがっていい高校にいけるぞ試験』
 『受かったらこの大学入れてこの先の人生はひとまず順風満帆だぞ試験』
 『受かったら弁護士の卵になれるぞ試験』

という側面しか見ていないから、違うようにみえるんだ。
なお常に100点満点じゃないといけないのがプログラミングのつらいところだ。

テストコードがない場合

もしテストコードがないとリファクタリングしたあと手動テストするのに労力がかかって、
そして「え、そんなとこに影響出るの!?」みたいな見落としがあったりもして、
デグレードしてしまう確率が非常に高いため、リファクタリングにテストコードは必須だ。
デグレードしてしまう確率は、隕石が頭に降ってこない確率より高いだろう。

とは言うもののべつにテストコードなしのリファクタリングをすることも可能だ。
しかしこれは『勇気のプログラミング』と呼ばれ、
ソース変更によるデグレードの恐怖と日々戦いながら、まるで

 『ささやき いのり えいしょう ねんじろ』

のように、
「たのむぅっ! バグがでないでくれぇ!」と祈ることになる。

でもバグは出る。現実は非情である。

それでもテストコード書きたくない人へ

多くのテスト解説記事は、足し算・足し算ができているかのテストで構成されているけど
あんなものは役に立たない。

たとえば足し算をする関数をつくるとき
ちゃんと足し算できてるか確認するテストコードなんて、
書いたって意味がないように見えるから、

 「そんなのあたりまえすぎるから、書かなくていいじゃん。おまえなにがしたいの」

と思うはずだ。

ぼくもそうおもった。

しかし足し算をする関数引き算をする関数のような、
簡単な目的の関数を1000個書いてくださいと言われたら、
あなたは確実にバグを生み出すだろう。
+の代わりに、間違えて*にしているかもしれない。

テストコードは、工数を多めに取る代わりに、別の側面からチェックをすることによって、
リリース前にバグを発見することができるうえ、
「あとで使い回しができるから便利だよ」というものだ。

だからテストを書いたからといってバグがなくなるわけじゃないし、
テストがバグっていることもある。
でも、
 足し算をして値を返すものを作ること
 ちゃんと足し算できてるか確認するものを作ること
と、異なる側面から、1つのものを見ることができるので、
コードをわかりやすく書くことができ、確認しやすいように関数・メソッドを分割するようになる。

テストコードがなくてもいい場合

ありとあらゆる場合にテストコードが必要になるわけではない。
また実を言うと、これがテストコード不要論を唱える人たちの根拠でもある。

最初から完璧な設計ができており、ゴールが見えている場合においては
テストコードなどというものは必要ない。

また、小さなプロダクトでは、
テストを書くより実際自分がやりたいことと書いたものを照合する手動テストのほうが早く、全ソースコードを把握することもできるため、
そういうときは、別にテストがなくてもなんとかなる。
1プロジェクトで、2万行以下なら1人ですべて把握できるから大体大丈夫だ。

 じゃあ100人なら200万行いけるよとかそんなこと言ってないよね?

ただしそれは最終的なゴールが2万行以下であることが確実なときに限る。

それから、テストコードを書く技術というのは、ひとつのスキルなので、
誰でもすぐにできるものではない。
工数が余計にかかってしまい、メリットを享受する前に、
「なんだこれ。使えないじゃん!!」と終わってしまう可能性すらある。

ちょっとテストについて書きすぎてしまったので、他のくわしい情報は
ググッてみつけてほしい。

まとめ in つくりなおすこと

 テストコード is 『短期的には工数を犠牲にするが、長期的に開発を楽にしてくれる頼れるアイツ』

 やっぱり神様なんていなかったね。

 じみちにリファクタリングしようね。


方法2: あきらめる

リファクタリングはむりです!!!!!!

 複雑怪奇なスパゲッティコード
 足りない人材
 襲いかかる納期
 あきらかな設計ミス
 テストってたべられますか
 これって仕様バグなんじゃないの
 そんな技術ないからわかんないにゃ
 リファクタリングする暇があったら働けとか言われる

わらえる話ではない。
リソースが足りない場合は、どうしてもこうなりがちだ。
技術的にリファクタリングは無理な状況というのはある。

だって凄腕な人は、そもそもそんな変なコード書いたり変な設計しないから、

 「え、これを直すの? ぼくが1から書いたほうがはやいよ(*´∀`*)」

とか言って、ほんとうに1から書いてすぐ作って、
大人数でやったあとには、ゴミを生産したという結果だけが残った。
みたいなことがほんとうにあるのだ。

とりわけ、既にデータが入っているデータベースをリファクタリングするのは、

 狂気だ。

でも解決はしないといけない。

げんじつをうけいれよう

「こうあるべき」という状態にするのは、もう絶対に不可能なので
それを受け入れることが最初にやることだ。

「これはファッキンクソうんこなのだ」と心を落ち着けるのが
いちばん重要なことだ。

心を落ち着けたあとは、一回寝よう。
次の日に驚くべき解決策が頭に浮かんでいることもある。

もちろん浮かぶはずがないので、
そういうときはとりあえずコーヒーを飲もう。

ラッパークラスを作ってみる

『うんこの中からほしいリソースを取り出すために、手袋をつくる』という手法だ。
データベースでいうとCREATE VIEWだ。(データベースがうんこというわけではない)
速度は遅くなるが、インターフェースとして活用できるので、一見解決策のようにみえるけどちがう。

でも、そんな暇ないしそれもムリだよ

エンジニアには欠けている思想(ぼくも含め)だが
マネジメント側・営業側でなんとかしてもらうということもできる。

もっと言うと、マネジメント側・営業側と

 「なぜできないのか」
 「客はそれでおkなのか」
 「とりあえずなんとかならないのか」

というコミュニケーションができていないと、
解決できない問題にいつまでたっても取り組むというめちゃくちゃ意味のないことをやるはめになるうえ、

 「それべつにできなくても代替方法があるならおkだよん」

みたいなこともあるので、だいじ。

ただ、これは自分の技術力では手に負えないという

 『技術者としての敗北宣言』

であることをちゃんと肝に銘じておかないと、単なる技術力ない人で終わってしまうので注意だ。

そもそも意味不明なものを作らされているし、意味不明だって言ってもとりあえず作ってとか言われる謎状態の場合

深く考えず、適当に意味不明のものをつくればいいとおもう。
そして鬱病になる前に転職しよう。


 IT業界はいつでも人手不足だ!!!



その他の方法

ない

 ないよ (*´∀`*)



おわりに

結局技術力・知識をひたすら身につけておくことしかできない

魔法はない。
普段から研鑽することで、技術的負債を解決できる能力というのを会得できるのだ。
わからないからしんどいのだ。
そして何がわかっていないのかもわからないからしんどいのだ。

大学数学に、小学生の算数レベルの知識だけで立ち向かったって解けるわけがない。

これはそれとほとんど同じお話なのだ。
近いことはやれたとしても、答えにたどり着くことはできない。

銀の弾丸はない」なんてかっこよく言われてるけど、
「足し算を知らずに微分積分を理解する方法はない」と同じことだ。

いやがんばれば足し算という概念を経由せずに積分の概念を理解できるかもしれないけど
ぜったいそれできるやつって、足し算知ってるからね。

あるべきおじさん

「こうあるべきだ」と言うだけならかなり簡単だ。
じっさいぼくもよく使ってしまう。
「こういうふうにつくればよかった」「なんだこれはひどい」みたいなことをよく言う。

でも、「あるべきあるべき」と言って、なんとかしようとしていなければ、
結局ただの愚痴を言っているひとになってしまう。

 「こうあるべきだから、なんとかしてその方向に直そう」
 「こうあるべきだけど、これはそこまで重要でもないし問題ないからおk」

みたいな感じの、かっこいい『アルベキスト』になりたいとぼくは思う。

おわりのおわりに

考えながら書いてたら、結局

 「銀の弾丸ないわろた」
 「テストコードの話しかしてないわろす」

みたいになってしまった。つらい。
なんか5時間ぐらいかけてこの記事書いたしさらにつらい。
ねむい。

へんなとこあったらコメントとかで指摘してもらえるとありがたいどす。

あとこれたぶんスマホからだと読みにくいとおもう。