PhxCount Genenderソリッドの紹介


コードビーム2020で、我々のCTOと共同創設者マルセロLebreは、導入しました.リモートは、1年以上にわたってこれらのパターンを利用しており、結果は素晴らしいされている!CodeBaseのすべての部分を通して一貫した構造を維持している間、我々が新しい考えと特徴を造ることができる速度は、本当に顕著です.
以下に概説されたパターンは私たちによく役立っていますが、彼らは欠点を持って来ます.
PhxCount Genlose固体は、教育を受けて、そして、ビルディングブロックでここで説明されている他のものを作成するために、他のものを教育するだけでなくボイラープレート問題を解決することを目指します.

しっかりした原則


話からのパターンは、原則として最初にロバート・マーティンによってデザイン原則とデザインパターンで紹介されるセットの上に構築します.

  • s ingle責任原則:「クラスが変わる理由の1つ以上の理由が、なければなりません」言い換えると、すべてのクラスは1つの責任を持つべきです.

  • pen pen原則:「ソフトウェア実体は拡張のためにオープンでなければなりませんが、変更のために閉じられます.」

  • 基本的なクラスへのポインタまたは参照を使用する関数は、それを知らずに派生クラスのオブジェクトを使用できなければなりません

  • 多くのクライアント特有のインターフェースは、1つの汎用インタフェースよりよいです

  • D寛容反転原則:「抽象化に依存してください.
    これらのそれぞれに深く潜入する必要はありませんが、彼らは次のソリューションのそれぞれの背後にある理由として念頭に置いておくことが重要です.

    ファインダー、ハンドラ、サービス、および値


    これらの4つのパターンは、我々がリモートで我々のフェニックスアプリで構築するすべての後のビルディングブロックです.驚くべきことに、それぞれの間にはほとんど重複がありません、そして、特徴は通常以下のイデオロギーのうちの1つで幸せな家を見つけます.

    仕上げ


    データを取得します.彼らは変異したり書いたりしないでください.
    非複雑なデータベースクエリもフェニックスコンテキストに存在することがあります.フィルタリング、順序付け、および/またはページ付けのためのいくつかの条件がある場合、クエリを複雑にすることができます.親指の規則は、Paramsを渡したり、関数にマップ変数を出力するときに、ファインダーがより適切です.
    ドゥ
    アプリケーション論理
  • によって、編成される

  • ハンドラおよびサービス全体にわたって再利用可能な
  • は1つの単一の目標
  • を達成することに集中します
  • 単一の公開機能を公開します
  • はデータ構造
  • を読む
  • は、複雑なデータ
  • を返す値を使います
    ファイナンダは、データを読み、ルックアップするだけである
    いけない
  • すべてのサービス
  • を呼び出します
  • データ構造を作成/変更する
  • 以下は、ユーザーを見つけるファインダの例である.
    defmodule Remoteoss.Accounts.Finder.UserWithName do
      alias Remoteoss.Accounts
    
      def find(name) when is_binary(name) do
        case Accounts.get_user_by_name(name) do
          nil -> {:error, :not_found}
          user -> {:ok, user}
        end
      end
    
      def find(_), do: {:error, :invalid_name}
    end
    

    ハンドラ


    ハンドラはオーケストラです.派遣・構成のみに存在する.ハンドラは、一緒に応答を戻すために、タスクの実行と/またはデータをフェッチします.
    ドゥ
    ビジネスロジック、ドメインまたはサブドメインによって整理
  • はハイレベルのオペレーション
  • を調整します
  • コマンド・サービス、ファインダ、値または他のハンドラ
  • 複数の公共機能
  • は、コントローラ暗がり
  • を保ちます
  • は、
  • を読みやすくします
  • フロー制御( if , case , pattern matchなど)
  • いけない
  • は、データ構造
  • を直接作成/修正する
  • は、いかなる読み書き操作も
  • を実行する
    ユーザーを作成し、通知を送信し、いくつかのデータを取得するハンドラの例です.
    defmodule Remoteoss.Handler.Registration do
      alias Remoteoss.Accounts.Service.{CreateUser, SendNotification}
      alias Remoteoss.Accounts.Finder.UserWithName
    
      def setup_user(name) do
        with {:ok, user} <- CreateUser.call(name),
             :ok <- SendNotification.call(user),
             user_details <- UserWithName.find(name) do
          {user, user_details}
        else
          error ->
            error
        end
      end
    end
    

    サービス


    サービスは実行アームです.サービス実行、データの書き込み、サードパーティサービスの起動など.
    ドゥ
    24579172はアプリケーション・ロジックによって組織します
    ハンドラおよび他のサービス全体で再利用可能な
  • はサービス、findersと値
  • を指令します
  • は1つの単一の目標
  • を達成することに集中します
  • は単一の公共機能を公開します:呼び出し
  • データ構造を作成/変更する
  • は実行して、処置
  • をします
    いけない
  • は複数の目標を達成するためにサービスを使用する
  • 呼び出しハンドラ
  • あまりにも大きい場合は、小さなサービスに分割する必要があります.
  • 以下はユーザーを作成するサービスの例です.
    defmodule Remoteoss.Accounts.Service.CreateUser do
      alias Remoteoss.Accounts
      alias Remoteoss.Service.ActivityLog
      require Logger
    
      def call(name) do
        with {:ok, user} <- Accounts.create_user(%{name: name}),
             :ok <- ActivityLog.call(:create_user) do
          {:ok, user}
        else
          {:error, %Ecto.Changeset{} = changeset} ->
            {:error, {:invalid_params, changeset.errors}}
    
          error ->
            error
        end
      end
    end
    


    値は、応答、中間オブジェクトなどのデータ構造を構成することができます.あなたは、値がAPIからJSONを返す際に非常に役に立つとわかります、そして、大部分のケースで、我々のView render functionsをただ一つの線(MyValue)に整えます.ビルドします.
    ドゥ
    24579172はアプリケーション・ロジックによって組織します
    ハンドラ、サービス、およびファイナンダ全体で再利用可能な
  • は、データ構造
  • を構成することに集中する
  • 単一の公開機能を公開します.
  • は、単純なロジック
  • を通して構築するために、構成を使用する
  • は、ListまたはMapだけを返します
  • いけない
  • すべてのサービス、ハンドラやフィニッシュ
  • を呼び出す
    JSON応答で使用するユーザーオブジェクトをビルドする値の例を次に示します.
    defmodule Remoteoss.Accounts.Value.User do
      alias Remoteoss.Value
    
      @valid_fields [:id, :name]
    
      def build(user, valid_fields \\\\ @valid_fields)
    
      def build(nil, _), do: nil
    
      def build(user, valid_fields) do
        user
        |> Value.init()
        |> Value.only(valid_fields)
      end
    end
    

    どのようにPhCrest Genかさ固体は助けますか?


    リモートの(ほぼ400 Kの線と同じくらい大きい)アプリケーションを構築するとき!同じような構造を何度も書くことは退屈になります.我々はビジネスロジックと詳細にできるだけ早く取得したい.PhxCount Genchen固体は、我々がすぐにそうすることができるのと同じくらい多くのボイラープレートを生成することによって、より速く速くパートに我々を得ます.その後、微調整することができます微調整微調整我々は好きなように!うまくいけば、発電機は便利です、そして、非常に少なくともPhxCount Genlose固体で、いくつかの新しいパターンまたはトリックを学ぶリソースとして行動することができます!
    PhxChort Genlose固体はまだその幼少期にあります、しかし、それはすでに上記のパターン(価値)のより複雑な部分のうちの1つで援助することができます.
    あなたはあなたのミックスに次のを追加することによってあなたのフェニックスのアプリにPhxCount Genoweソリッドを追加することができます.exs:
    def deps do
      [
        {:phx_gen_solid, "~> 0.1", only: [:dev], runtime: false}
        ...
      ]
    end
    
    依存関係のインストールとコンパイル
    $ mix do deps.get, deps.compile
    

    行動の例


    すべてのPhxCount General固体発電機は、あなたがすでによく知られているフェニックスタスクと同じ構造に従います.

    簡単な値の生成


    $ mix phx.gen.solid.value Accounts User users id slug name
    
    これはmyCountアプリ/アカウント/値/ユーザーの次のコードを生成します.ex
    defmodule MyApp.Accounts.Value.User do
      alias MyApp.Value
    
      @valid_fields [:id, :name]
    
      def build(user, valid_fields \\\\ @valid_fields)
    
      def build(nil, _), do: nil
    
      def build(user, valid_fields) do
        user
        |> Value.init()
        |> Value.only(valid_fields)
      end
    end
    
    あなたの値を構築するすべてのヘルパーを使用して“作曲家”を定義している場合は、フラグを指定することができます-値モジュールmyApp.成分.値、およびジェネレータで使用されるエイリアスはalias myappになります.成分.値.
    推奨値の作曲家を生成したい場合は、-ヘルパーフラグをコマンドとともに渡します.これはコンテキストmyCountアプリ/値を設定します.エクストラ.

    結論


    リモートは慎重に我々はすぐに繰り返すことができますし、手で問題に私たちの完全な焦点を与えることができるエンジニアのためのワークフローを細工しました.それはステークホルダー、プロダクトマネージャー、デザイナー、エンジニアの美しいシンフォニーです.おかしなことは、共通の問題が一般的でないスペースでは、まだ何が残っているかにおける非効率性を見つけることです.それは人間性だが、進歩する.
    あなたが貢献に興味があるならば、我々のGitHubに向かう!
    PhxCount Genoweソリッドのドキュメントは、hexdocsにもあります.