Rのつく財団入り口

ITエンジニア界隈で本やイベント、技術系の話などを書いています。

【感想】『リファクタリング 既存のコードを安全に改善する (第2版)』:20年を経て生まれ変わる名著

伝説的名著の2版、題材はJavaScriptへ! (Pythonじゃなかったぞい)

 本の感想エントリです。外部から動かした際の動きを変えずにプログラムの内部構造を改善し、メンテしやすさや拡張しやすさ、コードを書いた人以外からの理解しやすさや扱いやすさを改善していく手法である「リファクタリング」。
 よくソフトウェア工学や開発の現場で出てくる単語ですが、このリファクタリングの教科書と言えばタイトルがそのまんまの『リファクタリング』。英語版は1999年刊行、腕に覚えのあるITエンジニアの方なら2000年代~2010年代にかけて読んでいる人の多い、あのマーチン・ファウラー大先生の有名な本でした。この頃世に出たオブジェクト指向デザインパターン、開発手法などの本と同様、言語の題材はJavaとなっています。
 その2版が計画されている、しかも今度は言語がJavaScript……というニュースが2018年に話題になりましたが、最近じっくり読むことができました。

www.ohmsha.co.jp

Chap.1 リファクタリング-最初の例

 2版の原題はRefactoring, Second Edition。439ページほど。あの伝説の本の2版か……と震えながら読書開始です。序文を見ると長く親しまれてきた本も時代に合わせて変えたことが書いてあり、歴史を感じさせます。
 ファウラー本ではいつものように穏やかに淡々と文章は進みます。最初の例は初版ではレンタルビデオの金額計算だったのですが、劇の公演の請求書を作る関数に変わりました。これは時が経っても変わらなさそうなクラシックな題材ですね。変数宣言はletconstfor ofのループやアロー関数もありES6以降の書き方になっています。
 最後はクラス化、サブクラスに処理を分岐させるポリモーフィングまでやってリファクタリングは完成します。

Chap.2 リファクタリングの原則

 リファクタリングの原則はなんぞやという話、いつするか、その歴史など。こういう歴史の話になるとよく出てくる、Smalltalk言語が本書でも出てきます。
 ファウラーさんはエディターはEmacs派だけどリファクタに必要な時はEclipseIntelliJ IDEAも使うそうです。JavaScriptのエディターやリファクタリングツールの話は出てこないですね。JS界隈ではおなじみのVisual Studio Codeは使っていないのでしょうか。

Chap.3 コードの不吉な臭い

 将来悪しき影響を及ぼすであろう、スメルがするリファクタリングすべきコードの特徴を語る章。不可思議な名前、重複したコード、長い関数...などはぱぱっと見でもお馴染み。特性の横恋慕、インサイダー取引、相続拒否なんかは名前付けが面白いですね。初版といくつか名前が違ったり追加されたりしています。ネット上では以下の記事に一覧表があります。

devtab.jp

 この章はテスト駆動開発で有名なケント・ベックさんと一緒に書いたそうで、文中に紛れ込んでいるジョークが面白かったら自分作、つまらなかったらベックさん作だと何やら冗談で予防線が張ってあります。これが……達人の余裕……(うそ)

Chap.4 テストの構築

 リファクタリングと共に推奨されているテスト技法の話。JSのテストフレームワーク Mocha+Chaiで、ある画面を実装している関数群をテストしていきます。この辺はテスト駆動開発などの本にもよく出てくるところ。
 本書でも他の本と同じく、リファクタリングは常に細かい単位で行い、その都度細かい単位でテストして動作が同じなのを担保しつつコツコツ進めていくのがよいと論じています。

 自分はJavaScriptではテストフレームワークは未経験、テストコードでなく画面の実物を動かしながらのリファクタリングで済んでしまうことが多いので、ううむいつか本格的にやらんとなと思いました。  

Chap.5 カタログの紹介

 5章以降が本書のメイン、リファクタリングカタログ。名前づけがされたテクニックそれぞれについて、UMLっぽいけど違う何かの図やコード例とともに解説していきます。
 最初は他の言語でもおなじみ関数の抽出から。恥ずかしながらJSの関数の入れ子化は使ったことがありませんでした……

Chap.6 リファクタリングはじめの一歩

 変数の抽出、カプセル化、関数宣言の変更、パラメータオブジェクトの導入などは他の言語でもお馴染みのテクニック。私的にはGetterなどふだん使っていないJavaScriptの書き方も出てきて思わぬ所で復習になります。だんだんES6以降の新しい書き方の活用やオブジェクト指向に則った、しっかりしたJavaScriptを書きたくなってきます。

