先日以前も読んだことのあるリーダブルコードを読み返しました。
実はエンジニアとして実務に携わる前から読んではいたのですが、中盤のページ以降から経験不足が故にきちんとした理解に落とし込めてはいませんでした。
実務を経験して3年半経った今読むと、なんとなく実践できているところや新たな気付きがありましたので、そういった部分を記事に書いていこうと思います。
特に学び・気付きがあったところ
※以下は書籍本文の内容を私なりにかみ砕いて列挙していますので細かな言語表現は異なる場合があります。
条件分岐は左辺に比較対象、右辺に比較値を配置した方が読みやすい
例えばデータ作成処理で上限数を判定する処理があった場合、以下のように書きます。
TypeScriptでの例
... const MAX_RECORD_LENGTH = 100; const currentRecords: any[] = []; /** 新規データを作成するメソッド */ public createRecord(): void { // 比較対象を左辺に、比較値を右辺に配置して条件分岐 if (currentRecords.length > MAX_RECORD_LENGTH) { ... } ... }
これを意識したことは無かったのですが、言われてみると確かにその通りで無意識のうちに実践できていたり、一部ではできていなかったりしていました。気を付けたいポイントです。
コメントには懸念点やロジック記述の意図を書く
ロジックそのものはソースコードで担保されているので、ソースコードだけでは分からない点をコメントに書いた方が第三者にとって有用なコメントになり得るということでした。割とそういうコメントは書かない傾向があったので気を付けたいところ…。
個人的には外部サービスとの連携をするようなロジックを書く時にそういったコメントがあると、サービス特有の仕様を把握しやすくなるので嬉しいですね。外部サービスのドキュメントの品質はまちまちなので…😑
本書ではプログラマの考えをコメントに書くことを"監督のコメンタリー"と表現されてますが、とても理解しやすい表現で好きです。
デフォルト値を代入するなら最初にまとめて書いてしまう
このようなタイトルでピックアップされていたわけではありませんが、コードを読みやすくする技法の1つとして具体的なソースコードを添えて紹介されていました。最近になってようやくこのような書き方を意識して出来るようになってきたなと感じています。
例えばデータを検索するような処理で、とある項目がnullだった場合に"(未登録)"という文字列を画面出力するような要件だった場合、ソースコードではどこかのタイミングで"(未登録)"という文字列を変数に代入する必要性が出てきます。
その代入処理が別の処理の間に差し込まれると理解し辛いコードになり得るので、ソースの頭にまとめて書いて各処理の記述場所を分離した方が良いということでした。
このように処理を1か所にまとめ直すことを"デフラグ"と表現されていましたが、概念の全体像が浮かびやすい良い表現だと思いました。リーダブルコードとタイトルを掲げているだけあって、説明する文章自体も理解がしやすいよう構成されていると感じます。
実装要件を複数のタスクに分割して列挙する
例えばとあるフロントエンドの実装要件として「ユーザーの所属する部署情報をデータベースから取得して画面表示する」という要件があったとしたら、下記のようにタスクを分割できます。
- WebAPIへのHTTPリクエストを生成する。なおリクエストにはユーザー情報を付与する。
- WebAPIへHTTPリクエストを開始する。
- WebAPIのHTTPレスポンスのステータスコードをハンドリングする。
- WebAPIのHTTPレスポンスに含まれる部署情報を画面へレンダリングする。
上記のようにタスク分割できたら、内容に応じてクラスやメソッド等に適切に分割していくということでした。どう分割していくかは利用している言語、フレームワーク、ライブラリ、既存実装によって変わってくるでしょうが、まずタスク分割するという作業がソースコード設計上大切な部分だと思います。頭の整理にもなりますしね。
慣れた言語だと最初に実装のないメソッドをガリガリと記述して実装すべき内容を俯瞰して見れる状態にし、その後に各メソッドの実装をコーディングしていくという書き方をしたりするのですが、これもタスク分割の1種と言えるかもしれません。
あとがき
発売が2012年とそろそろ10年を迎えようとしている書籍ですが、コーディングをする上で大事な根っこの部分を体系的にリストアップしてくれているところが、今でもなお多くのエンジニアから読まれる理由なのだろうと感じます。コーディングで迷った時などにまた読み返したい本です。