ビジネス宣言👔 反応の論理⚛️


私は、あなたが反応するように宣言的な方法であなたの条件付きビジネスロジックを書くことができるNPMライブラリを発表しました.現在使用中ですHackerRank 生産において、複雑なレンダリングロジックに関して特に私たちのコードをより保守的で、読みやすくしました.
このライブラリがどうなるかに飛び込む前に、2つのアプローチの違いを理解しましょう.

宣言型と命令型プログラミングの違いは何ですか?


によるとwiki :
命令型プログラミングパラダイムでは、直接のステートメントを使用してプログラムの状態を操作して、目的の動作を実現します.
宣言のプログラミングパラダイムでは、プログラムをどのようにそれを達成するよりも達成する必要がありますに焦点を当てる.
私はあなたのGibber Jabberを得ません.
フォームデータを送信する「送信」ボタンなどの簡単なUIコンポーネントを想像してください.私たちがリクエストを待つのを待つ間、我々はボタンを無効にしたいです.
if(isLoading) {
  button.disabled = true;
}
無効な状態を達成するには、このようなUIを操作します.
対照的に、宣言的なアプローチは次のようになります.
return <Button disabled={isLoading} />;
宣言的なアプローチが懸念を分離するので、それのこの部分はUIが特定の州でどのように見なければならないかについて扱う必要があるだけです、そして、したがって、より理解しやすいです.
それで、ポイントに戻ります:

だから、どのように反応のような条件付きビジネスロジックを宣言できますか?


ヶ月前、私はlibrary on npm 呼ばれるmatch-rules 以下のコードを実行できます.
function isUserLocked(user: User) {
  // some messed up legacy locking logic data from backend
  if (
    user?.flagged === true &&
    user?.blocked === true &&
    (user?.is_locked === 0 || user?.is_locked === "LOCKED") && 
    user?.profile?.account_deleted === true
  ) {
    return true;
  }

  return false;
}

function showWarning(user: User) {
  return isUserLocked(user) && user?.show_warning;
}

function showAccountDisabled(user: User) {
  return isUserLocked(user) && user?.profile?.show_account_disabled;
}

if (isUserLocked(user)) {
  // render account locked UI
}

if (showWarning(user)) {
  // render warning UI or something else
}

if (showAccountDisabled(user)) {
  // render account disabled UI
}
to
import matchRules from 'match-rules';

import {
  IS_USER_LOCKED_RULE,
  SHOW_WARNING_RULE,
  SHOW_ACCOUNT_DISABLED_RULE
} from './rules';

// user object can be served from the app state 
if (matchRules(user, IS_USER_LOCKED_RULE)) {
  // render user locked UI
}

if (matchRules(user, SHOW_WARNING)) {
  // show warning UI
}

if (matchRules(user, [IS_USER_LOCKED_RULE, SHOW_ACCOUNT_DISABLED_RULE])) {
  // render account disabled UI
}
ここであなたのルールはrules.js オブジェクト構造の場合:
export const IS_USER_LOCKED_RULE = {
  flagged: true,
  blocked: true,
  is_locked: (value, sourceObject) => value === 0 || value === "LOCKED",
  profile: {
   account_deleted: true,
  },
};

export const SHOW_WARNING_RULE = {
  ...IS_USER_LOCKED_RULE,
  show_warning: true,
};