Chap.7 カプセル化

 関数群のクラスの中への集約、変換処理をひとつの関数への集約、フェーズの分離、レコード(JSの連想配列)のカプセル化、コレクションのカプセル化など。
 やはりJavaScriptの処理でも単にJSONの中身表示のようなレベルでなく、ロジックが本格的になる場合は、他の言語のようにクラス化して中に閉じ込めていったほうが良いのだなと思います。またコレクションやオブジェクトで元の値を変えないように、ライブラリのlodashでディープコピーしてから新しいオブジェクトだけいじるシーンがよく出てきます。

 文字や数字などプリミティブ型のクラス化やクラスのインライン化、委譲の隠蔽なども他の言語ではお馴染みのところ。コレクションのカプセル化では、やはり配列は常に本体でなくコピーを返した方がいいんですね。このへんも実践できていないのでなるほど……となります。

Chap.8 特性の移動

 関数や変数(フィールド)、プログラムの一部を移動してより良くするやり方。
 ファウラーさんはどう見てもその道のプロですが、自分でも間違いをすることを文中でも認めていて後からよくリファクタして直すことがあるそうで、この辺、達人プログラマー特有の謙虚さや穏やかさのようなものを感じます。

「パイプラインによるループの置き換え」は初版になかった、ES2015以降のパイプライン記法を使って処理を見やすくするリファクタリング。これについては自分の場合は見慣れてないからか、元のfor文スタイルでも別にいいじゃんとつい思ってしまいました。

Chap.9 データの再編成

 変数を分離したりフィールド名(メンバ変数名)を変えたり参照渡しを値にしたり、地味だけど後で効いてくるリファクタリングの章。

Chap.10 条件記述の単純化

 if分の中の長い条件を関数に外出ししたり、これも他の言語でお馴染みのリファクタリング
ネタとしてはファウラーさんはスコットランド料理のハギスが嫌いだそうです。イギリス圏でもよくネタにされるそうですが実物のお味はどうなんでしょう。

ja.wikipedia.org

 HTMLの雛形ウェブページのダミーテキストによく使われるロレム・イプサム(lorem ipsum)のネタもコード中に登場します。細かい所で時々笑いを挟んできます。

ja.wikipedia.org

 「ポリモーフィズムによる条件の単純化」は、共通の判定は親クラス、個別の判定はサブクラスに分けてクライアントコードからの呼び出しは単純な関数呼び出しだけにするテクニック。例が複雑ですが、JavaSciptでも静的言語とほぼ同じことができています。

 「特殊ケースの導入」は、特殊ケース用のクラスを用意して判定や特別処理を中に閉じ込め、こちらもクライアントからの呼び出しは簡単にするテクニック。クラスだけでなくただのオブジェクト(JSの連想配列)を使うやり方も一緒に書いてあるのがJavaScriptらしいです。
 こういう本格的なロジックはなんとなく別の言語で……と自分はつい思ってしまうのですが、もうJavaScriptで十分カバーできる時代なのだ……と改めて思います。

Chap.11 APIリファクタリング

 API的な仕事をする関数のリファクタリングの章。問合せと更新を別にする、引数で中の動きを分岐させる、逆に不要な引数を消す、フラグの引数はやめる、オブジェクトを引数で渡す...などなど。
 相反するリファクタテクニックもありますが、解説にあるようにそれぞれの場合に応じてでしょうか。サンプルのコードもこの章は比較的短くて分かりやすいです。
 不要ならクラスからsetter削除、ファクトリ関数からクラスを生成する、処理の塊ならコマンドオブジェクトに分割...と続き、このへんも何らかの言語経験がある方なら分かりやすいところです。

Chap.12 継承の取り扱い

 メソッドやフィールド、コンストラクタの親への上げ下げ。親クラスへメンバ変数を引き上げる例はスコープがprivateになっており、すわJSもいつの間にかここまで進化?と思わせてここだけ例がJavaになっています。
 このへんは批判の文脈ではないところでJSには言語仕様の欠陥があることも述べており、ファウラーさんも分かっててやってるんだなという感じです。

 サブクラスで種類を表すコードを置き換える、逆にサブクラスをやめる、スーパークラスを抽出する、委譲でサブクラスを置き換えるなどもJavaでお馴染みのテクニック。
 「継承=悪」 は昔あった「goto文=悪」 のもじりで、本書では継承は依然として有効であり、後からでも委譲にも置き換えられるので応用が利くよと論じています。このへん炎上しそうな極端な意見もネットだと見かけますが、やはり状況に応じて使い分けなんですね。

 「委譲によるサブクラスの置き換え」は、鳥の種類ごとのサブクラスをやめて親クラスだけにするなら委譲用のDelegateクラスをメンバ変数に置き、そこの中で個別処理をしていくテクニック。Delegateクラスの中で必要なところは鳥の種類ごとに継承を使うのがポイント。ここで鳥の種類がみなモンティ・パイソンのネタになっています。

