バグが発生すると嫌な気持ちになりますよね。特に誰かに見せている時にバグが発生なんてしたら冷や汗が止まりません。
今回の記事では、バグを発生させないために気をつけていることについてまとめていきたいと思います。
皆さんの意識していることもコメントで教えてください
1. ピュアな関数/コンポーネントを書く
ピュアな関数とは一体なんでしょうか。Wikipediaでは、下記のように説明されています。
In computer programming, a pure function is a function that has the following properties:
- the function return values are identical for identical arguments (no variation with local static variables, non-local variables, mutable reference arguments or input streams, i.e., referential transparency), and
- the function has no side effects (no mutation of local static variables, non-local variables, mutable reference arguments or input/output streams).
出典:https://en.wikipedia.org/wiki/Pure_function
つまり、「ピュアな関数」とは、①同じ引数に対して常に同じ結果を返す、②副作用を持たない関数のことです。
例えば、下記の関数は同じ引数に対して常に同じ結果を返すピュアな関数であると言えます。
function add(a: number, b: number) {
return a + b;
}
console.log(add(2, 3)); // 常に 5 を返す
また、副作用を持たないためピュアな関数の条件を満たしています。
では、下記の関数はどうでしょうか。
let multiplier = 2;
function multiply(a: number) {
return a * multiplier;
}
console.log(multiply(4)) // multiplierが 2 なら 8 を返す
multiplier = 3
console.log(multiply(4)) // multiplierが 3 なら 12 を返す
関数multiply
の実行結果は、multiplier
という値によって変化するため①の条件を満たしません。したがって、この関数はピュアな関数に分類されません。
今度は、②の条件を満たさない関数を見てみましょう。
function addToArray(arr: number[], value: number) {
arr.push(value); // 入力配列を変更する(破壊的操作)
return arr;
}
const numbers = [1, 2, 3];
addToArray(numbers, 4); // numbers は [1, 2, 3, 4] に変更される
上記の例では、numbers
という値が、関数addToArray
によって変更されています。
addToArray
は関数外部の状態を変更する副作用を持っているため、ピュアな関数に分類されません。
では、ピュアなコンポーネントとは一体なんなのでしょうか。これについては、React公式のKeeping Components Pureという記事で詳細に説明されているため省きますが、基本的な考え方は関数と同じです。
下記に二つのコンポーネントを示しました。上部がピュアでないコンポーネントの例で、下部がピュアなコンポーネントの例です。
ピュアなコンポーネントでは与えられた引数(Props)に対して、常に同じ結果が返される(描画される)ことがわかると思います。
<script setup>
// 🙅 ピュアじゃない例
import { ref } from 'vue';
const count = ref(0);
function increment() {
count.value++;
}
</script>
<template>
<div>
<p>カウント: {{ count }}</p>
<button @click="increment">プラス</button>
</div>
</template>
<script setup>
// 🙆 ピュアな例
import { defineProps, defineEmits } from 'vue';
defineProps<{
count: number
}>();
const emit = defineEmits(['update:count']);
const increment = () => emit('update:count');
</script>
<template>
<div>
<p>カウント: {{ count }}</p>
<button @click="increment">プラス</button>
</div>
</template>
このようなピュアな関数/コンポーネントを書くと、下記のような利点を得ることができます。
- 関心の分離が保たれる
- 繰り返し使いやすくなる
- テストしやすくなる
- 動きが予測しやすくなる
全ての関数/コンポーネントが必ずしもピュアである必要はありません。ですが、ピュアな書き方ができる場合は、ピュアな書き方をするのが良いと私は考えます。
2. データの流れを意識する
データの流れを意識する際に、主に考える点は下記の通りです。
- 多重管理を避ける
- データの流れの一貫性を保つ
同一のデータを複数箇所で定義・管理すると、データの整合性が損なわれバグに繋がる可能性があります。そのため、データの「唯一の真実」(Single Source of Truth)を確立し、一元管理を徹底することが重要です。
また、データが一方向に流れる仕組みを設計することで、予測可能性が向上し、トラブルの原因を特定しやすくなります。
3. 読みやすいコードを書く
上記の二点の意識ができたら、あとは読みやすいコードを書くだけでバグが減っていきます。
一般的に読みやすいコードに求められるものを下記にまとめてみました。
- ネストが浅い
- 変数名・関数名が嘘をつかない
- マジックバリューを使わない
その他にも様々な要素がありますが、この記事では割愛します。気になる方は、「リーダブルコード」という本をお勧めします。
いかがでしたか?この3点を意識するだけで、バグの発生率が減少すると思います。
また、バグが減るだけでなくテストが書きやすくなったり、レビューの負担が減るなど良いことが起こるのでぜひ試してみてください。
Happy Coding~