リファクタリングを行う方法【リファクタリング入門1】

この記事の内容

アーキテクチャスタイルに幾つかのケースがあるのと同じように、 リファクタリングの手法にも明確な6段階の手順が存在します。

今回の記事の目的はリファクタリングを行う2通りの方法について説明します。

大規模なリファクタリングを行う前に

リファクタリングを行う前には、なぜリファクタリングが必要なのかを経営陣に説明する必要があります。

次の記事は、システムにおけるスケーラビリティと弾力性の違いを説明するサイトです。また、スケーラビリティ/弾力性を高めるためにはどのようなシステム構成にするべきなのか、どのようなシステムがスケーラビリティが高いと言えるのかについても触れていきます。

詳しい内容はこちらの記事より参照してください-リファクタリングをするべき5つの理由

そして、経営陣にリファクタリングをするべき理由を説明して予算を獲得してからリファクタリングをしていこう。

リファクタリングでやってはいけないこと-象の移行アンチパターン

分散アーキテクチャへの移行と、モノシリックなアプリケーションの分解にゴーサインをもらえたとします。

この時に、「とりあえず大規模なアプリケーションを一口ずつ分解し、取り組めるところから少しずつ分解していく」というやり方は実は推奨されていない。 このような分解の仕方は象の移行アンチパターンと呼ばれます。

象の移行アンチパターンを進めた時は、通常は構造化されたシステムには繋がらず、結果的に分散した巨大な泥団子になります。 (この状態に分散モノシリックという名前がついていることもあります。)

では、どのような方法でシステムを分解して、リファクタリングへとつなげていけば良いのでしょうか?

答えは2通りあります。

  1. 戦術的fork

  2. コンポーネントベース分解

この二つです。

コンポーネントベース分解概要

コンポーネントベース分解とは、現行のシステムに眠るパターンを見つけ出して、高度に洗礼されたコンポーネントを抽出し、システムを分解するリファクタリングです。

コンポーネントベース分解が当てはまるのは、次の条件を満たした時です。

つまり、モノシリックアーキテクチャの中でもある程度形になっている必要があるということです。

戦術的フォーク

戦術的フォークの「フォーク」とは、gitなどのソースコード管理システムで使われる「フォーク」に由来する手法で、 「現行のシステム」からブランチを「フォーク」して、複数チームで同時並行でシステムをリファクタリングしていくやり方です。 そのようにしてアプリケーションのレプリカを作成し、それぞれのチームが彫刻のように不必要な部分を削っていくのがこの手法です。

コンポーネントベース分解が当てはまるのは、次の条件のみです

  • コードベースが定義可能

コンポーネントベースが分解可能であるかは戦術的フォークにとっては考慮するべき内容ではないです。 ですが、コンポーネントが明確に定義できていないような、構造化されていない寄せ集めであれば戦術的フォークが良いでしょう。

コードベースが分解可能であるとは

リファクタリングの内容を説明する際に出てきた「コードベースが分解可能である」とはどういう意味でしょうか。 この言葉を言い換えるのであれば、「このコードベースはサルベージ可能か?」という問とほぼ同義です。