ja.wikipedia.org

 「委譲によるスーパークラスの置き換え」は、不適切な継承があったら断ち切り、親クラスだったものをメンバ変数に置いてうまく処理していくやり方。こちらは魔法の巻物の管理がコード例の題材になっており、ゲーム・オブ・スローンズのネタが出てきます。

www.star-ch.jp

 自分は海外ファンタジーも好きなんですが、これの原作の『氷と炎の歌』シリーズは最初の『七王国の玉座』が長そうで手を出さなかったんだよな……
 と余談はさておき最後はコードの不吉な匂いと各種リファクタ手法の対応表もついて終了です。

JavaScriptになったことによる変更点

 目につく所ではだいたい以下のようなところでした。

  • Javaだと書けないグローバル変数は基本的に絶対禁止。コードの不吉な匂いにも挙がっている。
  • 変数宣言は基本const、変更の可能性がある時だけlet。諸悪の根源varは禁止。
  • 長い関数の内部処理をprivateな内部メソッドで分割していくようなリファクタリングは、関数の入れ子で実現。
  • 外から取り出すときは配列をコピーして返し元の値はImmutableにするような処理は、slice()を使ったりライブラリのlodashを使ったり。
  • 処理の流れの中の内部処理を無名関数で見やすくする時などに、ES2015のアロー関数の記法も登場。
  • ループで伝統的なfor (let i = 0; i < ..) だけでなくES2015のfor ofも登場。
  • ループの中の条件に合うものだけを取り出すような処理は、コードが長くなる伝統的な書き方でなくパイプライン処理や、ES2015のフィルタ関数を使用。ary.filter(o => o.name === 'Fowler') みたいなやつ。
  • オブジェクト指向を活用する際はES2015以降のclass記法。継承してポリモーフィズムを活かしたり。
  • クラス内部に隠蔽されたprivateなメンバ変数的なものはJavaScriptでは再現できないので、そこだけはふつうのプロパティのまま。コード例もJava
  • こうしたprivateなメンバ変数的なものを持たせたい時はコンストラクタの引数などで渡してプロパティで持たせ、変数名は昔からの伝統に従い、_firstName のように先頭にアンダーバーで区別。
  • こうしたオブジェクト内部にカプセル化して持った値を加工して外側に返したりする処理は、get name() のようなJavaScriptのGetter/Setterを活用。名前はメソッド風の動詞でなくメンバ変数風の名詞。
  • 常にclass記法で……でなく、簡単に済む場合はJavaScriptオブジェクトだけで完結させるパターンも。

 読む前はもっと、最新のECMAScript仕様に従った新しい書き方、JavaScript独特のやり方なんかがドバーっと出てきてグワーッ!ファーッ!!死亡!!! となるのかと震えていたのですが、意外とそうでもありませんでした。JavaScriptエコシステムを囲うNode.js周りの話もほとんど出てきません。よく考えればそれもそのはず、本書の主題はリファクタリングであって特定の言語に縛られるものではないですからね。
 ファウラーさんの語調は変わらず、題材がJavaだろうがJavaScriptだろうがリファクタリングの本質は変わらないのだよファッファッファッ……とでも言いたげな感じで静かに淡々と、ところどころ分かりにくい細かいギャグを交えながら進んでいきます。
 全体的にオブジェクト指向の伝統的なクラスや継承を中心に置いたテクニックが減って後の方に縮み、関数型ベースの考え方が増えた感じです。このあたりは20年の時の流れですね。
これは本書の中や後書きにも話がありますが、オブジェクト指向が廃れて関数型指向になったという極端な考え方ではなく、オブジェクト指向はもはや空気のように偏在化して使うのが当たり前になり、その後に生まれたアプローチとも両立できるよ……というぐらいで捉えておく方が妥当でしょう。

 というわけで、JavaScriptはまだそんなでも……という方も尻込みせず読んでみるとよいと思います。むしろ画面系のUI操作に近いところではなく、フロントエンドの奥の方とかバックエンド(サーバーサイド)の側のロジックに関するところをJSや別の言語でガッツリやっている方、より良いコードにしていきたい方にこそお勧めです。

