プログラミング言語には、動的型付け言語と静的型付け言語の2種類が存在するが、
この記事では「静的型付け言語を使え」という話をする。
結論
- 中規模〜大規模の開発である
- チーム開発をする
- 今は小規模でも今後成長する見込みがある
この前提条件がある場合は、迷わず型定義が使える言語を導入すべきである。
この記事では、そう判断する根拠を書く。
型定義ができる言語が良い理由4選
①コードリーディング時の認知負荷が低い
動的型付け言語に比べ、静的型付け言語はコードを読むときの認知負荷が低くなりやすい。
コードを読む際に、そのデータに関するヒントが増えるからだ。
前任者の変数名定義が多少甘かったとしても、その変数にどんなデータが入っているか想像がしやすくなる。
// 動的型付け言語(例:JavaScript)
// スコアがどんな範囲の数値を取るかを特定するには、getItemScore()を見に行く必要がある
const itemScore = getItemScore();
// 静的型付け言語(例:Java)
// スコアには整数値が入ることが確定していて、小数点を伴う数値が入ることはないと断言できる
Integer itemScore = getItemScore();
静的型付け言語で書くだけで、「〜かもしれない」という認知負荷を大幅に減らすことができる。
書くより読んでる時間が多くなりがちなチーム開発において
コードリーディングの認知負荷を減らしやすいのは最大のメリットだと言える。
②DDD(ドメイン駆動開発)との相性が良い
「読みやすいコードを設計する」という目的でよく目にするのがDDDである。
DDDは型定義ができる言語において本領を発揮する開発方法のため、
DDDを意識した書き方をしたい場合は静的型付け言語を選定しておいた方が良い。
細かくは触れないが①の例では、次のように書くことができる。
// Javaの例
// ItemScoreには仕様が明記されており、実装を見ると「1~100の値を取る」などがわかるようになっている
ItemScore itemScore = getItemScore();
③型関連のバグを防ぎやすい(書いている時点で気付ける)
動的型付け言語は、実行するまでエラーが分からない。
以下は、本来数値を入れるべき引数に文字列を入れてしまった例である。
function addScore(score1, score2) {
return score1 + score2; // 数値型を想定
}
// 実行例
const scoreA = 50;
const scoreB = "100"; // 文字列を意図せず代入
const total = addScore(scoreA, scoreB);
console.log(`Total Score: ${total}`);
静的型付け言語であれば、コードを書いている途中でIDEがエラーの可能性を教えてくれる。
④IDE補完やCopilotによる推測がされやすい
型定義がある言語では
「リスト系の型は.map()
が使えるな」とか「文字列の型には.toUpperCase()
が使えるな」などを
IDEが型から推測し、完全な補完候補を提示してくれる。
開発者としても「こういう標準メソッドが用意されているんだな」ということがすぐに分かるため
最初からドキュメントを検索する手間が省け、車輪の再開発をしてしまうリスクも低減できる。
GitHub Copilotなどのコード生成ツールにおいても
型情報があるほうがより正確なコードを推論する確率が高い。
逆に、動的型付け言語が優れている点
ここまで「静的型付け言語の方が素晴らしい」ということを言ってきたが
もちろん動的型付け言語が優れている点も存在する。
それは「型を気にしなくて良いので開発スピードが速い」ということである。
そのため、前提条件にも記載したことではあるが
- 個人開発
- 小規模
- 保守運用する予定がない(2度と読むことがない)
というケースにおいては、動的型付け言語で実装したほうが楽と言えるだろう。
ただし、最近はGitHub Copilotなどのコード生成ツールが生まれたことで
その「実装の速さ」というメリットは失われつつあると筆者は考えている。
余談
動的型付け言語のメリットとして「記述の柔軟性」というメリットを挙げている記事を見かけるが
これが全く理解できていないので、分かる人が居たら教えてほしい。
筆者はコード変更時の「変更しやすい」という意味だと捉えたが
変更しやすいかどうかはコード設計の方が大きく影響があると思っているので
この説明では納得がいかない。
もう一つの可能性として「異種データを同様に扱うことができる」という主張であれば
それはバグの温床なのでやめた方が良いし、interfaceのような抽象化の仕組みを使うことで十分解決できる。