{"id":293422,"date":"2019-08-15T09:01:12","date_gmt":"2019-08-15T09:01:12","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=293422"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=293422","title":{"rendered":"\u0412\u044b\u0431\u0438\u0440\u0430\u0435\u043c\u0441\u044f \u0438\u0437 \u0434\u0435\u0431\u0440\u0435\u0439 \u0442\u0435\u0441\u0442\u043e\u0432: \u0441\u0442\u0440\u043e\u0438\u043c \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0439 \u043f\u0443\u0442\u044c \u043e\u0442\u00a0\u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b \u043a \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435"},"content":{"rendered":"\n<div class=\"post__text post__text-html js-mediator-article\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/mu\/ll\/ar\/mullaroquhqtdb05ygvb82nmghu.jpeg\"><\/p>\n<p>  <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u0442\u044c \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0443 \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u043e\u043c\u0443 \u0441\u0442\u0438\u043b\u044e \u0434\u0438\u0437\u0430\u0439\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 Scala. \u041f\u043e\u0434\u0445\u043e\u0434 \u0431\u044b\u043b \u043d\u0430\u0432\u0435\u044f\u043d \u043c\u043d\u043e\u0433\u043e\u043c\u0435\u0441\u044f\u0447\u043d\u043e\u0439 \u0431\u043e\u043b\u044c\u044e \u043e\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u0434\u0435\u0441\u044f\u0442\u043a\u043e\u0432 \u0438 \u0441\u043e\u0442\u0435\u043d \u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0436\u0433\u0443\u0447\u0438\u043c \u0436\u0435\u043b\u0430\u043d\u0438\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u0445 \u043f\u0440\u043e\u0449\u0435 \u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u0435\u0435.<\/p>\n<p>  <\/p>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043a\u043e\u0434 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 Scala, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u044b\u0435 \u0438\u0434\u0435\u0438 \u0431\u0443\u0434\u0443\u0442 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u043e\u0432 \u043d\u0430 \u0432\u0441\u0435\u0445 \u044f\u0437\u044b\u043a\u0430\u0445, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u0445 \u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u0421\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 Github \u0441 \u043f\u043e\u043b\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<h2 id=\"problema\">\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430<\/h2>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u043a\u043e\u0433\u0434\u0430-\u043b\u0438\u0431\u043e \u0438\u043c\u0435\u043b\u0438 \u0434\u0435\u043b\u043e \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 (\u043d\u0435 \u0432\u0430\u0436\u043d\u043e \u2014 \u044e\u043d\u0438\u0442-\u0442\u0435\u0441\u0442\u0430\u043c\u0438, \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c\u0438 \u0438\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c\u0438), \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u043e\u043d\u0438 \u0431\u044b\u043b\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u0432 \u0432\u0438\u0434\u0435 \u043d\u0430\u0431\u043e\u0440\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439. \u041a \u043f\u0440\u0438\u043c\u0435\u0440\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"scala\">\/\/ \u0414\u0430\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043c\u0430\u0433\u0430\u0437\u0438\u043d. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0441\u043e\u0432\u043e\u043a\u0443\u043f\u043d\u043e\u0441\u0442\u0438 \/\/ \u0441\u0432\u043e\u0435\u0439 \u0440\u043e\u043b\u0438, \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0431\u043e\u043d\u0443\u0441\u043e\u0432 \u0438 \u043e\u0431\u0449\u0435\u0439 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u0437\u0430\u043a\u0430\u0437\u0430, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \/\/ \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043a\u0438\u0434\u043a\u0443 \u0440\u0430\u0437\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430. \"\u0415\u0441\u043b\u0438 \u0440\u043e\u043b\u044c \u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b\u044f = 'customer'\" - {   import TestHelper._   \"\u0418 \u043e\u0431\u0449\u0430\u044f \u0441\u0443\u043c\u043c\u0430 \u043f\u043e\u043a\u0443\u043f\u043a\u0438 &lt; 250 \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0447\u0435\u0442\u0430 \u0431\u043e\u043d\u0443\u0441\u043e\u0432 - \u043d\u0435\u0442 \u0441\u043a\u0438\u0434\u043a\u0438\" in {     val db: Database = Database.forURL(TestConfig.generateNewUrl())     migrateDb(db)     insertUser(db, id = 1, name = \"test\", role = \"customer\")     insertPackage(db, id = 1, name = \"test\", userId = 1, status = \"new\")     insertPackageItems(db, id = 1, packageId = 1, name = \"test\", price = 30)     insertPackageItems(db, id = 2, packageId = 1, name = \"test\", price = 20)     insertPackageItems(db, id = 3, packageId = 1, name = \"test\", price = 40)      val svc = new SomeProductionLogic(db)     val result = svc.calculatePrice(packageId = 1)     result shouldBe 90   }   \"\u0418 \u043e\u0431\u0449\u0430\u044f \u0441\u0443\u043c\u043c\u0430 \u043f\u043e\u043a\u0443\u043f\u043a\u0438 &gt;= 250 \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0447\u0435\u0442\u0430 \u0431\u043e\u043d\u0443\u0441\u043e\u0432 - \u0441\u043a\u0438\u0434\u043a\u0430 10%\" in {     val db: Database = Database.forURL(TestConfig.generateNewUrl())     migrateDb(db)     insertUser(db, id = 1, name = \"test\", role = \"customer\")     insertPackage(db, id = 1, name = \"test\", userId = 1, status = \"new\")     insertPackageItems(db, id = 1, packageId = 1, name = \"test\", price = 100)     insertPackageItems(db, id = 2, packageId = 1, name = \"test\", price = 120)     insertPackageItems(db, id = 3, packageId = 1, name = \"test\", price = 130)     insertBonus(db, id = 1, packageId = 1, bonusAmount = 40)      val svc = new SomeProductionLogic(db)     val result = svc.calculatePrice(packageId = 1)     result shouldBe 279   } } \"\u0415\u0441\u043b\u0438 \u0440\u043e\u043b\u044c \u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b\u044f = 'vip'\" - {\/*...*\/}<\/code><\/pre>\n<p>  <\/p>\n<p>\u042d\u0442\u043e \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430, \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u044e\u0449\u0438\u0439 \u043e\u0441\u0432\u043e\u0435\u043d\u0438\u044f, \u0441\u043f\u043e\u0441\u043e\u0431 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432. \u0412 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043e\u043a\u043e\u043b\u043e 1000 \u0442\u0435\u0441\u0442\u043e\u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0443\u0440\u043e\u0432\u043d\u0435\u0439 (\u044e\u043d\u0438\u0442-\u0442\u0435\u0441\u0442\u043e\u0432, \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445, end-to-end), \u0438 \u0432\u0441\u0435 \u043e\u043d\u0438, \u0434\u043e \u043d\u0435\u0434\u0430\u0432\u043d\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0431\u044b\u043b\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u0432 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435. \u041f\u043e \u043c\u0435\u0440\u0435 \u0440\u043e\u0441\u0442\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043c\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u043e\u0449\u0443\u0449\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0438 \u0437\u0430\u043c\u0435\u0434\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 \u0442\u0430\u043a\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432: \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0437\u0430\u043d\u0438\u043c\u0430\u043b\u043e \u043d\u0435 \u043c\u0435\u043d\u044c\u0448\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0447\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0431\u0438\u0437\u043d\u0435\u0441-\u0437\u043d\u0430\u0447\u0438\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430.<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u043d\u043e\u0432\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u043f\u0440\u0438\u0434\u0443\u043c\u044b\u0432\u0430\u0442\u044c \u0441 \u043d\u0443\u043b\u044f, \u043a\u0430\u043a \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435. \u0417\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u043e\u0439 \u0448\u0430\u0433\u043e\u0432 \u0438\u0437 \u0441\u043e\u0441\u0435\u0434\u043d\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432. \u041a\u0430\u043a \u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0435, \u043a\u043e\u0433\u0434\u0430 \u0438\u0437\u043c\u0435\u043d\u044f\u043b\u0430\u0441\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u043a\u0430\u0440\u0442\u043e\u0447\u043d\u044b\u0439 \u0434\u043e\u043c\u0438\u043a \u0440\u0430\u0441\u0441\u044b\u043f\u0430\u043b\u0441\u044f \u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0435\u0433\u043e \u043f\u043e-\u043d\u043e\u0432\u043e\u0439 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0442\u0435\u0441\u0442\u0435: \u0432 \u043b\u0443\u0447\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0439-\u0445\u0435\u043b\u043f\u0435\u0440\u043e\u0432, \u0432 \u0445\u0443\u0434\u0448\u0435\u043c \u2014 \u0433\u043b\u0443\u0431\u043e\u043a\u0438\u043c \u043f\u043e\u0433\u0440\u0443\u0436\u0435\u043d\u0438\u0435\u043c \u0432 \u0442\u0435\u0441\u0442 \u0438 \u0435\u0433\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043d\u0438\u0435\u043c.<\/p>\n<p>  <\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0442\u0435\u0441\u0442 \u043f\u0430\u0434\u0430\u043b \u0447\u0435\u0441\u0442\u043d\u043e \u2014 \u0442. \u0435. \u0438\u0437-\u0437\u0430 \u0431\u0430\u0433\u0430 \u0432 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0435, \u0430 \u043d\u0435 \u0438\u0437-\u0437\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0432 \u0441\u0430\u043c\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u2014 \u043f\u043e\u043d\u044f\u0442\u044c, \u0433\u0434\u0435 \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0448\u043b\u043e \u043d\u0435 \u0442\u0430\u043a, \u0431\u0435\u0437 \u0434\u0435\u0431\u0430\u0433\u0430 \u0431\u044b\u043b\u043e \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e. \u0418\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0434\u043e\u043b\u0433\u043e \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f, \u043d\u0438\u043a\u0442\u043e \u0432 \u043f\u043e\u043b\u043d\u043e\u0439 \u043c\u0435\u0440\u0435 \u043d\u0435 \u043e\u0431\u043b\u0430\u0434\u0430\u043b \u0437\u043d\u0430\u043d\u0438\u044f\u043c\u0438 \u043e \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\u0445 \u2014 \u043a\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u0435\u0431\u044f \u0432\u0435\u0441\u0442\u0438 \u043f\u0440\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445.<\/p>\n<p>  <\/p>\n<p>\u0412\u0441\u044f \u044d\u0442\u0430 \u0431\u043e\u043b\u044c \u2014 \u0441\u0438\u043c\u043f\u0442\u043e\u043c\u044b \u0434\u0432\u0443\u0445 \u0431\u043e\u043b\u0435\u0435 \u0433\u043b\u0443\u0431\u043e\u043a\u0438\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0442\u0430\u043a\u043e\u0433\u043e \u0434\u0438\u0437\u0430\u0439\u043d\u0430:<\/p>\n<p>  <\/p>\n<ol>\n<li>\u0421\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0442\u0435\u0441\u0442\u0430 \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u0435. \u041a\u0430\u0436\u0434\u044b\u0439 \u0442\u0435\u0441\u0442 \u0443\u043d\u0438\u043a\u0430\u043b\u0435\u043d, \u043a\u0430\u043a \u0441\u043d\u0435\u0436\u0438\u043d\u043a\u0430. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0434\u0435\u0442\u0430\u043b\u0438 \u0442\u0435\u0441\u0442\u0430 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438 \u0434\u0435\u043c\u043e\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u0442. \u041d\u0435 \u0432\u0430\u0436\u043d\u044b\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u043e\u0442\u0432\u043b\u0435\u043a\u0430\u044e\u0442 \u043e\u0442 \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u2014 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u043e\u043c. \u041a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u0430 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432.<\/li>\n<li>\u0422\u0435\u0441\u0442\u044b \u043d\u0435 \u043f\u043e\u043c\u043e\u0433\u0430\u044e\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0430\u0433\u0438, \u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u044e\u0442 \u043e \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0435. \u0427\u0442\u043e\u0431\u044b \u043f\u043e\u043d\u044f\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0442\u0435\u0441\u0442, \u043d\u0443\u0436\u043d\u043e \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u0433\u043e\u043b\u043e\u0432\u0435 \u0438\u043b\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u0434\u0435\u0431\u0430\u0433\u0433\u0435\u0440\u043e\u043c.<\/li>\n<\/ol>\n<p>  <\/p>\n<h2 id=\"modelirovanie\">\u041c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h2>\n<p>  <\/p>\n<p>\u041c\u043e\u0436\u0435\u043c \u043b\u0438 \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043b\u0443\u0447\u0448\u0435? (\u0421\u043f\u043e\u0439\u043b\u0435\u0440: \u043c\u043e\u0436\u0435\u043c.) \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0438\u0437 \u0447\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u044d\u0442\u043e\u0442 \u0442\u0435\u0441\u0442.<\/p>\n<p>  <\/p>\n<pre><code class=\"scala\">val db: Database = Database.forURL(TestConfig.generateNewUrl()) migrateDb(db) insertUser(db, id = 1, name = \"test\", role = \"customer\") insertPackage(db, id = 1, name = \"test\", userId = 1, status = \"new\") insertPackageItems(db, id = 1, packageId = 1, name = \"test\", price = 30) insertPackageItems(db, id = 2, packageId = 1, name = \"test\", price = 20) insertPackageItems(db, id = 3, packageId = 1, name = \"test\", price = 40)<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u043a\u043e\u0434, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0431\u0443\u0434\u0435\u0442 \u0436\u0434\u0430\u0442\u044c \u043d\u0430 \u0432\u0445\u043e\u0434 \u043d\u0435\u043a\u0438\u0435 \u044f\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u2014 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b, \u0440\u0430\u0437\u043c\u0435\u0440\u044b, \u043e\u0431\u044a\u0435\u043c\u044b, \u0444\u0438\u043b\u044c\u0442\u0440\u044b \u0438 \u0442. \u043f. \u0422\u0430\u043a\u0436\u0435 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0435\u043c\u0443 \u0431\u0443\u0434\u0443\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043c\u0438\u0440\u0430 \u2014 \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043c\u0435\u043d\u044e \u0438 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 \u043c\u0435\u043d\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0414\u043b\u044f \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u0430 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f <em>\u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430<\/em> (<em>fixture<\/em>) \u2014 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0434\u043e\u043b\u0436\u043d\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0438\/\u0438\u043b\u0438 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u0430 \u0438 \u0432\u0445\u043e\u0434\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u043d\u0435\u0440\u0435\u0434\u043a\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c.<\/p>\n<p>  <\/p>\n<p>\u042d\u0442\u043e\u0439 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u043e\u0439 \u043c\u044b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c <em>\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c<\/em> (<em>dependency<\/em>) \u2014 \u043d\u0430\u043f\u043e\u043b\u043d\u0438\u043c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 (\u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0438 \u0442. \u043f.). \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u0439 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u043c\u044b \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 (\u0441\u0435\u0440\u0432\u0438\u0441\u044b, \u043c\u043e\u0434\u0443\u043b\u0438, \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438, \u0442. \u043f.).<\/p>\n<p>  <\/p>\n<pre><code class=\"scala\">val svc = new SomeProductionLogic(db) val result = svc.calculatePrice(packageId = 1)<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0432 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u043a\u043e\u0434 \u043d\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0431\u0438\u0437\u043d\u0435\u0441-\u0437\u043d\u0430\u0447\u0438\u043c\u044b\u0439 <em>\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/em> (<em>output<\/em>) \u2014 \u043a\u0430\u043a \u044f\u0432\u043d\u044b\u0439 (\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434\u043e\u043c), \u0442\u0430\u043a \u0438 \u043d\u0435\u044f\u0432\u043d\u044b\u0439 \u2014 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043f\u0440\u0435\u0441\u043b\u043e\u0432\u0443\u0442\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f: \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0438 \u0442. \u0434.<\/p>\n<p>  <\/p>\n<pre><code class=\"scala\">result shouldBe 90<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u0440\u043e\u0432\u043d\u043e \u0442\u0430\u043a\u0438\u043c\u0438, \u043a\u0430\u043a\u0438\u043c\u0438 \u043e\u0436\u0438\u0434\u0430\u043b\u0438, \u043f\u043e\u0434\u0432\u043e\u0434\u044f \u0438\u0442\u043e\u0433 \u0442\u0435\u0441\u0442\u0430 \u043e\u0434\u043d\u043e\u0439 \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 <em>\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u043c\u0438<\/em> (<em>assertion<\/em>).<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/em\/aa\/rb\/emaarb5ltmnme4-wpda0ebakueq.jpeg\"><\/p>\n<p>  <\/p>\n<p>\u041c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0439\u0442\u0438 \u043a \u0432\u044b\u0432\u043e\u0434\u0443, \u0447\u0442\u043e \u0432 \u0446\u0435\u043b\u043e\u043c \u0442\u0435\u0441\u0442 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043e\u0434\u043d\u0438\u0445 \u0438 \u0442\u0435\u0445 \u0436\u0435 \u0441\u0442\u0430\u0434\u0438\u0439: \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432, \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043d\u0430 \u043d\u0438\u0445 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0441 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u043c\u0438. \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u0444\u0430\u043a\u0442, \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 <strong>\u043f\u0435\u0440\u0432\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0432 \u0442\u0435\u0441\u0442\u0435<\/strong> \u2014 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u044b, \u044f\u0432\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0432 \u0442\u0435\u0441\u0442 \u043d\u0430 \u0441\u0442\u0430\u0434\u0438\u0438. \u042d\u0442\u0430 \u0438\u0434\u0435\u044f \u043d\u0435 \u043d\u043e\u0432\u0430 \u0438 \u0443\u0436\u0435 \u0434\u0430\u0432\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u0432 BDD-\u0441\u0442\u0438\u043b\u0435 (<em>behavior-driven development<\/em>).<\/p>\n<p>  <\/p>\n<p>\u0427\u0442\u043e \u043d\u0430\u0441\u0447\u0435\u0442 \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u043e\u0441\u0442\u0438? \u041b\u044e\u0431\u043e\u0439 \u0438\u0437 \u0448\u0430\u0433\u043e\u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432 \u0441\u0435\u0431\u0435 \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0433\u043e\u0434\u043d\u043e \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0445. \u0417\u0430\u0431\u0435\u0433\u0430\u044f \u0432\u043f\u0435\u0440\u0435\u0434, \u043c\u044b \u043c\u043e\u0433\u043b\u0438 \u0431\u044b \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443, \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u044f \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0435\u043a\u0443\u044e \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u043e\u0447\u0438\u0442\u0430\u0435\u043c\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u0430 \u043f\u043e\u0442\u043e\u043c \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0435 \u0432 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0411\u0414. \u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c, \u043d\u043e, \u0432 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c \u0441\u0447\u0435\u0442\u0435, \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0441\u0442\u0430\u0434\u0438\u044f\u043c.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/55\/qf\/zl\/55qfzlhkl99txyyhizbvzg48yhs.jpeg\"><\/p>\n<p>  <\/p>\n<h2 id=\"zapusk-testov\">\u0417\u0430\u043f\u0443\u0441\u043a \u0442\u0435\u0441\u0442\u043e\u0432<\/h2>\n<p>  <\/p>\n<p>\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0432\u043e\u043f\u043b\u043e\u0442\u0438\u0442\u044c \u0438\u0434\u0435\u044e \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u0430 \u043d\u0430 \u0441\u0442\u0430\u0434\u0438\u0438, \u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c, \u043a\u0430\u043a\u0438\u043c \u0431\u044b \u043c\u044b \u0445\u043e\u0442\u0435\u043b\u0438 \u0432\u0438\u0434\u0435\u0442\u044c \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442.<\/p>\n<p>  <\/p>\n<p>\u0412 \u0446\u0435\u043b\u043e\u043c, \u043d\u0430\u043c \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0442\u0435\u0441\u0442\u043e\u0432 \u043c\u0435\u043d\u0435\u0435 \u0442\u0440\u0443\u0434\u043e\u0437\u0430\u0442\u0440\u0430\u0442\u043d\u044b\u043c \u0438 \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u0438\u044f\u0442\u043d\u044b\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c. \u0427\u0435\u043c \u043c\u0435\u043d\u044c\u0448\u0435 \u0432 \u0442\u0435\u043b\u0435 \u0442\u0435\u0441\u0442\u0430 \u044f\u0432\u043d\u044b\u0445 \u043d\u0435\u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 (\u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0449\u0438\u0445\u0441\u044f \u0433\u0434\u0435-\u0442\u043e \u0435\u0449\u0435) \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439, \u0442\u0435\u043c \u043c\u0435\u043d\u044c\u0448\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u043d\u043e\u0441\u0438\u0442\u044c \u0432 \u0442\u0435\u0441\u0442\u044b \u043f\u043e\u0441\u043b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432 \u0438\u043b\u0438 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0438 \u0442\u0435\u043c \u043c\u0435\u043d\u044c\u0448\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043d\u0430 \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u0435 \u0442\u0435\u0441\u0442\u0430. \u0414\u0438\u0437\u0430\u0439\u043d \u0442\u0435\u0441\u0442\u0430 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u0434\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0442\u044c \u043a \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u043a\u0443\u0441\u043a\u043e\u0432 \u043a\u043e\u0434\u0430 \u0438 \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0431\u0435\u0437\u0434\u0443\u043c\u043d\u043e\u043c\u0443 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e. \u041d\u0435\u043f\u043b\u043e\u0445\u043e \u0431\u044b\u043b\u043e \u0431\u044b, \u0435\u0441\u043b\u0438 \u0431\u044b \u0442\u0435\u0441\u0442\u044b \u0438\u043c\u0435\u043b\u0438 \u0443\u043d\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432\u0438\u0434. \u041f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u043e\u0441\u0442\u044c \u0443\u043b\u0443\u0447\u0448\u0430\u0435\u0442 \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u044c \u0438 \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442 \u0432\u0440\u0435\u043c\u044f \u2014 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u044c\u0442\u0435, \u043a\u0430\u043a \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0431\u044b \u0443\u0445\u043e\u0434\u0438\u043b\u043e \u0443 \u0441\u0442\u0443\u0434\u0435\u043d\u0442\u043e\u0432-\u0444\u0438\u0437\u0438\u043a\u043e\u0432 \u043d\u0430 \u043e\u0441\u0432\u043e\u0435\u043d\u0438\u0435 \u043a\u0430\u0436\u0434\u043e\u0439 \u043d\u043e\u0432\u043e\u0439 \u0444\u043e\u0440\u043c\u0443\u043b\u044b, \u0435\u0441\u043b\u0438 \u0431\u044b \u043e\u043d\u0438 \u0431\u044b\u043b\u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0441\u043b\u043e\u0432\u0430\u043c\u0438 \u0432 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u0435, \u0430 \u043d\u0435 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u044f\u0437\u044b\u043a\u043e\u043c.<\/p>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043d\u0430\u0448\u0430 \u0446\u0435\u043b\u044c \u2014 \u0441\u043a\u0440\u044b\u0442\u044c \u0432\u0441\u0435 \u043e\u0442\u0432\u043b\u0435\u043a\u0430\u044e\u0449\u0435\u0435 \u0438 \u043b\u0438\u0448\u043d\u0435\u0435, \u043e\u0441\u0442\u0430\u0432\u0438\u0432 \u043d\u0430 \u0432\u0438\u0434\u0443 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0430\u0436\u043d\u0443\u044e \u0434\u043b\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e: \u0447\u0442\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u043e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0432\u0445\u043e\u0434\u0435, \u0430 \u0447\u0442\u043e \u2014 \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/em\/aa\/rb\/emaarb5ltmnme4-wpda0ebakueq.jpeg\"><\/p>\n<p>  <\/p>\n<p>\u0412\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u043c\u043e\u0434\u0435\u043b\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0442\u0435\u0441\u0442\u0430. \u0422\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u0430\u0436\u0434\u0443\u044e \u0442\u043e\u0447\u043a\u0443 \u043d\u0430 \u044d\u0442\u043e\u043c \u0433\u0440\u0430\u0444\u0438\u043a\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b \u0438\u0437 \u043e\u0434\u043d\u043e\u0439 \u0432 \u0434\u0440\u0443\u0433\u0443\u044e \u2014 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u041f\u0440\u0438\u0439\u0442\u0438 \u043e\u0442 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043a \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c\u0443 \u043c\u043e\u0436\u043d\u043e, \u043f\u043e\u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043a \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0443 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439. \u0418\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <em>\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0439<\/em>: \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 (\u043d\u0430\u0437\u043e\u0432\u0435\u043c \u0435\u0435 <code>prepare<\/code>), \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430 (<code>execute<\/code>) \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e\u0433\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 (<code>check<\/code>). \u041d\u0430 \u0432\u0445\u043e\u0434 \u044d\u0442\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0434\u0438\u043c \u043f\u0435\u0440\u0432\u0443\u044e \u0442\u043e\u0447\u043a\u0443 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u2014 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443. \u041f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0443\u044e\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432\u044b\u0441\u0448\u0435\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430 \u043d\u0430\u0437\u043e\u0432\u0435\u043c <strong>\u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430<\/strong> \u0442\u0435\u0441\u0442\u0430.<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">def runTestCycle[FX, DEP, OUT, F[_]](   fixture: FX,   prepare: FX =&gt; DEP,   execute: DEP =&gt; OUT,    check: OUT =&gt; F[Assertion] ): F[Assertion] =   \/\/ \u0412 Scala \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0438\u0441\u0430\u0442\u044c check(execute(prepare(fixture)))   \/\/ \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0447\u0438\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0441 \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 andThen:   (prepare andThen execute andThen check) (fixture)<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0412\u0441\u0442\u0430\u0435\u0442 \u0432\u043e\u043f\u0440\u043e\u0441, \u043e\u0442\u043a\u0443\u0434\u0430 \u0432\u043e\u0437\u044c\u043c\u0443\u0442\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438? \u0413\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u2014 \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0431\u0430\u0437\u0443, \u043c\u043e\u043a\u0430\u0442\u044c, \u0442. \u043f. \u2014 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0438 prepare \u0431\u0443\u0434\u0443\u0442 \u043e\u0431\u0449\u0438\u0435 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0442\u0435\u0441\u0442\u043e\u0432. \u041a\u0430\u043a \u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0435, \u043f\u0440\u043e\u0449\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430, \u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0438\u0435 \u0432 \u0441\u0435\u0431\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0441\u043f\u043e\u0441\u043e\u0431\u044b \u0432\u044b\u0437\u043e\u0432\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u2014 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430, <code>execute<\/code> \u0438 <code>check<\/code> \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u044f\u0432\u043d\u043e.<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0410\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u043f\u043e\u0434 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u043d\u0430 \u0411\u0414 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">\/\/ \u041d\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0431\u0430\u0437\u0443 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u043e\u0439 \u2014 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 def prepareDatabase[DB](db: Database): DbFixture =&gt; DB  def testInDb[DB, OUT](   fixture: DbFixture,   execute: DB =&gt; OUT,   check: OUT =&gt; Future[Assertion],   db: Database = getDatabaseHandleFromSomewhere(), ): Future[Assertion] =   runTestCycle(fixture, prepareDatabase(db), execute, check)<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0414\u0435\u043b\u0435\u0433\u0438\u0440\u0443\u044f \u0432\u0441\u0435 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u043d\u044e\u0430\u043d\u0441\u044b \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043d\u0435 \u0432\u043b\u0435\u0437\u0430\u044f \u043d\u0438 \u0432 \u043e\u0434\u0438\u043d \u0443\u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0442\u0435\u0441\u0442. \u0417\u0430 \u0441\u0447\u0435\u0442 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u043d\u0435\u0434\u0440\u044f\u0442\u044c\u0441\u044f \u0432 \u043b\u044e\u0431\u0443\u044e \u0442\u043e\u0447\u043a\u0443 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430, \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u044c \u0438\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0442\u0443\u0434\u0430 \u0434\u0430\u043d\u043d\u044b\u0435.<\/p>\n<p>  <\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043b\u0443\u0447\u0448\u0435 \u043f\u0440\u043e\u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430, \u0440\u0435\u0448\u0438\u043c <strong>\u0432\u0442\u043e\u0440\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443<\/strong> \u043d\u0430\u0448\u0435\u0433\u043e \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430 \u2014 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430. \u041d\u0430\u0448\u0435 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043b\u0438\u0448\u044c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c <em>\u0441\u0430\u0439\u0434-\u044d\u0444\u0444\u0435\u043a\u0442<\/em> \u2014 \u0432\u044b\u0432\u043e\u0434 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0430 \u043a\u043e\u043d\u0441\u043e\u043b\u044c. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0441\u043b\u0435 \u0441\u0430\u0439\u0434-\u044d\u0444\u0444\u0435\u043a\u0442\u0430 \u043c\u044b \u0432\u0435\u0440\u043d\u0435\u043c \u0435\u0433\u043e \u043a\u0430\u043a \u0435\u0441\u0442\u044c.<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u0441 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">def logged[T](implicit loggedT: Logged[T]): T =&gt; T =    (that: T) =&gt; {     \/\/ \u041f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u0438\u043d\u0441\u0442\u0430\u043d\u0441 \u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u0430 Logged \u0434\u043b\u044f T,     \/\/ \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u201c\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c\u201d \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u043c\u0443 that \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 log().     \/\/ \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u0430\u0445 - \u0434\u0430\u043b\u044c\u0448\u0435.      loggedT.log(that) \/\/ \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0437\u0430\u043f\u0438\u0441\u0438: that.log()     that              \/\/ \u043e\u0431\u044a\u0435\u043a\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u043d\u044b\u043c   }  def runTestCycle[FX, DEP, OUT, F[_]](   fixture: FX,    prepare: FX =&gt; DEP,   execute: DEP =&gt; OUT,    check: OUT =&gt; F[Assertion] )(implicit loggedOut: Logged[OUT]): F[Assertion] =   \/\/ \u0412\u043d\u0435\u0434\u0440\u044f\u0435\u043c logged \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 - \u043f\u043e\u0441\u043b\u0435 execute   (prepare andThen execute andThen logged andThen check) (fixture)<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0412\u043e\u0442 \u0442\u0430\u043a\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435\u043c \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0431\u0430\u0437\u044b <strong>\u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0442\u0435\u0441\u0442\u0435<\/strong>. \u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u043e \u0442\u0430\u043a\u0438\u0445 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0438\u0445 \u043b\u0435\u0433\u043a\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u043b\u0435\u0433\u043a\u043e \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043b\u0435\u0433\u043a\u043e \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0441\u0442\u0430\u043d\u0443\u0442 \u043d\u0435 \u043d\u0443\u0436\u043d\u044b.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ti\/2t\/l9\/ti2tl9pk8wkd4hp8pqevf74hdn4.jpeg\"><\/p>\n<p>  <\/p>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043d\u0430\u0448 \u0442\u0435\u0441\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<pre><code class=\"scala\">val fixture: SomeMagicalFixture = ???  \/\/ \u041e\u0431\u044a\u044f\u0432\u043b\u0435\u043d \u0433\u0434\u0435-\u0442\u043e \u0432 \u0434\u0440\u0443\u0433\u043e\u043c \u043c\u0435\u0441\u0442\u0435 def runProductionCode(id: Int): Database =&gt; Double =   (db: Database) =&gt; new SomeProductionLogic(db).calculatePrice(id) def checkResult(expected: Double): Double =&gt; Future[Assertion] =   (result: Double) =&gt; result shouldBe expected  \/\/ \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043d\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 Database \u0441\u043a\u0440\u044b\u0442\u043e \u0432 testInDb \"\u0415\u0441\u043b\u0438 \u0440\u043e\u043b\u044c \u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b\u044f = 'customer'\" in testInDb(   state = fixture,   execute = runProductionCode(id = 1),   check = checkResult(90) )<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0435\u043b\u043e \u0442\u0435\u0441\u0442\u0430 \u0441\u0442\u0430\u043b\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e\u0441\u043b\u043e\u0432\u043d\u044b\u043c, \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0435\u0441\u0442\u0430\u0445, \u0438 \u043c\u044b \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0438\u0433\u0434\u0435 \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043d\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445. \u041e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u043e\u0434\u043d\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430&#8230;<\/p>\n<p>  <\/p>\n<h2 id=\"podgotovka-fikstur\">\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0444\u0438\u043a\u0441\u0442\u0443\u0440<\/h2>\n<p>  <\/p>\n<p>\u0412 \u043a\u043e\u0434\u0435 \u0432\u044b\u0448\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0447\u0442\u043e \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0430 \u0443\u0436\u0435 \u043e\u0442\u043a\u0443\u0434\u0430-\u0442\u043e \u0432\u043e\u0437\u044c\u043c\u0435\u0442\u0441\u044f \u0432 \u0433\u043e\u0442\u043e\u0432\u043e\u043c \u0432\u0438\u0434\u0435 \u0438 \u0435\u0435 \u043b\u0438\u0448\u044c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0435 \u2014 \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u0438\u043d\u0433\u0440\u0435\u0434\u0438\u0435\u043d\u0442 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0442\u0435\u0441\u0442\u043e\u0432, \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u043d\u0435 \u043a\u043e\u0441\u043d\u0443\u0442\u044c\u0441\u044f \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0438\u0445 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c.<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0443 \u043d\u0430\u0448\u0435\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430 \u0435\u0441\u0442\u044c \u0442\u0438\u043f\u0438\u0447\u043d\u0430\u044f \u0411\u0414 \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430 (\u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0441 4 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c\u0438, \u043d\u043e \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0438\u0445 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0441\u043e\u0442\u043d\u0438). \u0427\u0430\u0441\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u0447\u0430\u0441\u0442\u044c \u2014\u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0431\u0438\u0437\u043d\u0435\u0441\u043e\u0432\u0443\u044e, \u0438 \u0432\u0441\u0435 \u0432\u043c\u0435\u0441\u0442\u0435 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0445 \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439. \u0422\u0430\u0431\u043b\u0438\u0446\u044b \u0441\u0432\u044f\u0437\u0430\u043d\u044b \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 (<em>foreign keys<\/em>) \u2014 \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c <code>Bonus<\/code>, \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c <code>Package<\/code>, \u0430 \u0435\u0439 \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u2014 <code>User<\/code>. \u0418 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/3z\/of\/sy\/3zofsyjoygierusjtmlu_okrmh0.png\"><\/p>\n<p>  <\/p>\n<p>\u041e\u0431\u0445\u043e\u0434\u044b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u0441\u0445\u0435\u043c\u044b \u0438 \u0432\u0441\u044f\u0447\u0435\u0441\u043a\u0438\u0435 \u0445\u0430\u043a\u0438 \u0432\u0435\u0434\u0443\u0442 \u043a \u043d\u0435\u043a\u043e\u043d\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u0438 \u0438, \u043a\u0430\u043a \u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0435, \u043a \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0447\u0430\u0441\u0430\u043c \u0443\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u0435\u0431\u0430\u0433\u0430. \u041f\u043e \u044d\u0442\u043e\u0439 \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0431\u0430\u0437\u0443 \u043f\u043e-\u0447\u0435\u0441\u0442\u043d\u043e\u043c\u0443.<\/p>\n<p>  <\/p>\n<p>\u041c\u044b \u043c\u043e\u0433\u043b\u0438 \u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u043e\u0435\u0432\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u043d\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f, \u043d\u043e \u0434\u0430\u0436\u0435 \u043f\u0440\u0438 \u043f\u043e\u0432\u0435\u0440\u0445\u043d\u043e\u0441\u0442\u043d\u043e\u043c \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0438\u0438 \u044d\u0442\u043e\u0439 \u0438\u0434\u0435\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432. \u0427\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u043d\u0430 \u0441\u0430\u043c\u0438 \u044d\u0442\u0438 \u043c\u0435\u0442\u043e\u0434\u044b? \u041d\u0443\u0436\u043d\u043e \u043b\u0438 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u044b, \u0435\u0441\u043b\u0438 \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442? \u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u043c\u043f\u043e\u0440\u0442\u043e\u043c \u043a\u0435\u043c-\u0442\u043e \u0435\u0449\u0435)? \u041a\u0430\u043a \u043c\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c, \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u0443\u044e \u043e\u0442 \u043c\u043d\u043e\u0433\u0438\u0445 \u0434\u0440\u0443\u0433\u0438\u0445?<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041d\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0431\u0430\u0437\u044b \u0432 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u043c \u0442\u0435\u0441\u0442\u0435<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">insertUser(db, id = 1, name = \"test\", role = \"customer\") insertPackage(db, id = 1, name = \"test\", userId = 1, status = \"new\") insertPackageItems(db, id = 1, packageId = 1, name = \"test\", price = 30) insertPackageItems(db, id = 2, packageId = 1, name = \"test\", price = 20) insertPackageItems(db, id = 3, packageId = 1, name = \"test\", price = 40)<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0420\u0430\u0437\u0440\u043e\u0437\u043d\u0435\u043d\u043d\u044b\u0435 \u0445\u0435\u043b\u043f\u0435\u0440-\u043c\u0435\u0442\u043e\u0434\u044b, \u043a\u0430\u043a \u0432 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u2014 \u044d\u0442\u043e \u0442\u0430 \u0436\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430, \u043d\u043e \u043f\u043e\u0434 \u0434\u0440\u0443\u0433\u0438\u043c \u0441\u043e\u0443\u0441\u043e\u043c. \u041e\u043d\u0438 \u0432\u043e\u0437\u043b\u0430\u0433\u0430\u044e\u0442 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u043c\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438 \u0438 \u0438\u0445 \u0441\u0432\u044f\u0437\u044f\u043c\u0438 \u043d\u0430 \u043d\u0430\u0441 \u0441\u0430\u043c\u0438\u0445, \u0430 \u043d\u0430\u043c \u0431\u044b \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u044d\u0442\u043e\u0433\u043e \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c.<\/p>\n<p>  <\/p>\n<p>\u0412 \u0438\u0434\u0435\u0430\u043b\u0435, \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u0434\u043d\u043e\u0433\u043e \u0432\u0437\u0433\u043b\u044f\u0434\u0430 \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0432 \u043e\u0431\u0449\u0438\u0445 \u0447\u0435\u0440\u0442\u0430\u0445 \u043f\u043e\u043d\u044f\u0442\u044c, \u0432 \u043a\u0430\u043a\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0442\u0435\u0441\u0442\u0430. \u041e\u0434\u043d\u0438\u043c \u0438\u0437 \u043d\u0435\u043f\u043b\u043e\u0445\u0438\u0445 \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u043e\u0432 \u0434\u043b\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u0430 (\u0430-\u043b\u044f <em>\u0434\u0430\u0442\u0430\u0441\u0435\u0442\u044b<\/em> \u0432 PHP \u0438 Python), \u0433\u0434\u0435 \u043d\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u043b\u0438\u0448\u043d\u0435\u0433\u043e, \u043a\u0440\u043e\u043c\u0435 \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u044b\u0445 \u0434\u043b\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438 \u043f\u043e\u043b\u0435\u0439. \u0415\u0441\u043b\u0438 \u0432 \u0444\u0438\u0447\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0441\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430, \u0432\u0441\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u0441\u0432\u0435\u0434\u0435\u0442\u0441\u044f \u043a \u0430\u043a\u0442\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044f\u0447\u0435\u0435\u043a \u0432 \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0435. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<p>  <\/p>\n<pre><code class=\"scala\">val dataTable: Seq[DataRow] = Table(   (\"Package ID\", \"Customer's role\", \"Item prices\", \"Bonus value\", \"Expected final price\")   , (1, \"customer\", Vector(40, 20, 30)           , Vector.empty      ,  90.0)   , (2, \"customer\", Vector(250)                  , Vector.empty      , 225.0)   , (3, \"customer\", Vector(100, 120, 30)         , Vector(40)        , 210.0)   , (4, \"customer\", Vector(100, 120, 30, 100)    , Vector(20, 20)    , 279.0)   , (5, \"vip\"     , Vector(100, 120, 30, 100, 50), Vector(10, 20, 10), 252.0) )<\/code><\/pre>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/5j\/dt\/2p\/5jdt2pdn7hdzhepaut_bhukkcgm.jpeg\"><\/p>\n<p>  <\/p>\n<p>\u0418\u0437 \u043d\u0430\u0448\u0435\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u043c\u044b \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c <em>\u043a\u043b\u044e\u0447\u0438<\/em> \u2014 \u0441\u0432\u044f\u0437\u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u043e ID. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c, \u0435\u0441\u043b\u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0434\u0440\u0443\u0433\u043e\u0439, \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043a\u043b\u044e\u0447 \u0438 \u0434\u043b\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438. \u041c\u043e\u0436\u0435\u0442 \u0441\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0442\u0430\u043a, \u0447\u0442\u043e \u0434\u0432\u0435 \u0440\u0430\u0437\u043d\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e\u0442 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0441 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u0438\u044e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u043f\u043e \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u043e\u043c\u0443 \u043a\u043b\u044e\u0447\u0443 \u0411\u0414 (<em>primary key<\/em>). \u041d\u043e \u043d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u043e \u0434\u0435\u0448\u0435\u0432\u043e \u0434\u0435\u0434\u0443\u043f\u043b\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u2014 \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043a\u043b\u044e\u0447\u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043b\u043e\u0436\u0438\u0442\u044c \u0438\u0445 \u0432 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044e\u0449\u0443\u044e \u0434\u0435\u0434\u0443\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u044e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0432 <code>Set<\/code>. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e\u0433\u043e \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e, \u043c\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0443\u043c\u043d\u0443\u044e \u0434\u0435\u0434\u0443\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u044e \u0432 \u0432\u0438\u0434\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0441\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430.<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u043b\u044e\u0447\u0435\u0439<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">sealed trait Key case class PackageKey(id: Int, userId: Int) extends Key case class PackageItemKey(id: Int, packageId: Int) extends Key case class UserKey(id: Int) extends Key case class BonusKey(id: Int, packageId: Int) extends Key<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0444\u0435\u0439\u043a\u043e\u0432\u043e\u0433\u043e \u043d\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u0435\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u043c\u0435\u043d) \u043c\u044b \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u0443\u0435\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c\u0443 \u043a\u043b\u0430\u0441\u0441\u0443. \u0417\u0430\u0442\u0435\u043c, \u043f\u0440\u0438\u0431\u0435\u0433\u0430\u044f \u043a \u043f\u043e\u043c\u043e\u0449\u0438 \u044d\u0442\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u0438 \u043f\u0440\u0430\u0432\u0438\u043b \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u043a\u043b\u044e\u0447\u0435\u0439, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u044b-\u0441\u0442\u0440\u043e\u043a\u0438, \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0435 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0432 \u0431\u0430\u0437\u0443.<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u0438\u043c\u0435\u0440 \u0441\u0442\u0440\u043e\u043a<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">object SampleData {   def name: String = \"test name\"   def role: String = \"customer\"   def price: Int = 1000   def bonusAmount: Int = 0   def status: String = \"new\" }  sealed trait Row case class PackageRow(id: Int, name: String, userId: Int, status: String) extends Row case class PackageItemRow(id: Int, packageId: Int, name: String, price: Int) extends Row case class UserRow(id: Int, name: String, role: String) extends Row case class BonusRow(id: Int, packageId: Int, bonusAmount: Int) extends Row<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0414\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0445 \u0444\u0435\u0439\u043a\u043e\u0432\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043d\u0430\u043c \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u044f. \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f <a href=\"https:\/\/github.com\/softwaremill\/quicklens\"><em>\u043b\u0438\u043d\u0437\u0430\u043c\u0438<\/em><\/a> \u2014 \u043f\u0440\u043e\u0431\u0435\u0433\u0430\u0442\u044c \u043f\u043e \u0432\u0441\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u043c \u0441\u0442\u0440\u043e\u043a\u0430\u043c \u0438 \u043c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u043b\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0443\u0436\u043d\u043e. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043b\u0438\u043d\u0437\u044b \u0432 \u0438\u0442\u043e\u0433\u0435 \u2014 \u044d\u0442\u043e \u043e\u0431\u044b\u0447\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0438 \u0432 \u044d\u0442\u043e\u043c \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0438\u0445 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0441\u0442\u044c.<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u0438\u043c\u0435\u0440 \u043b\u0438\u043d\u0437\u044b<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">def changeUserRole(userId: Int, newRole: String): Set[Row] =&gt; Set[Row] =   (rows: Set[Row]) =&gt;      rows.modifyAll(_.each.when[UserRow])       .using(r =&gt; if (r.id == userId) r.modify(_.role).setTo(newRole) else r)<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438, \u0432\u043d\u0443\u0442\u0440\u0438 \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f \u2014 \u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0441\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u043e \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u0445 \u043e\u0434\u043d\u0438\u043c <code>insert<\/code>\u2019\u043e\u043c, \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u044f \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432, \u0438\u043b\u0438 \u0437\u0430\u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0411\u0414 \u0434\u043b\u044f \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u044f \u043e\u0442\u043b\u043e\u0432\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c.<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">def makeFixture[STATE, FX, ROW, F[_]](   state: STATE,   applyOverrides: F[ROW] =&gt; F[ROW] = x =&gt; x ): FX =   (extractKeys andThen     deduplicateKeys andThen     enrichWithSampleData andThen     applyOverrides andThen     logged andThen     buildFixture) (state)<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0412\u0441\u0435 \u0432\u043c\u0435\u0441\u0442\u0435 \u0434\u0430\u0441\u0442 \u043d\u0430\u043c \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0430\u043f\u043e\u043b\u043d\u0438\u0442 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u2014 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445. \u0412 \u0441\u0430\u043c\u043e\u043c \u0442\u0435\u0441\u0442\u0435 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u0438\u0434\u043d\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u043b\u0438\u0448\u043d\u0435\u0433\u043e, \u043a\u0440\u043e\u043c\u0435 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0430 \u2014 \u0432\u0441\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u043a\u0440\u044b\u0442\u044b \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0439.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/b3\/wz\/cq\/b3wzcqmqj3gomn-s-zycrakuegy.jpeg\"><\/p>\n<p>  <\/p>\n<p>\u041d\u0430\u0448 \u0442\u0435\u0441\u0442-\u0441\u044c\u044e\u0442 \u0442\u0435\u043f\u0435\u0440\u044c \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<pre><code class=\"scala\">val dataTable: Seq[DataRow] = Table(   (\"Package ID\", \"Customer's role\", \"Item prices\", \"Bonus value\", \"Expected final price\")   , (1, \"customer\", Vector(40, 20, 30)           , Vector.empty      ,  90.0)   , (2, \"customer\", Vector(250)                  , Vector.empty      , 225.0)   , (3, \"customer\", Vector(100, 120, 30)         , Vector(40)        , 210.0)   , (4, \"customer\", Vector(100, 120, 30, 100)    , Vector(20, 20)    , 279.0)   , (5, \"vip\"     , Vector(100, 120, 30, 100, 50), Vector(10, 20, 10), 252.0) )  \"\u0415\u0441\u043b\u0438 \u0440\u043e\u043b\u044c \u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b\u044f -\" - {   \"'customer'\" - {     \"\u0418 \u043e\u0431\u0449\u0430\u044f \u0441\u0443\u043c\u043c\u0430 \u043f\u043e\u043a\u0443\u043f\u043a\u0438\" - {       \"&lt; 250 \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0447\u0435\u0442\u0430 \u0431\u043e\u043d\u0443\u0441\u043e\u0432 - \u043d\u0435\u0442 \u0441\u043a\u0438\u0434\u043a\u0438\" - {         \"(\u043a\u0435\u0439\u0441: \u043d\u0435\u0442 \u0431\u043e\u043d\u0443\u0441\u043e\u0432)\" in calculatePriceFor(dataTable, 1)         \"(\u043a\u0435\u0439\u0441: \u0435\u0441\u0442\u044c \u0431\u043e\u043d\u0443\u0441\u044b)\" in calculatePriceFor(dataTable, 3)       }       \"&gt;= 250 \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0447\u0435\u0442\u0430 \u0431\u043e\u043d\u0443\u0441\u043e\u0432\" - {         \"\u0415\u0441\u043b\u0438 \u043d\u0435\u0442 \u0431\u043e\u043d\u0443\u0441\u043e\u0432 - \u0441\u043a\u0438\u0434\u043a\u0430 10% \u043e\u0442 \u0441\u0443\u043c\u043c\u044b\" in           calculatePriceFor(dataTable, 2)         \"\u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0431\u043e\u043d\u0443\u0441\u044b - \u0441\u043a\u0438\u0434\u043a\u0430 10% \u043e\u0442 \u0441\u0443\u043c\u043c\u044b \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0447\u0435\u0442\u0430 \u0431\u043e\u043d\u0443\u0441\u043e\u0432\" in           calculatePriceFor(dataTable, 4)       }     }   }   \"'vip' - \u0442\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u043a\u0438\u0434\u043a\u0430 20% \u043a \u0441\u0443\u043c\u043c\u0435 \u043f\u043e\u043a\u0443\u043f\u043a\u0438 \u0434\u043e \u0432\u044b\u0447\u0435\u0442\u0430 \u0431\u043e\u043d\u0443\u0441\u043e\u0432, \u0430 \u043f\u043e\u0442\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u043a\u0438\u0434\u043e\u0447\u043d\u044b\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430\" in     calculatePriceFor(dataTable, 5) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0410 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u0434:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">\/\/ \u041f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0442\u0435\u043b\u043e \u0442\u0435\u0441\u0442\u0430 def calculatePriceFor(table: Seq[DataRow], idx: Int) =   testInDb(     state = makeState(table.row(idx)),     execute = runProductionCode(table.row(idx)._1),     check = checkResult(table.row(idx)._5)   ) def makeState(row: DataRow): Logger =&gt; DbFixture = {   val items: Map[Int, Int] = ((1 to row._3.length) zip row._3).toMap   val bonuses: Map[Int, Int] = ((1 to row._4.length) zip row._4).toMap   MyFixtures.makeFixture(     state = PackageRelationships       .minimal(id = row._1, userId = 1)       .withItems(items.keys)       .withBonuses(bonuses.keys),     overrides = changeRole(userId = 1, newRole = row._2) andThen       items.map { case (id, newPrice) =&gt; changePrice(id, newPrice) }.foldPls andThen       bonuses.map { case (id, newBonus) =&gt; changeBonus(id, newBonus) }.foldPls   ) } def runProductionCode(id: Int): Database =&gt; Double =   (db: Database) =&gt; new SomeProductionLogic(db).calculatePrice(id) def checkResult(expected: Double): Double =&gt; Future[Assertion] =   (result: Double) =&gt; result shouldBe expected <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 \u0442\u0435\u0441\u0442-\u043a\u0435\u0439\u0441\u043e\u0432 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435\u0439, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 <strong>\u043f\u043e\u043a\u0440\u044b\u0442\u0438\u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0447\u0438\u0441\u043b\u0430 \u0433\u0440\u0430\u043d\u0438\u0447\u043d\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u0439<\/strong>, \u0430 \u043d\u0435 \u043d\u0430 \u0431\u043e\u0439\u043b\u0435\u0440\u043f\u043b\u0435\u0439\u0442\u0435.<\/p>\n<p>  <\/p>\n<h2 id=\"pereispolzovanie-koda-podgotovki-fikstur-na-drugih-proektah\">\u041f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u0444\u0438\u043a\u0441\u0442\u0443\u0440 \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445<\/h2>\n<p>  <\/p>\n<p>\u0425\u043e\u0440\u043e\u0448\u043e, \u043c\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0434\u043b\u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u0444\u0438\u043a\u0441\u0442\u0443\u0440 \u0432 \u043e\u0434\u043d\u043e\u043c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435, \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u0432 \u043d\u0430 \u044d\u0442\u043e \u043d\u0435\u043c\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0427\u0442\u043e, \u0435\u0441\u043b\u0438 \u0443 \u043d\u0430\u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432? \u041e\u0431\u0440\u0435\u0447\u0435\u043d\u044b \u043b\u0438 \u043c\u044b \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043f\u0435\u0440\u0435\u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0430\u0442\u044c \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434 \u0438 \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u0438\u0442\u044c?<\/p>\n<p>  <\/p>\n<p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0443 \u0444\u0438\u043a\u0441\u0442\u0443\u0440 \u043e\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438. \u0412 \u043c\u0438\u0440\u0435 \u0424\u041f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044f <em>\u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u0430<\/em> (<em>typeclass<\/em>). \u0415\u0441\u043b\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e, \u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u044b \u2014 \u044d\u0442\u043e \u043d\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0438\u0437 \u041e\u041e\u041f, \u0430 \u043d\u0435\u0447\u0442\u043e \u0432\u0440\u043e\u0434\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432, \u043e\u043d\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442 \u043d\u0435\u043a\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0433\u0440\u0443\u043f\u043f\u044b \u0442\u0438\u043f\u043e\u0432. \u041f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u0435 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u044d\u0442\u0430 \u0433\u0440\u0443\u043f\u043f\u0430 \u0442\u0438\u043f\u043e\u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0435 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438, \u0430 \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c, \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435. \u0422\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u0441 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435\u043c, \u0440\u0435\u0437\u043e\u043b\u0432\u0438\u043d\u0433 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u043e\u0432 \u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u043e\u0432 (\u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/docs.scala-lang.org\/tour\/implicit-parameters.html\">\u0438\u043c\u043f\u043b\u0438\u0441\u0438\u0442\u044b<\/a>) \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 <em>\u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438<\/em>, \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438. \u0414\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0432 \u043d\u0430\u0448\u0438\u0445 \u0446\u0435\u043b\u044f\u0445, \u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u044b \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u043a\u0430\u043a <em>\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f<\/em> (<em>extensions<\/em>) \u0438\u0437 <a href=\"https:\/\/kotlinlang.org\/docs\/reference\/extensions.html\">Kotlin<\/a> \u0438 <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/programming-guide\/classes-and-structs\/extension-methods\">C#<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0437\u0430\u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442, \u043d\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c, \u0447\u0442\u043e \u0443 \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432\u043d\u0443\u0442\u0440\u0438, \u043a\u0430\u043a\u0438\u0435 \u0443 \u043d\u0435\u0433\u043e \u043f\u043e\u043b\u044f \u0438 \u043c\u0435\u0442\u043e\u0434\u044b. \u041d\u0430\u043c \u0432\u0430\u0436\u043d\u043e \u043b\u0438\u0448\u044c, \u0447\u0442\u043e\u0431\u044b \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0431\u044b\u043b\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043e \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 <code>log<\/code> \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u043e\u0439. \u0418\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u043a\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <code>Logged<\/code> \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u0431\u044b\u043b\u043e \u0431\u044b \u0442\u0440\u0443\u0434\u043e\u0437\u0430\u0442\u0440\u0430\u0442\u043d\u043e, \u0434\u0430 \u0438 \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u2014 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u0447\u043d\u044b\u0445 \u0438\u043b\u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 \u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438 \u0432\u0441\u0435 \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0449\u0435. \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0430\u043d\u0441 \u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u0430 <code>Logged<\/code>, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, \u0438 \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0435\u0435 \u0432 \u0443\u0434\u043e\u0431\u043e\u0447\u0438\u0442\u0430\u0435\u043c\u043e\u043c \u0432\u0438\u0434\u0435. \u0410 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0430\u043d\u0441 \u0434\u043b\u044f \u0442\u0438\u043f\u0430 <code>Any<\/code> \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 <code>toString<\/code>, \u0447\u0442\u043e\u0431\u044b \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0432 \u0441\u0432\u043e\u0435\u043c \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0438.<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041f\u0440\u0438\u043c\u0435\u0440 \u0442\u0430\u0439\u043a\u043b\u0430\u0441\u0441\u0430 Logged \u0438 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u043e\u0432 \u043a \u043d\u0435\u043c\u0443<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"scala\">trait Logged[A] {   def log(a: A)(implicit logger: Logger): A }  \/\/ \u0414\u043b\u044f \u0432\u0441\u0435\u0445 Future implicit def futureLogged[T]: Logged[Future[T]] = new Logged[Future[T]] {   override def log(futureT: Future[T])(implicit logger: Logger): Future[T] = {     futureT.map { t =&gt;       \/\/ map \u043d\u0430 Future \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u043c\u0435\u0448\u0430\u0442\u044c\u0441\u044f \u0432 \u0435\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043e\u043d\u0430       \/\/ \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f       logger.info(t.toString())       t     }   } }  \/\/ \u0424\u043e\u043b\u043b\u0431\u044d\u043a, \u0435\u0441\u043b\u0438 \u0432 \u0441\u043a\u043e\u0443\u043f\u0435 \u043d\u0435 \u043d\u0430\u0448\u043b\u0438\u0441\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u0438\u043c\u043f\u043b\u0438\u0441\u0438\u0442\u044b implicit def anyNoLogged[T]: Logged[T] = new Logged[T] {   override def log(t: T)(implicit logger: Logger): T = {     logger.info(t.toString())     t   } }<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>\u041a\u0440\u043e\u043c\u0435 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u043d\u0430 \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u0444\u0438\u043a\u0441\u0442\u0443\u0440. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u044b \u0438 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u0443\u044e \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u043d\u0430 \u0438\u0445 \u043e\u0441\u043d\u043e\u0432\u0435. \u041e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0435\u0433\u043e \u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u2014 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u044b \u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0434\u043b\u044f \u0442\u0438\u043f\u043e\u0432.<\/p>\n<p>  <\/p>\n<pre><code class=\"scala\">\/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b def makeFixture[STATE, FX, ROW, F[_]](   state: STATE,   applyOverrides: F[ROW] =&gt; F[ROW] = x =&gt; x ): FX =   (extractKeys andThen     deduplicateKeys andThen     enrichWithSampleData andThen     applyOverrides andThen     logged andThen     buildFixture) (state)  override def extractKeys(implicit toKeys: ToKeys[DbState]): DbState =&gt; Set[Key] =   (db: DbState) =&gt; db.toKeys()  override def enrichWithSampleData(implicit enrich: Enrich[Key]): Key =&gt; Set[Row] =   (key: Key) =&gt; key.enrich()  override def buildFixture(implicit insert: Insertable[Set[Row]]): Set[Row] =&gt; DbFixture =   (rows: Set[Row]) =&gt; rows.insert()  \/\/ \u0422\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u044b, \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0438\u0435 \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u0435 \u0447\u0435\u0433\u043e-\u0442\u043e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0430) \u043d\u0430 \u043a\u043b\u044e\u0447\u0438 trait ToKeys[A] {   def toKeys(a: A): Set[Key]    \/\/ Something =&gt; Set[Key] } \/\/ ...\u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u044e \u043a\u043b\u044e\u0447\u0435\u0439 \u0432 \u0441\u0442\u0440\u043e\u043a\u0438 trait Enrich[A] {   def enrich(a: A): Set[Row]    \/\/ Set[Key] =&gt; Set[Row] } \/\/ ...\u0438 \u0432\u0441\u0442\u0430\u0432\u043a\u0443 \u0441\u0442\u0440\u043e\u043a \u0432 \u0431\u0430\u0437\u0443 trait Insertable[A] {   def insert(a: A): DbFixture   \/\/ Set[Row] =&gt; DbFixture }  \/\/ \u0418\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0435\u043c \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u044b \u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 (\u0441\u043c. \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438) implicit val toKeys: ToKeys[DbState] = ??? implicit val enrich: Enrich[Key] = ??? implicit val insert: Insertable[Set[Row]] = ???<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u0444\u0438\u043a\u0441\u0442\u0443\u0440, \u044f \u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f \u043d\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u043e\u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f SOLID \u043a\u0430\u043a \u043d\u0430 \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0435\u0433\u043e \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u0438 \u0438 \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438 \u043a \u0440\u0430\u0437\u043d\u044b\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u043c:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u041f\u0440\u0438\u043d\u0446\u0438\u043f \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438 (<em>The Single Responsibility Principle<\/em>): \u043a\u0430\u0436\u0434\u044b\u0439 \u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0440\u043e\u0432\u043d\u043e \u043e\u0434\u0438\u043d \u0430\u0441\u043f\u0435\u043a\u0442 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u0430.<\/li>\n<li>\u041f\u0440\u0438\u043d\u0446\u0438\u043f \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u0441\u0442\u0438\/\u0437\u0430\u043a\u0440\u044b\u0442\u043e\u0441\u0442\u0438 (<em>The Open Closed Principle<\/em>): \u043c\u044b \u043d\u0435 \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u043c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0431\u043e\u0435\u0432\u043e\u0439 \u0442\u0438\u043f \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432, \u043c\u044b \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c \u0435\u0433\u043e \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0430\u043c\u0438 \u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u043e\u0432.<\/li>\n<li>\u041f\u0440\u0438\u043d\u0446\u0438\u043f \u043f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u041b\u0438\u0441\u043a\u043e\u0432 (<em>The Liskov Substitution Principle<\/em>) \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435.<\/li>\n<li>\u041f\u0440\u0438\u043d\u0446\u0438\u043f \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 (<em>The Interface Segregation Principle<\/em>): \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u043d\u043e\u0433\u043e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0432\u043c\u0435\u0441\u0442\u043e \u043e\u0434\u043d\u043e\u0433\u043e \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0433\u043e.<\/li>\n<li>\u041f\u0440\u0438\u043d\u0446\u0438\u043f \u0438\u043d\u0432\u0435\u0440\u0441\u0438\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 (<em>The Dependency Inversion Principle<\/em>): \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u0444\u0438\u043a\u0441\u0442\u0443\u0440 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043d\u0435 \u043e\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u0431\u043e\u0435\u0432\u044b\u0445 \u0442\u0438\u043f\u043e\u0432, \u0430 \u043e\u0442 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0445 \u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u043e\u0432.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0423\u0431\u0435\u0434\u0438\u0432\u0448\u0438\u0441\u044c \u0432 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0432\u0441\u0435\u0445 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u043e\u0432, \u043c\u043e\u0436\u043d\u043e \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0442\u044c, \u0447\u0442\u043e \u043d\u0430\u0448\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u043e \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u043c \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445.<\/p>\n<p>  <\/p>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430, \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0444\u0438\u043a\u0441\u0442\u0443\u0440 \u0438 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u043e\u0432 \u0432 \u0444\u0438\u043a\u0441\u0442\u0443\u0440\u044b, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0430\u0431\u0441\u0442\u0440\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0432\u0448\u0438\u0441\u044c \u043e\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043c\u044b, \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u0433\u043e\u0442\u043e\u0432\u044b \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u0432\u0441\u0435 \u0442\u0435\u0441\u0442\u044b.<\/p>\n<p>  <\/p>\n<h2 id=\"itogi\">\u0418\u0442\u043e\u0433\u0438<\/h2>\n<p>  <\/p>\n<p>\u041c\u044b \u043f\u0435\u0440\u0435\u0448\u043b\u0438 \u043e\u0442 \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e (\u043f\u043e\u0448\u0430\u0433\u043e\u0432\u043e\u0433\u043e) \u0441\u0442\u0438\u043b\u044f \u0434\u0438\u0437\u0430\u0439\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u043c\u0443. \u041f\u043e\u0448\u0430\u0433\u043e\u0432\u044b\u0439 \u0441\u0442\u0438\u043b\u044c \u0445\u043e\u0440\u043e\u0448 \u043d\u0430 \u0440\u0430\u043d\u043d\u0438\u0445 \u044d\u0442\u0430\u043f\u0430\u0445 \u0438 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0442\u0435\u043c, \u0447\u0442\u043e \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0442\u0440\u0443\u0434\u043e\u0437\u0430\u0442\u0440\u0430\u0442 \u0438 \u043d\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430, \u043d\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u0442\u0435\u0441\u0442\u043e\u0432 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043c\u043d\u043e\u0433\u043e. \u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0442\u0438\u043b\u044c \u043d\u0435 \u043f\u0440\u0438\u0437\u0432\u0430\u043d \u0440\u0435\u0448\u0438\u0442\u044c \u0432\u0441\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0432 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438, \u043d\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u0442\u044c \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0442\u0435\u0441\u0442\u043e\u0432 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445, \u0433\u0434\u0435 \u0438\u0445 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u0441\u0447\u0438\u0441\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0442\u043d\u044f\u043c\u0438 \u0438\u043b\u0438 \u0442\u044b\u0441\u044f\u0447\u0430\u043c\u0438. \u0422\u0435\u0441\u0442\u044b \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u0435\u0435 \u0438 \u0444\u043e\u043a\u0443\u0441\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043d\u0430 \u0442\u043e\u043c, \u0447\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u0430\u0436\u043d\u043e (\u0434\u0430\u043d\u043d\u044b\u0435, \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u043a\u043e\u0434 \u0438 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442), \u0430 \u043d\u0435 \u043d\u0430 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0445 \u0448\u0430\u0433\u0430\u0445.<\/p>\n<p>  <\/p>\n<p>\u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043d\u0430 \u0436\u0438\u0432\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u0449\u043d\u044b\u043c\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0442\u0430\u0439\u043f\u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438. \u0421 \u0438\u0445 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043b\u0435\u0433\u043a\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u043d\u0435\u043e\u0442\u044a\u0435\u043c\u043b\u0435\u043c\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u043e\u0441\u0442\u044c \u0438 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0441\u0442\u044c.<\/p>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0445\u043e\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u0432\u044b\u043a\u043d\u0443\u0442\u044c \u043a \u043d\u043e\u0432\u044b\u043c \u0442\u0435\u0441\u0442\u0430\u043c, \u043e\u043d\u0430 \u043e\u0441\u0442\u0430\u043b\u0430\u0441\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c. \u041d\u043e\u0432\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u043f\u0438\u0448\u0443\u0442\u0441\u044f \u0431\u044b\u0441\u0442\u0440\u0435\u0435, \u043b\u043e\u0433\u0438 \u0443\u043f\u0440\u043e\u0449\u0430\u044e\u0442 \u0436\u0438\u0437\u043d\u044c, \u0430 \u043a \u0434\u0430\u0442\u0430\u0441\u0435\u0442\u0430\u043c \u0443\u0434\u043e\u0431\u043d\u043e \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0442 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u043f\u043e \u043a\u043e\u0440\u043d\u0435\u0440-\u043a\u0435\u0439\u0441\u0430\u043c. \u041c\u044b \u0441\u0442\u0440\u0435\u043c\u0438\u043c\u0441\u044f \u043a \u0442\u043e\u043c\u0443, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u043f\u0435\u0440\u0435\u0432\u0435\u0441\u0442\u0438 \u0432\u0441\u0435 \u0442\u0435\u0441\u0442\u044b \u043d\u0430 \u043d\u043e\u0432\u044b\u0439 \u0441\u0442\u0438\u043b\u044c. \u041f\u0440\u0438\u044f\u0442\u043d\u043e\u0433\u043e \u0432\u0430\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f!<\/p>\n<p>  <\/p>\n<hr>\n<p>  <\/p>\n<p>\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0438 \u043f\u0440\u0438\u043c\u0435\u0440: <a href=\"https:\/\/github.com\/ThatAnnoyingCatAt4am\/escaping-thicket-of-tests\">Github<\/a><\/p>\n<\/div>\n<p>               <script class=\"js-mediator-script\">!function(e){function t(t,n){if(!(n in e)){for(var r,a=e.document,i=a.scripts,o=i.length;o--;)if(-1!==i[o].src.indexOf(t)){r=i[o];break}if(!r){r=a.createElement(\"script\"),r.type=\"text\/javascript\",r.async=!0,r.defer=!0,r.src=t,r.charset=\"UTF-8\";var d=function(){var e=a.getElementsByTagName(\"script\")[0];e.parentNode.insertBefore(r,e)};\"[object Opera]\"==e.opera?a.addEventListener?a.addEventListener(\"DOMContentLoaded\",d,!1):e.attachEvent(\"onload\",d):d()}}}t(\"\/\/mediator.mail.ru\/script\/2820404\/\",\"_mediator\")}(window);<\/script>     <br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/2gis\/blog\/463623\/\"> https:\/\/habr.com\/ru\/company\/2gis\/blog\/463623\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html js-mediator-article\">\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/mu\/ll\/ar\/mullaroquhqtdb05ygvb82nmghu.jpeg\"><\/p>\n<p>  <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0438\u0442\u044c \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0443 \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u043e\u043c\u0443 \u0441\u0442\u0438\u043b\u044e \u0434\u0438\u0437\u0430\u0439\u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 Scala. \u041f\u043e\u0434\u0445\u043e\u0434 \u0431\u044b\u043b \u043d\u0430\u0432\u0435\u044f\u043d \u043c\u043d\u043e\u0433\u043e\u043c\u0435\u0441\u044f\u0447\u043d\u043e\u0439 \u0431\u043e\u043b\u044c\u044e \u043e\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u0434\u0435\u0441\u044f\u0442\u043a\u043e\u0432 \u0438 \u0441\u043e\u0442\u0435\u043d \u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0445 \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0436\u0433\u0443\u0447\u0438\u043c \u0436\u0435\u043b\u0430\u043d\u0438\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u0445 \u043f\u0440\u043e\u0449\u0435 \u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u0435\u0435.<\/p>\n<p>  <\/p>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043a\u043e\u0434 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 Scala, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u044b\u0435 \u0438\u0434\u0435\u0438 \u0431\u0443\u0434\u0443\u0442 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0449\u0438\u043a\u043e\u0432 \u043d\u0430 \u0432\u0441\u0435\u0445 \u044f\u0437\u044b\u043a\u0430\u0445, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u0445 \u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u0421\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 Github \u0441 \u043f\u043e\u043b\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-293422","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/293422","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=293422"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/293422\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=293422"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=293422"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=293422"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}