積分積分



Conjlijアイデア/Cursive IDEのclojureインテンシブ演習.

導入


去年の12月、私が入会する前に休暇をとっていたときMetosin 私は、私のクロジュールの単純なサーバー運動をもう一度実行することによって、私のクロジュール技能を少し訓練することに決めました.私の前のブログの記事で、その運動についてもっと読むことができます.Clojure Impressions Round Three . そのブログ記事では、「あなたは、アプリケーション州管理ライブラリなしでそれをすることができます」と述べました.私はまだその声明に賛成です、しかし、私が昨年1月にMetosinで働き始めたとき、私はClojureアプリケーションで州管理に関してMetosinIntegrant . 私は、以前のエクササイズで行ったように、あなた自身の国家管理を作成するか、いくつかの州管理ライブラリを使用するかどうかについて何らかの会話をしました.それらの会話によると、私は、これらの人々が本当に良い法律家であるので、彼らが州管理図書館を使っているので、彼らが彼らを使うべきであるという説得力のある理由がなければなりません.それで、私はもう一つのClojure単純なサーバー運動を実行することに決めました.同時に、私はコードを少しより簡単にするために若干のリファクタリングをしました、そして、また、新しいデータストアを加えました:postgres(それの前にデータCSVオプションとしてダミーCSVとダイナモがありました).リファクタリングの仕事も良いテストベンチを使用してどのように良い状態管理ライブラリは、リファクタリングの仕事に役立ちます.
あなたはそのプロジェクトを見つけることができますGithub .
免責事項:これは、それがスムーズに状態を処理してclojure開発を行うようにIntegrantを使用する方法を学ぶためにちょうど個人的な運動だった.この演習は決して完璧な例ではなく、WebショップやWebアプリケーションを設定することです-歴史的な理由のための多くの特殊性(例えば、ドメインエンティティは単純なベクトルで渡されます-私は代わりにマップを使用する必要があります).

積分はなぜ?


なぜInteantや他の状態管理ライブラリを使用し、自分自身を処理しないのですか?私が以前のブログ記事で言ったように、Clojureはかなり柔軟で、簡単にatom . しかし、統合状態のような良い状態管理ライブラリは、はるかに提供しています.Inteantでは、あなたのコンポーネントを管理し、どのようにお互いにあなたのアプリケーションの全体的な状態を作るために関連する簡単なEZNファイルを持つことができます.Integrantのもう一つの強力な機能は、異なる目的(例えばテストの実行のための状態とテストのための状態)のために異なる状態を簡単に作成する能力であり、これらの状態をリセットする.次の章でこれらの機能を展開しましょう.

EDNとしての積分状態構成


