【はじめての輪読会】リーダブルコード10~11章

◆ Live配信スケジュール ◆
サイオステクノロジーでは、Microsoft MVPの武井による「わかりみの深いシリーズ」など、定期的なLive配信を行っています。
⇒ 詳細スケジュールはこちらから
⇒ 見逃してしまった方はYoutubeチャンネルをご覧ください
【5/21開催】Azure OpenAI ServiceによるRAG実装ガイドを公開しました
生成AIを活用したユースケースで最も一番熱いと言われているRAGの実装ガイドを公開しました。そのガイドの紹介をおこなうイベントです!!
https://tech-lab.connpass.com/event/315703/

最初に

こんにちは!佐々木千奈です。

輪読会も3周目に突入しましたね。今回私はリーダブルコード10章と11章をまとめていきます。

今週の輪読会はリーダブルコードは第三部、コードの再構成 を進めていきます。

10章 無関係の下位問題を抽出する

関数の目的を明確にし、直接的に関係がないものは別の関数に抽出する。

無関係の下位問題を積極的に見つめて抽出する考え方

  1. 関数やコードブロックを見て、「このコードの高レベルの目標は何か?」と自問する。
  2. コードの各行に対して、「高レベルの目標に直接効果があるのか?あるいは、無関係の下位問題を解決するのか?」自問する。
  3. 無関係の下位問題を解決しているコードが相当量あれば、それらを抽出して別の関数にする。

例 10.3 その他の汎用コード

JSのデバッグではよく、alart()でメッセージボックスをポップアップして情報を表示させる。以下の関数呼び出しではAjaxでデータをサーバに送信して、返ってきたディクショナリを表示している。

ajax_post({
	url: '<http://example.com/submit>',
	data: data,
	on_success: function(response_data){
		var str = "{\\n";
		for (var key in response_data){
			str += "" + key + "=" response_data[key] + "\\";
		}
		alart(str + "}");
		
		// 引き続き 'response_data' の処理
	}
});

上のコードの高レベルの目標は**「サーバをAjaxで呼び出してレスポンスを処理する」である。でも、このコードの大部分は「ディクショナリをキレイに印字(pretty_print)する」**という「無関係の下位問題」を解決しようとしている。

このコードを抽出して、format_pretty(obj)のような関数にする。

var format_pretty = function(obj) {
		var str = "{\\n";
		for (var key in response_data){
			str += "" + key + "=" response_data[key] + "\\";
		}
		return str + "}";
}

この関数を分離したことにより、objに期待するオブジェクト以外の文字列やundifinedなどが入った場合の例外処理なども簡単に追加することができるようになる。

その他10章メモ

  • 無関係の下位問題を抽出して別の関数に抽出することで、コードが読みやすくなる上に個別にテストしたり再利用することが可能になる
  • ライブラリとして実装されていないユーティリティコードは自分で作成して使いまわすのが良い👍
  • 1つの機能が独立した関数となることで、関数の改善が楽になる。
  • 小さな関数を作りすぎると逆に読みにくくなってしまうためやりすぎに注意。

11章 一度に1つのことを

一度に複数のことをするコードは理解しにくい。

そのため、コードは1つずつタスクを行うようにしなければいけない。

一度に1つのことを行うための手順

  1. コードが行っている「タスク」を全て列挙する。これは「オブジェクトが妥当か判定する」から「ツリーのすべてのノードをイテレートする」まで。
  2. タスクをできるだけ異なる関数に分割する。少なくとも異なる領域に分割する。

例 11.2 タスクは小さくできる

ブログに設置する投票用のウィジェットがある。ユーザーはUpとDownを投票できる。ユーザーの投票には以下のように3つの状態がある。これらの投票をscoreに反映させるためのコードを見てみよう。

ユーザーが投票や更新のためにボタンをクリックしたら以下のJavaScriptが呼び出される。

vote_changed(old_vote,new_vote); // 投票は”Up” or “Down”

もとのコード

var vote_changed = function(old_vote,new_vote){
	var score = get_score();

	if(new_vote !== old_vote){
		if(new_vote === 'UP'){
			score += (old_vote === 'Down' ? 2 : 1);
		} else if (new_vote ==='Down') {
			score -= (old_vote === 'Up' ? 2 : 1);
    } else if (new_vote === '') {
			score += (old_vote === 'Up' ? -1 : 1);
    }
	}
	set_score(score);
};

これは短いコードだが、前の状態から次の状態への変化により、scoreへの影響を全て考えて計算しており、複雑である。複雑であるため、間違いを見つけにくい。スコアを更新するという1つのことをやっているように見えて、実際には以下の2つの処理を行っている。

  1. old_voteとnew_voteを数値にパースする
  2. scoreを更新する。

これらのタスクを別々に解決すると、読みやすいコードになる。最初の(投票を数値にパースする)という処理をvote_valueという関数として切り出した場合、以下のようなコードに改善される。

一度に1つのことを行うように改善したコード

var vote_value = function(vote){
	if (vote === 'Up') {
		return +1;
	}
	if (vote === 'Down') 
		return -1
	}
	return 0;
};

var_vote_changed = function (old_vote, new_vote)  {
	var score = get_score();
	score -= vote_value(old_vote); // 古い値を削除する
	score += vote_value(new_vote); // 新しい値を追加する

	set_score(score); 
};

その他11章メモ

  • タスクを小さく分割し、関数の単位に分割したり、論理的な区分に分けてあげることで、コードをぐっと理解しやすくすることができる。
  • コードの分割の方法は1通りではないし、複数の手法がある。正解がないが、タスクを分割して整理することが重要である。

感想

10~11章では、無関係の下位問題を抽出する、一度に1つのことを行う、という2つの視点でコードを改善する方法について学んだ。2つとも少し似た概念だと思った。どちらの場合でも、コードを一旦引いた視点から見て、リファクタリングする手法について説明していた。

コードが目的の動作を達成すると、一旦そこで満足してしまいそうになるが、そこで一度立ち止まってこれらの手法に当てはめて整理することでより読みやすいコードを作成することができ、その手間が重要だとわかった。

振り返って整理することで、ロジックが間違っていた場合などにそれに気が付くことが容易になる。

コードを書いていると、一度に複数の処理をしなければならないように感じることがあるが、タスクを様々な視点から分割する方法が紹介されていた。

同時の輪読会で龍ちゃんが12~13章のまとめを行っていたのですが、実際の経験も盛り込まれていておもしろかったです。

リーダブルコード輪読会の他のブログはこちら

アバター画像
About tina 12 Articles
高専専攻科情報系学科卒業後、2022年にサイオステクノロジーに入社。入社後は、フロントエンド、インフラなどを学習してGrafana plugin開発に携わり、その後も学習をしながら日々業務に奮闘中。
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。


ご覧いただきありがとうございます。
ブログの最新情報はSNSでも発信しております。
ぜひTwitterのフォロー&Facebookページにいいねをお願い致します!



>> 雑誌等の執筆依頼を受付しております。
   ご希望の方はお気軽にお問い合わせください!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


質問はこちら 閉じる