export const SHOW_ACCOUNT_DISABLED_RULE = {
  profile: {
    show_account_disabled: true,
  },
};
条件付き論理を宣言的な方法で宣言する利点について見てみましょう.
  • それはかなり認知複雑さを減らすIS_USER_LOCKED_RULE それはすべての条件を比較して満たすために必要なものを説明しますisUserLocked 関数.オブジェクト構造は読みやすくなります.
  • を作成することができますし、複数のルールを渡す:構成/複数のルールを拡張新しいルールを形成するには、繰り返しを回避します.また、複数のルールオブジェクトをArray 規則.
    デフォルトで複数のルールを比較するand 演算子を使用すると、それらを比較することもできますor 合格者{ operator: 'or' } オプションのprop.これについてもっと読むことができますdocs .
    我々は拡張によって新しい規則を構成したIS_USER_LOCKED_RULE
  • export const SHOW_WARNING_RULE = {
      ...IS_USER_LOCKED_RULE,
      show_warning: true,
    };
    
    オブジェクトベースの構造では、複雑さを導入せずに簡単にルールを拡張できます.
  • 単体テストで時間を節約する:あなたはルールオブジェクトの特定の単位テストを記述する必要はありません、最大であなたがしたい場合は、スナップショットのテストを行うことができます.match-rules あなたのためのルールマッチングロジックを処理するので、仕様を書く必要はありません.
  • ソースのJavaScriptのデータ構造はほとんどオブジェクトです.オブジェクトの状態を定義するのも理にかなっています.オブジェクトの構造を変更する必要はありません.あなたのオブジェクトが深く入れ子にされるならば、それは特に役立ちます.
    例ではstatus キーはプロファイルオブジェクトの入れ子になっていました.我々が書いた規則は、同じ構造と期待された値を持っていました.
  • profile: {
      account_deleted: true,
    },
    
  • 関数を使用して複雑な条件を処理する:これまでのルールで独自の関数を書き込むことができますので、任意の条件を処理することが可能です.
    関数に遭遇すると、値(最初のパラメータとして)と元のソースオブジェクト(2番目のパラメータとして)は、その関数のソースからそのレベルの対応するキーに一致します.上記の例では、is_locked キー.
  • is_locked: (value, sourceObject) => value === 0 || value === "LOCKED"
    
    キーの値と元のソースオブジェクトの組み合わせを使用すると、複雑な条件を処理することができます.この関数のためにspecを書かなければなりません.

    だから、私は自分の考えをライブラリに統合し、それをルールと呼びました



    それが我々がちょうど議論した原則に関して働くので、より多くの実践を考えてください.
    もし私が正確な定義を与えなければならないなら、match-rules あなたの条件付きビジネスロジックを宣言的に書くことができる小さな(1 kBのgzip)ゼロ依存Javascriptユーティリティです.
    これは、機能フラグ、複雑な条件、条件付きレンダリングで使用することができます残りはあなたの想像力です.

    どうやって動くの?


    match-rules 仕事は、それはRULES ソースオブジェクトの対応するキーのオブジェクト.これは、ツリーのようにルールオブジェクトを扱うことによって、再帰的に各キーを介してノードが残っているまで行く.規則は一般に、ソースオブジェクトからキーの小さな部分集合を含んでいます、それは期待された値で同様に完全なオブジェクトの正確な複製でありえます.

    使用方法と詳細なドキュメント

    yarn add match-rules or npm install --save match-rulesmatchrulesのAPIは次のようになります.
    import matchRules from 'match-rules';
    
    // returns a boolean value.
    matchRules(
      sourceObject, // can be any object with data.
      RULES_OBJECT, // you can also pass multiple rules in an array [RULE_ONE, RULE_TWO],
      options, // (optional)
    );
    
    const options = {
      operator: 'and', // (optional, default: 'and') in case of multiple rules you can pass 'and' or 'or'. In the case of 'or,' your rules will be compared with 'or' operator. Default is 'and'
      debug: true, // (optional, default: false) when debug is true, it logs a trace object which will tell you which rule failed and with what values of source and rules object.
    };
    
    // NOTE: all the rules inside a single rule are concatenated by 'and' operator by default.
    
    例と詳細なドキュメントをご覧くださいGithub repo .

    関係者


    大きな感謝


    コードレビュー、デザイン議論、フィードバック、および名前で来るmatch-rules :p
    この記事を徹底的に検討して、建設的なフィードバックをして、このブログサイトを推薦してください.
    この記事の重要なバグとフィードバックを報告する.

    現状


    これは100 %のコードカバレッジで安定しており、現在で使用されているHackerRank 生産で.match-rules は依存関係を持ちません.
    それがあなたのユースケースに合わないならば、プル要求を横切って送ってください.
    次の時は条件付きレンダリングロジックを書くときです.このライブラリを試してください.あなたは、後でxDに私に感謝します.
    いくつかのサポートを表示する場合は、それが有用見つけるスターを残す.
    ギタブhttps://github.com/naman03malhotra/match-rules
    NPM :https://www.npmjs.com/package/match-rules
    生の例https://stackblitz.com/edit/match-rules
    他のチェックアウトopen-source project , 自動スキップイントロのためのシンプルな下見を見てクロムの拡張子Netflix and Prime .
    議論したいならmatch-rules , コメントまたは下に手を伸ばす.