(ちなみに、コードベースが分解可能でない場合には、そもそもリファクタリングではなくリプレイスを選択するべきです。

コードベースがリファクタリング可能で、内部構造を持つかどうかの判断は一人のアーキテクトでは難しいですが、 いくつか基準となるメトリクス(指標)が存在します。

コンポーネントへの入力と出力の数から判断する

求心性結合と遠心性結合という二つの言葉がある。

システムの構造を変化する際には、これら二つのメトリクスに注目しましょう。

例えばAdressという共有クラスを見つけたとする。モノリスなコードを分解する際には、核となる概念を見つけ出すことが一般的であり、 これを再利用するのが重要であるが、同時に他のシステムがどれだけこのクラスを利用しているかを判断する必要があります。 実は、ほぼ全てのプログラミング言語には、こうしたコードの結合特性を分析できるツールが存在します。

Jdependの出力を可視化するEclipseブラグイン from https://marketplace.eclipse.org/content/jdepend4eclipse

抽象度

プログラミング言語でよく言われる「抽象化」はコードの再利用性を高くでき、コードベース全体を測る手助けになる。 逆に言えば、1000行にわたるメソッドが一つあるようなコードを理解するのはとても難しく、これは抽象的とは言えない。

ところで、この抽象度を図る計算式が存在する。

(Σma)/(Σmc + Σma)

Σma : 遠心性結合(出力される接続数)

Σmc : 求心性結合(入力される接続数)

この式を要約すると「出力される数が多ければ多いほど、抽象度は低い」という意味になる。

アーキテクチャを分解する

コンポーネントベース分解

モノシリックなシステムをマイクロサービスに分解する際の複雑さは、大抵コンポーネントの定義の不十分さに由来することが多い。 ここではコンポーネントとは、システム内で明確に定義された役割と責任を持ち、明確に定義された一連の操作を行うアプリケーションの構成要素と定義する。

例えば、pythonではディレクトリ構造により名前空間が形成され、一つのコンポーネントとなる。

from https://resanaplaza.com/2021/07/17/%E3%80%90%E5%9B%B3%E3%81%A7%E8%A7%A3%E8%AA%AC%E3%80%91python-%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E6%8E%A8%E5%A5%A8%E3%81%AE%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80/

コンポーネントベース分解ではコンポーネントを連続的に抽出しリファクタリングを行う手法である。

コンポーネントベースの分解方法は次の5つの手順で行う

  1. コンポーネントの発見とウェイト調節:アプリケーション内部のコードから一定のパターンを見つけ出し、機能の増減を行う

  2. コンポーネントの共通化:アプリケーションで重複する機能を見つけ出し、再利用してコードを減らす

  3. コンポーネントのフラット化:ドメインごとにコンポーネント同士をまとめたり拡張したりする

  4. コンポーネントの依存関係の発見:コンポーネントの依存関係を特定し、問題がないかを調査、改善する

  5. コンポーネントドメイン作成:論理的なドメインに完全に分離する

  6. ドメインサービスの作成:コンテナ/サーバー別にドメインを分離する

戦術的フォーク

コードのリファクタリングで一番最初位思い浮かべるのは、システムの一部を抽出するやり方である。 しかしこのやり方では、影響範囲がどこまであるのか、どの程度クリーンなコードにできたかが確認できない。 リファクタリングにはもう一つやり方があり、それがシステムの不要なものを削除するアプローチである。

開発者は不要なコードを削除する手間が発生するが、依存関係はそのままである。 そのために、抽出で繰り返し行わなくてはないない結合への対処を回避することができる。

1.例えば、一つのがんじがらめになったリファクタリングする必要のあるリポジトリがあるとする。

from https://postd.cc/distributed_big_balls_of_mud/

2.そのリポジトリを二つのチームが担当し、既存のモノリスからサービスベースアーキテクチャへと移行したい。 その場合は、次のようにアプリケーションをforkして、全く同じソースコードを作成する。

3.各チームはコードべーすの全体のコピーを受け取ると、必要なコードだけを抽出する代わりに、不要なコードの削除を開始する このアプローチの方がシステムを分解しやすいことが多いからだ。

4.最終的にシステムは、二つの独立したサービスを手に入れることができた

from https://tech.askul.co.jp/entry/2019/04/09/132952

戦術的フォークのデメリット

  • 出来上がったサービスには、モノリスから引き継がれた使われないコードが大量に残っていることが多い

  • 凝縮されたモジュールには追加のコストを払う必要がある

備考

title:大規模なリファクタリングを行う2通りの方法【リファクタリング入門】

description:大規模なリファクタリングを行うには二つの方法がある。できるところから少しずつやっていく方法は優れたリファクタリングでないことが多い。そうではなく、だ規模なリファクタリングを効率的に行う方法をこの記事で解説する。

category_script:page_name.startswith("3")

img:https://github.com/kawadasatoshi/techblog/blob/main/0/inhouse_se/3063/breakdown.png?raw=true