💨

リファクタリングの進め方(Vue編)

2022/12/21に公開

こんにちは!Ayaです。
最近リファクタリングをしており、その中で気を付けている点について、まとめてみました。
Vueで説明していますが、他の言語でも共通していることもあるので、参考になれば幸いです。

課題

フォームを使った作成(new.vue)と編集(edit.vue)のファイルがそれぞれ肥大化しており、1ファイル500行を超えることもあり、コードを理解することに時間がかかりました。
また関連した新規機能があると、現状のコードにさらに追加することで、さらに長くなっていき、複雑さも増す
というような辛みがありました。
こちらがファイル構成👇
作成だとnew.vueが親のコンポーネントで、new-entity.vueから編集と共通で使用しているform.vueを呼び出しています。

├── common/
│   ├── components
│   │   └──form.vue
│   └── type.ts
├── new/
│   ├── components
│   │   └──new-entity.vue
│   └── new.vue
└── /edit
    ├── components
    │    └──edit-entity.vue
    └── edit.vue

どのようにリファクタリングを進めていったか

1. Options APIからComposition APIに移行

Options APIの課題とは

Options APIとTypeScriptとの相性が良いとは言えず、型推論が効かないことあります。ドキュメントでもオプション内で型推論ができるようにするには、defineComponentを使う必要があると書かれています。TSから受けられる恩恵は大きいので、積極的にComposition APIに修正していきたいと考えています。

なぜ最初にやった方が良いのか

Options APIからComposition APIに移行は、リファクタリングではないのですが、Composition APIに移行してからの方がリファクタリングしやすいと考えました。リファクタとComposition APIを同時に行うのも、大きな修正になり、バグが生まれやすくなるため、分けておこないました。

2. 作成と編集の共通部分をまとめる

なぜ共通化を行うのか

作成と編集は、基本的な機能は同じところが多く、類似した関数があったため、まとめることができました。例えば、型やリクエスト周りの処理など使いまわしています。

### 共通で使用しているform.vueには影響がないようにする
複数のエンジニアでリファクタリングをしていたというのもあるのですが、作成と編集で使用しているform.vueに影響がないように、この時点では進めるという方針を決めました。なぜかというと、form.vueを修正すると編集と作成の両方をファイルも修正する必要が出てくるためです。先に共通化を進めることで、form.vueを修正したとしても、修正する箇所が少なくなると考えました。今回は、先に作成のファイルを共通化できるように修正し、それを編集に適応するような流れになるように進めていきます。

3. 今後行うこと

form.vueも肥大化しているため、form.vueのリファクタ&分割を進めていきます。また、formで扱っているデータ構造の見直しもすることで、サーバーに渡すために値を整形している箇所も再度リファクタリングできるかもしれません。

どこまでリファクタリングすべきか

今回悩んだことは、どこまでリファクタリングをおこなうべきかでした。500行以上のコードをリファクタリングするとなると時間が必然とかかります。今回のリファクタリングでもだいぶ時間も掛けていたため、上記で述べたformで扱っているデータ構造の見直しをするのは、やめようかなと考えこともありました。
その時に、教えていただいたのが、@t_wadaさんの「質とスピード」でした。簡単にいうとスピードと質はトレードオフではないですよという内容です(詳しい内容はスライド見てくだい)。スピードを犠牲にしても、質がすぐに追いつき、結果的には上回るとのことです。
であれば、できる時に一緒に修正した方が、結果的にはスピードにつながるということで、リファクタリングの大切さを知りました。

リファクタリングの際に気をつけたこと

命名の大切さ

関数、型名、変数名の命名が適切かを考え直すことが大切だと感じました。どの英単語を使うかよりも、その役割を理解しているかで、適切な命名ができるかの鍵になると最近感じています。逆に命名に悩むときは、その変数が必要であるかなど、役割自体の見直しが必要かもしれません。(そうは言っても難しい...)

型をしっかりつける

ついつい面倒になりがちですが、取り敢えず型をしっかりとつけましょう! 
例えば、空のオブジェクトを初期値に設定すると、型がオブジェクトということしか分からず、どのような値が入るのか分かりません。型をつけることで、可読性も上がります。

//変更前
const user = ref({}) 

//変更後
type User = {
 id: number
 name: string
}
const user = ref<User | undefined>(undefined)

リアクティブなデータの扱い方

取り敢えず、refやreactiveでデータを管理したくなりますが、変更が必要のない値は、computedを使用して、リアクティブな値をそのまま渡す方が、コードがすっきりします。

//変更前
const name = ref('')
const result = await getName()
name.value = result.name

//変更後
const result = await getName()
const name = computed(() => result.name)

まとめ

リファクタリングをする際に、どの順序で、どこまでのコードをリファクタリングするべきかの方針を立てることが大切であると感じました。
私もまだまだな部分もありますが、意識して可読性のあるコードが書けるように心がけたいと思います!

Discussion