あなたの状態の初期設定を提供する構成ファイルを作成することができますどのようにさまざまなコンポーネントとその相互作用で構築されます.これはかなり良いです.この動画を見るconfig.edn ファイル.CSV、DynamoDB、Postgresの3つの「データストア」と、これらのそれぞれに対する統合的な設定を作成したことがわかります.
 :backend/csv {:profile #ig/ref :backend/profile
               :active-db #ig/ref :backend/active-db
               :data-dir "dev-resources/data"}

 :backend/ddb {:active-db #ig/ref :backend/active-db
               :ss-table-prefix "ss"
               :ss-env #profile {:prod "prod"
                                 :dev "dev"
                                 :test "test"}
               :endpoint {:protocol :http :hostname "localhost" :port 8000}
               :aws-profile "local-dynamodb"}

 :backend/postgres {:active-db #ig/ref :backend/active-db
                    :adapter "postgresql"
                    :username #or [#env DB_USERNAME "simpleserver"]
                    :password #or [#env DB_PASSWORD "simpleserver"]
                    :server-name #or [#env DB_HOST "localhost"]
                    :port-number #long #or [#env DB_PORT 5532]
                    :database-name #or [#env DB_NAME "simpleserver"]
...

サービスコンポーネントには、これらのデータストアコンポーネントへの参照があります.
 ; Gather different data store services here.
 :backend/service {:profile #ig/ref :backend/profile
                   :active-db #ig/ref :backend/active-db
                   :csv #ig/ref :backend/csv
                   :ddb #ig/ref :backend/ddb
                   :postgres #ig/ref :backend/postgres
                   }

私は他のコンポーネント、Jetty、NREPLなどを省略しています.確かに、あなたの状態は非常に簡単ですが、この機能を必要としないが、あなたの状態が多くのコンポーネントとそれらの間のさまざまな相互作用がある場合、この機能はかなり良いです.
私が使用する積分構成を読むためにAero . Aeroは、環境変数を単純な条件付けと文字列から数値への変換のためのコンポーネントとメカニズムの内部の値に注入する良い方法を提供します.:port-number #long #or [#env DB_PORT 5532] - すなわち、環境変数DBLANEポートを使用しています.

積分による異なる状態


もう一つの強力な機能は、異なる目的のために異なる状態を作成することです.例えば、この演習では、2つの状態を作りました.プロダクション(開発中)でシステムを実行し、テストを実行するための1つです.プロダクション/開発状態はconfig.edn の設定と構成core.clj ファイル
例えば、それぞれのデータストアには非常に異なる状態が現れます.
(defmethod ig/init-key :backend/csv [_ {:keys [profile active-db data-dir]}]
  (log/debug "ENTER ig/init-key :backend/csv")
  ; We simulate this data store using atom.
  ; We initialize the "db" from :data-dir.
  (if (= active-db :csv)
    (let [csv-data
          {:data-dir data-dir
           :db (atom {:domain {}
                      :session #{}
                      :user {}})}]
      ; Let's keep the test database empty.
      (if (not= profile :test)
        (csv-db-loader/load-csv-db csv-data))
      (:db csv-data))))

(defmethod ig/init-key :backend/ddb [_ {:keys [active-db ss-table-prefix ss-env endpoint aws-profile]}]
  (log/debug "ENTER ig/init-key :backend/ddb")
  (if (= active-db :ddb)
    (ddb-config/get-dynamodb-config ss-table-prefix ss-env endpoint aws-profile)))

(defmethod ig/init-key :backend/postgres [_ opts]
  (log/debug "ENTER ig/init-key :backend/postgres")
  (if (= (:active-db opts) :postgres)
    {:datasource (hikari-cp/make-datasource (dissoc opts :active-db)) :active-db (:active-db opts)}))

“CSV”データベースは、CSVファイルから初期化され、我々は単純なclojure原子を使用してデータベースを“シミュレート”.我々がデータストアとしてダイナモを使うとき、我々は尋ねますget-dynamodb-config 状態を初期化する関数.PostgreSQLのデータストアを使用する場合には、hikari-pc データベース接続を初期化するライブラリ.
The test_config.clj ファイルはテスト状態初期化を含んでいる.これは、主に実際の状態初期化を再利用するが、いくつかの値を上書きします.
(defn test-config []
  (let [test-port (random-port)
        ; Overriding the port with random port, see TODO below.
        _ (log/debug (str "test-config, using web-server test port: " test-port))]
    (-> (core/system-config :test)
        ;; Use the same data dir also for test system. It just initializes data.
        (assoc-in [:backend/csv :data-dir] "dev-resources/data")
        (assoc-in [:backend/jetty :port] test-port)
        ;; In Postgres test setup use simpleserver_test database.
        (assoc-in [:backend/postgres :database-name] "simpleserver_test")
        ;; No nrepl needed in tests. If used, use other port than the main system.
        (assoc-in [:backend/nrepl :bind] nil)
        (assoc-in [:backend/nrepl :port] nil)
        (assoc-in [:backend/csv :port] nil))))

例えば、Jetty用の異なるポートを使用して、Jettyを同時に開発・テストすることができます.また、テスト用にPostgreSQLデータベースも使用します.

状態のリセット


Inteantは、状態をリセットするための良い補助機能を提供します:移動、リセット、停止など-これらの機能の意味をチェックしてくださいIntegrant Repl documentation . 創作したCursive 最も使用される補助関数のホットキーなど.(integrant.repl/reset) is alt-J . それで、どんな名前空間のどんな変化でもするとき、そしてalt-J Integrantは影響を受けた名前空間を再読み込みするのを面倒にして、状態をリセットします.これは目の点滅で起こるので、私は打っていますalt-J クロジュールをするとき、かなりしばしば.
もし開発状態があったら、その状態を問い合わせることができます.
(user/env)
=>
{:profile :dev,
 :active-db :postgres,
 :service {:domain #simpleserver.service.domain.domain_postgres.PostgresR{:db {:datasource #object[com.zaxxer.hikari.HikariDataSource
                          0x42ab0edd
                          "HikariDataSource (HikariPool-33)"],
...

テストはテスト状態を開始しますが、手動で起動し、テスト状態を問い合わせることもできます.
(simpleserver.test-config/go)
(simpleserver.test-config/test-env)
=>
{:profile :test,
 :active-db :postgres,
 :service {:domain #simpleserver.service.domain.domain_postgres.PostgresR{:db {:datasource #object[com.zaxxer.hikari.HikariDataSource
                          0x780ac829
                          "HikariDataSource (HikariPool-35)"],
...

ご覧の通りHikariDataSource はそれらの状態の異なるオブジェクトです.
これはかなり良いです.私は通常、開発状態を打つ私のスクラッチファイルで異なるものを実験します.私が幸せなとき、私は傷コードからコードを生産コードに移します.いくつかのテストに問題がある場合は、手動でテスト構成を開始し、テストコードからフォームを送信してREPLで実行し、フォームがテスト状態に達することができます.

ランニングテスト


私はJust DynamoDBとPostgresデータベースの両方のレシピ.の両方から始めましょう.
λ> just
Available recipes:
    backend # Start backend repl.
    backend-kari # Start backend repl with my toolbox.
    dynamodb # Start local dynamodb emulator
    lint # Lint
    list
    postgres # Start local postgres
    test db # Test

# First Postgres...
λ> just postgres
NOTE: Remember to destroy the container if running again!
Starting docker compose...
Creating ss-postgres_postgres_1 ... done
Creating Simple Server schemas...
...

# ...and then DynamoDB...
λ> just dynamodb
Sending build context to Docker daemon 62.11MB
Step 1/15 : FROM python:3.8.2-slim-buster
 ---> e7d894e42148
Step 2/15 : RUN rm /bin/sh && ln -s /bin/bash /bin/sh
 ---> Using cache
...
Successfully tagged ss-uploader:0.1
Creating ss-dynamodb_local-dynamodb_1 ... done
Creating ss-dynamodb_uploader-app_1 ... done
Attaching to ss-dynamodb_local-dynamodb_1, ss-dynamodb_uploader-app_1
...

intellij idea/cursiveのテストを実行したいなら、アクティブなデータストアをconfig.edn :
 ; csv, ddb, postgres
 ;:backend/active-db #or [#env SS_DB :csv]
 ;:backend/active-db #or [#env SS_DB :ddb]
 :backend/active-db #or [#env SS_DB :postgres]
...

...そして、整数値をリセットし、intellij - idea/cursiveでテストを実行します.

intellij idea/cursive ideにおけるClojure Integrant Exerciseのランニングテスト
私の設定では、私のSimpleServerのDBフラグをSS_DB ) 存在するなら、それを使ってください.したがって、上記のように、コマンドラインでテストスイートを実行することもできます.Justfile :
# Test
@test db:
    ./run-tests.sh 

…とrun-tests.sh SimCount DBフラグを設定するヘルパーは、以下のコマンドで使用されます.
...
MYDB=$1
if [["$MYDB" =~ ^(csv|ddb|postgres)$]]; then
    echo "Starting tests with $MYDB configuration..."
else
    echo "Unknown DB configuration: $MYDB, exiting..."
    exit 2
fi
SS_DB=$MYDB clojure -A:dev:test:common:backend -m kaocha.runner

テストを実行しましょう.
# First using DynamoDB as data store...
λ> just test ddb
Starting tests with ddb configuration...
[(........)(...........................)(...)(.......)]
14 tests, 45 assertions, 0 failures.
# ...and then Postgres:
λ> just test postgres
Starting tests with postgres configuration...
[(...)(...........................)(.......)(........)]
14 tests, 45 assertions, 0 failures.

...とIntegrateは、アプリケーションが右のデータストアを使用するように、テスト状態を構成することに注意します.

結論


私はこの積分練習をしたことがうれしいです.私は今、高品質の状態管理ライブラリを使用して利益を実現する国家管理自分自身を実装する.LISPとしてクロジュールが本当に強力で柔軟なので、あなたは非常に簡単に自分自身の状態管理を行うことができます.しかし、高品質の状態管理ライブラリを使用して、基本的に無料であなたがそれを心配する必要はありませんが、構成として状態を記述し、開発中に別の目的のために異なる状態を使用するように基本的な配管を提供します.
作家は、クラウドプロジェクトでclojureを使ってMetosinで働いています.あなたがフィンランドでClojureプロジェクトを始めることに興味があるならば、または、あなたはフィンランドでClojureトレーニングを得ることに興味があります.
カリマルティラ
  • LinkedInのカーラマルティラのホームページ