TypeScriptのベストプラクティスを見てみる #4

github.com TypeScriptのベストプラクティスを見てみようの第4弾です。

16. 関数のパラメータとしてフラグを使用しない

関数が長くなると、複雑さが増して読みにくくなるのは本当によくある問題ですよね。私もコードレビューをしていて、よく感じることがあります。例えば、こんなコードなんかです。

function doSomething(flag: boolean) {
  if (flag) {
    // なにかをする
  } else {
    // 別のことをする
  }
}

こういったコードは、関数を分割することで、よりクリーンになります。

function doSomething() {
  // なにかをする
}

function doSomethingElse() {
  // 別のことをする
}

関数を分割することは、クリーンなコードを書くための基本中の基本です。コメントでグループ化するのも良い方法ですが、コメントに頼りすぎるのは避けたいところ。関数名や変数名で意図を表現できるように心がけることが大切だと思います。

17. 必要な分だけコメントを書く、それ以上は書かない

コメントは文脈によって適切に入れる必要があります。複雑なロジックには説明のコメントを入れることで、コードの理解を助けることができます。また、一見不要に見える処理があるときは、なぜそれが必要なのかを説明するコメントがあると良いですね。

例えば、こんなコードがあったとします。

// 祝日の場合は特別ボーナスを加算する
if (isHoliday(date)) {
  bonus += specialBonus;
}

ここでは、なぜ祝日にボーナスを加算するのかを説明するコメントがあることで、コードの意図が明確になります。

ただ、コメントを入れすぎるとかえって読みにくくなってしまうので、バランスが大切です。例えば、こんなコメントは冗長ですよね。

// iを1ずつインクリメントする
for (let i = 0; i < 10; i++) {
  // 処理
}

18. 配列をループする最速の方法を使う

配列をループする際、for文を使うのが最速です。特にindexを使ってアクセスする場合はそうですね。

const arr = [1, 2, 3, 4, 5];
for (let i = 0, len = arr.length; i < len; i++) {
  console.log(arr[i]);
}

ただ、可読性の面ではmapやforEachを使うのが良いでしょう。特にチーム開発においては、可読性の高いコードを書くことが重要だと私は考えています。

const arr = [1, 2, 3, 4, 5];
arr.forEach(item => console.log(item));

データ量が多い場合は、データ構造の見直しや適切なデータ取得の方法を検討することが先決ですね。パフォーマンスを重視するあまり、可読性を損なってしまうのは本末転倒だと思います。

19. 配列のメソッドを優先する

配列メソッドを使うと、コードがより短く読みやすくなります。中間変数を使わない関数型アプローチを使いましょう。

const arr = [1, 2, 3, 4, 5];
const doubled = arr.map(item => item * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

こんな風に、シンプルで表現力豊かなコードが書けるのが関数型プログラミングの醍醐味ですよね。

20. どのようなデータも信用しない

システムに入力されるデータを無条件に信頼するのは危険です。常にバリデーションを行うことが重要ですね。特にユーザー入力のデータは、意図しない値が含まれている可能性があるので注意が必要です。

例えば、ユーザーからの入力をそのままSQLクエリに埋め込むようなコードは、SQLインジェクション脆弱性を引き起こします。

const userId = getUserInput();
const query = `SELECT * FROM users WHERE id = ${userId}`;

このようなコードは、ユーザーが悪意を持って1 OR 1=1などの入力を行った場合、全ユーザーの情報が漏洩してしまう危険性があります。

実際に、SQLインジェクションクロスサイトスクリプティングなどの脆弱性を突かれて、個人情報の流出などの被害が発生している事例は後を絶ちません。入力データのチェックは、セキュリティ上欠かせない対策だと言えるでしょう。

const userId = getUserInput();
if (!validateUserId(userId)) {
  throw new Error('不正なユーザーIDです');
}
const query = `SELECT * FROM users WHERE id = ${escapeSqlString(userId)}`;

このように、入力データのバリデーションとエスケープ処理を行うことで、安全性が大幅に向上します。