Lodash is dead. Long live Radash.
記事は上記記事を意訳したものです。
※当ブログでの翻訳記事は元サイト様に許可を得て掲載しています。
Lodashの何が問題なのか?
JavaScriptの動的な能力が欠点ではなく特徴として捉えられていた時代に、Lodashは異なる入力に対して異なる振る舞いをする関数を提供することで、できる限り役立つように作られました。現在では、私たちはより良い方法を知っています。純粋関数、決定論的な振る舞い、関数合成といった関数型のコンセプトがJavaScriptコミュニティに根付いています - ありがたいことです🙏
Lodashは2009年(Underscoreとして)に作成され、2012-2013年頃にフォーク(Lodashとして)された後に力を持ちました。2012年頃のJavaScriptを覚えていますか?当時、私はJavaScriptでバックエンドを書くことは無責任で愚かだと信じていました。言語が安全ではなく、保守できず、扱いにくかったからです。10年で言語、ランタイム、コミュニティがこれほど進化したことは驚くべきことです。もはや同じ言語とは言えません。
Lodashは2012年頃のJavaScript開発者の問題を解決するために設計・開発されました。それらは現在の私たちの問題ではありません。オプショナルチェーニングとnull合体演算子の追加だけでも、Lodashの関数の多くが不要になりました。TypeScriptの台頭以降の変化については言うまでもありません。今日の市場では、Lodashのような基礎的なパッケージは有用な型を提供する必要があります。
関数の詳細分析
私が根拠なく批判しているわけではないことを示すため、Lodashのいくつかの関数について、なぜそれらが博物館に属していて、あなたのプロジェクトには不要なのかを説明します。
Lodashの_.get関数
_.get
関数は、path
パラメータに文字列または配列値を渡すことができます。これは当時は動的な機能と考えられていましましたが、現在では単なるバグの温床です。TypeScriptでは、_.get({ name: 'ray' }, 'age')
というコードはエラーを生成しません。なぜなら、Lodashの型はオブジェクトに指定された文字列パスが存在するかを検証しないからです。
Lodashの_.filter関数
ここには3つの問題があります:
- 第二パラメータとして異なる型を受け入れます。これはもはや特徴ではありません。
- オブジェクト、配列、文字列を渡す場合、型が機能しません。Lodashの型付けが不十分なため、TypeScriptは提供された配列の型に値が存在するかチェックできません。
- null合体演算子とオプショナルチェーニングにより、
filter
関数はやや不要になっています。nullチェックに多くの行のコードが必要だった時は便利でしたが、上記の例は?
と??
で同じように簡潔に書けます。
これらの点は他の多くの関数にも当てはまります。_.find
と_.some
関数はその一例です。
Lodashの_.map関数
さらに悪いのは_.map
や_.size
のような関数です。上記で言及した問題に加えて、第一引数と第二引数として様々な値を受け入れる機能があります。これは特徴ではありません!
コード品質
ここまでの内容は受け入れられますが、ここからが本当の問題です。簡単な便利ツール群ライブラリを使用する場合(これらの関数は自分で実装するのはそれほど難しくありません)、ソースコードを簡単に見られることを期待します。
Lodashのドキュメントがリンクしているソースコードを見てください。
若い頃の私なら、ソースを何時間もかけて掘り下げ、すべての内部APIを学び、すべての関数呼び出しを記録し、最終的に「isNumber
関数はどのように動作するのか?」といった単純な質問に答えられるようになるまで理解したでしょう。
一行の関数がどのように動作するかを理解するために、15,000行のコードを精査し、内部APIを学ぶ必要があってはいけません。これはアンチパターンの極みです。
でも、そのコミュニティは...
これがLodashの唯一の強みです。古く、誰もが知っており、Stack Overflowには関連するQ&Aが満載です。
また、その功績を認めるべきですが、以前の世代には非常に役立ちました。
では、どうするか?
Radash(/raw-dash/と発音、RamdaとLodashから)は、私たちの世代のLodashです。
- ゼロ依存のJavaScriptユーティリティツールキットで、この10年で作られました。
- TypeScriptで書かれているため、強力で有用な型が最初から付属しています。
- Lodashで時代遅れになった関数を省いています。
- これまで見たことはないけれど常に欲しかった新しい関数を提供します(以下参照)。
- ソースコードは新規参入者のための理解しやすさを最優先に保守されています。ほとんどの場合、Radashの関数を使いたいけどインストールしたくない場合は、GitHubから直接コピーできるはずです。
try関数
try
関数は私の最も好きなRadash関数でしょう。過去10年で見つけた最大のコードクリーン化のハックです。何かを試したい時に制御フローを分岐する必要はありません。tryの外側にミュータブルなlet変数を作成し、内側で設定し、後でチェックする必要もありません。
いつものように、Radashでは、ソースコードと型の強さを気に入るはずです。
parallel関数
parallel
関数はPromise.all
の代替として使っています。あるチームはBluebirdの使用を完全にparallelに置き換えたそうです。一度に何個のリクエストを行うかを制御できるだけでなく、エラー処理もはるかに優れています。parallel
関数は、すべてのプロミスが解決された後、すべての子エラーを含むAggregateError
をスローします。つまり、parallel
からのレスポンスは、エラーと値のプロパティを持つ奇妙なオブジェクトの配列ではなく、期待する値だけになります。
retry関数
retry
関数は私と私のチームにとってasync-retry
ライブラリの代替となっています。try
、parallel
、retry
を組み合わせると、ほとんどのバックエンドサービスのフォールトトレランスライブラリを置き換えるツールが手に入ります。
counting関数
counting
関数は配列内のキーや識別子の出現回数を数えます。予想以上に使用することになる小さな関数の一つです。
range関数
range
関数はループを扱う際に非常に役立ちます。生のfor (let i; i < n; i++)
ループを見ると少し吐き気を催します。range
は同じような機能を提供しますが、臭いコードやリスクなしで簡単に使えます。
range
はジェネレータを返すので、range(0, 100000000)
を安全に呼び出せます。
list関数
list
関数はrange
関数の美しいいとこです。場合によっては、ジェネレータではなく実際のリストが必要です。そのような場合にはlist
関数があります。簡単、迅速、動的なリスト作成は、ループ以外の多くのユースケースでも便利です。
他にも素晴らしい関数がたくさんあります。以下は私のお気に入りの一部です:
objectify
とlistify
throttle
とdebounce
pick
とomit
compose
とchain
memo
とproxied
すべての関数は適切な型付け、ドキュメント、テストがされており、シンプルさを優先して書かれています。もし間違いを見つけた場合は、PRを提出するか、issueを開いてください!
Radashに欠けているLodashが持っている唯一のものは、コミュニティです。Radashが気に入ったら、この記事をシェアするか、GitHubでスターを付けるか、友達にシェアしてください。