まとめ:言語が変わっても色褪せないリファクタリングのバイブル

 ということで名著の2版に相応しい内容。普段からプログラミングに触れている方であれば、プログラミングするときにもっと良くできる箇所があるのではないか……と考えたくなる一冊でした。自分も気付きがいろいろあって、もうJavaScriptでも十分に本格的なロジックが書けることを改めて認識しないとなと思いました。

 なお欠点としてKindle版の問題があります。僕はKindle Fire HD 10で読んだのですが、横にして2ページ1画面で見ようとすると拡大されたままで見開き表示不可。縦にして1ページ1画面にすると収まるのですが上下が無駄に空いてしまって1ページが縮小されすぎ。
ピンチアウトして心持ち拡大すると丁度良くなるのですが、ページをめくると戻ってしまう……という、コードはリファクタリングできてスッキリするけど画面がスッキリしてないなんとも残念な感じになります。430ページ以上あるので物理本は重いのですが、電子版を買われる方はご注意ください。

 僕が初版を読んだのは2000年代半ばごろか、まだ新装版が出る前の初版でした。当時エンタープライズ開発の世界ではWebアプリの時代が華開いてJavaが大進撃、Strutsで多くの業務システムが作られたりその後に来る来ると言われたJSFが結局流行らなかったり、日本発のSeasar/Seasar2が颯爽と現れて消えていったり。そうこうしてるうちにGoogleマップが衝撃を与えてAjaxjQueryが出てきてJavaScript復権の兆しが徐々に見えてきたり。PHPRubyが注目され始めてMatz大先生をよくメディアでも見かけるようになったり、いろいろありました。
 Webアプリケーションエンジニアとしてチャンスを掴んだ自分はJavaをがっつりやってオブジェクト指向を学んで資格を取って、ある程度分かった気になってきたら定番のGoFデザインパターンも学んで、その流れでこのリファクタリングの本へ。
 非情報系卒で社会に出てからプログラムを学び、オブジェクト小僧やデザインパターン小僧を経て進んできた当時の自分には本書はかなり難しく、苦労しながら重い紙の本を通勤電車の中で読み進めた記憶があります。

 あれから十数年。コード例がJavaScriptに生まれ変わった本書を読むと、あの頃に比べたらだいぶスラスラと、何が言いたいのか並行して理解しながら読み進めることができました。特に才能があるわけでもない職業エンジニアの自分でも、コツコツやっていれば進歩はするもんだなとふと感慨に耽りました。
 また初版と第2版で約20年、時や言語と共に移り変わるテクニックもあればも変化しないプログラミングの本質や真理もある、その両方に触れることが大切だな……と改めて思いました。

関連リンク集

2nd EditionがJSになるという衝撃ニュース!そして秋の英語版完成を伝える2018年の記事。どちらもはてブ300以上、多くのエンジニアが復活に注目したのが分かります。

www.publickey1.jp

www.publickey1.jp

勝手ながら拝見したネット上の書評のリンクです。

初版の新装版についての感想。

Qiitaでマインドマップにまとめた方がいました。

おまけ リファクタリング関連の書籍

初版を新装版にした『新装版 リファクタリング』は物理版が2014年、電子版が2017年。言語がJavaでがっつりやるならこちらもまだ有用でしょう。

おおもとの初版『リファクタリング―プログラムの体質改善テクニック』は原著が1999年で日本語版が2000年、これはさすがに古いです。むかし僕が読んだのはこちらでした。

数学ガール』で有名な結城浩さんによる『Java言語で学ぶリファクタリング入門』という本もあります。物理本が2007年、電子版が2014年。こちらも言語はJava、ファウラー版のリファクタリングを元に、実例を元により分かりやすく解説した本となっています。最初から日本語なのは翻訳本が苦手な方には大きいかも。

Java言語で学ぶリファクタリング入門

Java言語で学ぶリファクタリング入門

Ruby界隈だと時々名前が挙がる『リファクタリング:Rubyエディション』も前からある本なのですが2020年に復刊しました。JavaJavaScript以外の特定言語でリファクタリングの商業本があるのは確かこのRubyだけ!

あの名著『達人プログラマー』の著者の一人のアンディ・ハントさんの『リファクタリング・ウェットウェア』もアジャイル界隈の文脈で時々名前を聞きます。オライリー本で2009年なのでちょい古いか。こちらはコードのリファクタリングでなく、仕事する時の人間の脳のリファクタリングの本。

リファクタリング・ウェットウェア ―達人プログラマーの思考法と学習法

リファクタリング・ウェットウェア ―達人プログラマーの思考法と学習法

  • 作者:Andy Hunt
  • 発売日: 2009/04/27
  • メディア: 単行本(ソフトカバー)

『レガシーコードからの脱却』はこの前感想を書きましたがこちらも良い本ですね。

iwasiman.hatenablog.com

関連で『レガシーコード改善ガイド』『レガシーソフトウェア改善ガイド』もあります。

iwasiman.hatenablog.com iwasiman.hatenablog.com