{"id":470839,"date":"2025-08-15T15:00:07","date_gmt":"2025-08-15T15:00:07","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=470839"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=470839","title":{"rendered":"<span>\u041c\u0435\u0436\u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0435 (\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043d\u044b\u0435) \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0422\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442, \u043a\u043e\u0433\u0434\u0430 \u043e\u043d\u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u0441\u0430\u043c\u0438\u0445 \u0434\u043e\u043c\u0435\u043d\u043e\u0432<\/p>\n<p>\u042f \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u0441 \u0442\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439:<br \/> \u043b\u043e\u0433\u0438\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 \u0434\u043e\u043c\u0435\u043d\u0430\u043c\u0438 \u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u0441\u0430\u043c\u0438\u0445 \u0434\u043e\u043c\u0435\u043d\u043e\u0432<br \/> \u0430 \u0432 \u043a\u043d\u0438\u0436\u043a\u0430\u0445 \u043e\u0431 \u044d\u0442\u043e\u043c \u043d\u0435 \u043f\u0438\u0448\u0443\u0442<\/p>\n<p>\u042f \u0441\u0442\u0440\u043e\u0438\u043b \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043f\u043e DDD, \u0432\u0441\u0435 \u043a\u0440\u0430\u0441\u0438\u0432\u043e:<\/p>\n<ul>\n<li>\n<p>\u0434\u043e\u043c\u0435\u043d\u044b<\/p>\n<\/li>\n<li>\n<p>\u0430\u0433\u0440\u0435\u0433\u0430\u0442\u044b<\/p>\n<\/li>\n<li>\n<p>use cases<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0431\u044b\u0442\u0438\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0442\u043e\u043c \u043f\u0440\u0438\u0448\u0451\u043b \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439: &#171;\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0437\u0430\u043a\u0430\u0437&#187;<\/p>\n<p>\u042f \u0434\u0443\u043c\u0430\u043b: &#171;\u041d\u0443, Order::cancel(), \u0432\u044b\u0437\u043e\u0432\u0443 inventory.release(), pricing.refund(), \u0438 \u0433\u043e\u0442\u043e\u0432\u043e&#187;<\/p>\n<p>\u041d\u043e, \u0445\u043c\u043c&#8230;<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0430 \u0443\u0436\u0435 \u0432 \u043f\u0443\u0442\u0438 \u2014 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u043d\u0443\u044e \u043d\u0430\u043a\u043b\u0430\u0434\u043d\u0443\u044e<br \/>\u0415\u0441\u043b\u0438 \u043f\u043b\u0430\u0442\u0451\u0436 \u043f\u0430\u0434\u0430\u043b \u0434\u0432\u0430\u0436\u0434\u044b \u2014 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u0441\u0451, \u0430 \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u0439 \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u2014 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043c\u043e\u0440\u043e\u0437\u0438\u0442\u044c \u0431\u0430\u043b\u043b\u044b<br \/>\u0415\u0441\u043b\u0438 \u0442\u043e\u0432\u0430\u0440\u0430 \u043d\u0435\u0442 \u2014 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0440\u0435\u0437\u0435\u0440\u0432 \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u043a\u043b\u0430\u0434, \u043f\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0443, \u0441\u043f\u0440\u043e\u0441\u0438\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u0435\u0441\u043b\u0438 \u0434\u043e\u0440\u043e\u0436\u0435<br \/>\u0415\u0441\u043b\u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u043b \u043f\u043b\u0430\u0442\u0451\u0436 \u2014 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0440\u0435\u0437\u0435\u0440\u0432 \u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0443<\/p>\n<p>\u0418 \u044f \u043f\u043e\u043d\u044f\u043b:<\/p>\n<p>\u0421\u0430\u043c\u0430\u044f \u0441\u043b\u043e\u0436\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u2014 \u043d\u0435 \u0432 \u0434\u043e\u043c\u0435\u043d\u0430\u0445, \u0430 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438. \u0412 \u043a\u043d\u0438\u0436\u043a\u0430\u0445 \u043f\u043e DDD, Clean Architecture, Hexagonal \u2014 \u043e\u0431 \u044d\u0442\u043e\u043c \u043d\u0435 \u043f\u0438\u0448\u0443\u0442. \u0422\u0430\u043c \u0443\u0447\u0430\u0442:<\/p>\n<ul>\n<li>\n<p>&#171;Use case \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0442\u043e\u043d\u043a\u0438\u043c&#187;<\/p>\n<\/li>\n<li>\n<p>&#171;\u0414\u043e\u043c\u0435\u043d \u044d\u0442\u043e \u0446\u0435\u043d\u0442\u0440 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438&#187;<\/p>\n<\/li>\n<li>\n<p>&#171;\u041c\u0435\u0436\u0434\u0443 \u0434\u043e\u043c\u0435\u043d\u0430\u043c\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0438\u043b\u0438 \u0432\u044b\u0437\u043e\u0432\u044b API c JSON (\u0442.\u0435. \u0442\u0438\u043f\u044b \u043d\u0430 \u0433\u0440\u0430\u043d\u0438\u0446\u0435 \u0442\u0435\u0440\u044f\u044e\u0442\u0441\u044f, \u0437\u043d\u0430\u0447\u0438\u0442 \u0431\u0438\u0437\u043d\u0435\u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0433\u0440\u0430\u043d\u0438\u0446\u0443 \u043d\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044f\u0442)&#187; <\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u044f \u043f\u043e\u0439\u0434\u0443 \u043f\u043e \u043a\u043d\u0438\u0436\u043a\u0430\u043c \u0438 \u0432\u043e\u0442\u043a\u043d\u0443 \u044d\u0442\u043e\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0432 \u043e\u0431\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u0438 Order, \u0442\u043e \u0442\u043e\u0442 \u0441\u0442\u0430\u043d\u0435\u0442 &#171;\u0431\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c&#187;<\/p>\n<ul>\n<li>\n<p>\u0417\u0430\u0432\u0438\u0441\u0435\u0442\u044c \u043e\u0442 4 \u0434\u043e\u043c\u0435\u043d\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u0417\u043d\u0430\u0442\u044c \u043f\u0440\u043e \u0441\u0442\u0430\u0442\u0443\u0441 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e retry, hold, freeze<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0440\u0443\u0448\u0430\u0442\u044c SRP<\/p>\n<\/li>\n<li>\n<p>\u0410 \u0437\u0430\u043e\u0434\u043d\u043e \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c anti corruption layer \u0442.\u043a. \u043d\u0430 \u0432\u0445\u043e\u0434 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0439\u0442\u0438 \u0447\u0442\u043e \u0443\u0433\u043e\u0434\u043d\u043e, \u044f \u043b\u0438\u0448\u0430\u044e\u0441\u044c \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0439 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430, \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u043d\u044b\u0445 \u0432 \u0442\u0438\u043f\u0430\u0445<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u043e \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u0433\u043e\u0432\u043e\u0440\u0438\u0442, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0442\u043e?<\/p>\n<p>\u042f \u0432\u0432\u0451\u043b \u0442\u043e, \u0447\u0435\u0433\u043e \u043d\u0435 \u0431\u044b\u043b\u043e \u0432 \u0443\u0447\u0435\u0431\u043d\u0438\u043a\u0430\u0445:<\/p>\n<p><strong>CrossDomainCoordinator<\/strong><\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0430 \u0441\u0435\u0431\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 \u043b\u043e\u0433\u0438\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043b\u0438\u0448\u043d\u0438\u0435, \u0447\u0443\u0436\u0435\u0440\u043e\u0434\u043d\u044b\u0435 \u0434\u043b\u044f \u0431\u0438\u0437\u043d\u0435\u0441 \u0434\u043e\u043c\u0435\u043d\u043e\u0432  <\/p>\n<\/li>\n<li>\n<p>\u0417\u043d\u0430\u0435\u0442, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0434\u043e\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e<\/p>\n<\/li>\n<li>\n<p>\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0430\u043c\u0438: retry, hold, freeze<\/p>\n<\/li>\n<li>\n<p>\u041f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0434\u043b\u044f \u0430\u0443\u0434\u0438\u0442\u0430 <\/p>\n<p><strong>SharedKernel<\/strong><\/p>\n<\/li>\n<li>\n<p>\u0421\u0430\u043c\u0430\u044f \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0434\u043b\u044f \u0432\u0441\u0435\u0445, \u043a\u0430\u043a \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0430 \u041a\u043e\u043c\u043f\u0430\u043d\u0438\u0438<\/p>\n<p>\u0412\u043a\u0440\u0430\u0442\u0446\u0435:<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"rust\">if status == InTransit {     self.delivery.cancel_with_fee(...).await?;     self.delivery.create_return_label(...).await?; }  let (inv, loy) = tokio::join!(     self.inventory.cancel_reservation(...),     self.loyalty.rollback_points(...), );  self.pricing.refund_payment(...).await?; self.event_bus.publish(...).await;  Ok(()) }<\/code><\/pre>\n<p>src\/<br \/> \u251c\u2500\u2500 domain\/<br \/> \u2502   \u251c\u2500\u2500 pricing\/<br \/> \u2502   \u2502   \u2514\u2500\u2500 src\/<a href=\"http:\/\/lib.rs\" rel=\"noopener noreferrer nofollow\">lib.rs<\/a><br \/> \u2502   \u251c\u2500\u2500 inventory\/<br \/> \u2502   \u2502   \u2514\u2500\u2500 src\/<a href=\"http:\/\/lib.rs\" rel=\"noopener noreferrer nofollow\">lib.rs<\/a><br \/> \u2502   \u251c\u2500\u2500 delivery\/<br \/> \u2502   \u2502   \u2514\u2500\u2500 src\/<a href=\"http:\/\/lib.rs\" rel=\"noopener noreferrer nofollow\">lib.rs<\/a><br \/> \u2502   \u2514\u2500\u2500 loyalty\/<br \/> \u2502       \u2514\u2500\u2500 src\/<a href=\"http:\/\/lib.rs\" rel=\"noopener noreferrer nofollow\">lib.rs<\/a><br \/> \u251c\u2500\u2500 application\/<br \/> \u2502   \u251c\u2500\u2500 coordination\/<br \/> \u2502   \u2502   \u251c\u2500\u2500 <a href=\"http:\/\/mod.rs\" rel=\"noopener noreferrer nofollow\">mod.rs<\/a><br \/> \u2502   \u2502   \u251c\u2500\u2500 <a href=\"http:\/\/handlers.rs\" rel=\"noopener noreferrer nofollow\">handlers.rs<\/a><br \/> \u2502   \u2502   \u2514\u2500\u2500 <a href=\"http:\/\/events.rs\" rel=\"noopener noreferrer nofollow\">events.rs<\/a><br \/> \u2502   \u2514\u2500\u2500 use_cases\/<br \/> \u2502       \u251c\u2500\u2500 create_<a href=\"http:\/\/order.rs\" rel=\"noopener noreferrer nofollow\">order.rs<\/a><br \/> \u2502       \u251c\u2500\u2500 cancel_<a href=\"http:\/\/order.rs\" rel=\"noopener noreferrer nofollow\">order.rs<\/a><br \/> \u2502       \u251c\u2500\u2500 confirm_order_<a href=\"http:\/\/payment.rs\" rel=\"noopener noreferrer nofollow\">payment.rs<\/a><br \/> \u2502       \u2514\u2500\u2500 retry_<a href=\"http:\/\/payment.rs\" rel=\"noopener noreferrer nofollow\">payment.rs<\/a><br \/> \u251c\u2500\u2500 infrastructure\/<br \/> \u2502   \u251c\u2500\u2500 web\/<br \/> \u2502   \u2502   \u251c\u2500\u2500 <a href=\"http:\/\/handlers.rs\" rel=\"noopener noreferrer nofollow\">handlers.rs<\/a><br \/> \u2502   \u2502   \u251c\u2500\u2500 <a href=\"http:\/\/routes.rs\" rel=\"noopener noreferrer nofollow\">routes.rs<\/a><br \/> \u2502   \u2502   \u2514\u2500\u2500 <a href=\"http:\/\/state.rs\" rel=\"noopener noreferrer nofollow\">state.rs<\/a><br \/> \u2502   \u251c\u2500\u2500 adapters\/<br \/> \u2502   \u2502   \u251c\u2500\u2500 mock_*.rs<br \/> \u2502   \u2502   \u2514\u2500\u2500 in_memory_<a href=\"http:\/\/repository.rs\" rel=\"noopener noreferrer nofollow\">repository.rs<\/a><br \/> \u2502   \u2514\u2500\u2500 persistence\/<br \/> \u2502       \u251c\u2500\u2500 <a href=\"http:\/\/mod.rs\" rel=\"noopener noreferrer nofollow\">mod.rs<\/a><br \/> \u2502       \u251c\u2500\u2500 order_<a href=\"http:\/\/repository.rs\" rel=\"noopener noreferrer nofollow\">repository.rs<\/a><br \/> \u2502       \u2514\u2500\u2500 schema.sql<br \/> \u2514\u2500\u2500 shared\/<a href=\"http:\/\/lib.rs\" rel=\"noopener noreferrer nofollow\">lib.rs<\/a><\/p>\n<p>\u0412 \u043a\u043e\u0434\u0435 \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e:<\/p>\n<ul>\n<li>\n<p>\u0434\u043e\u043c\u0435\u043d\u044b \u043f\u0440\u043e\u0441\u0442\u044b\u0435, \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445, \u0447\u0435\u043c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f (\u043b\u043e\u0433\u0438\u043a\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0432 \u0442\u0438\u043f\u0430\u0445), \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0447\u0438\u0441\u0442\u044b\u043c\u0438: inventory, delivery, loyalty \u2014 \u043d\u0435 \u0437\u043d\u0430\u044e\u0442 \u0434\u0440\u0443\u0433 \u043e \u0434\u0440\u0443\u0433\u0435<\/p>\n<\/li>\n<li>\n<p>\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440 \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0447\u0442\u0438 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0438\u0437 \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 (\u043f\u0440\u0430\u0432\u0438\u043b) \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f, \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u0432\u043d\u0443\u0442\u0440\u0438, \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u043c\u0435\u0441\u0442\u043e, \u0433\u0434\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u0437\u0430\u0432\u0438\u0441\u044f\u0449\u0438\u0435 \u043e\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0434\u043e\u043c\u0435\u043d\u043e\u0432<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u044f \u0441\u0445\u0430\u043b\u044f\u0432\u0438\u043b \u0438 \u043d\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0434\u043b\u044f \u0434\u043e\u043c\u0435\u043d\u043e\u0432 \u043b\u043e\u0433\u0438\u043a\u0443, \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0438. \u041d\u0443, \u0438 \u0442\u0430\u043a \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u0447\u0442\u043e \u043e\u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f. <\/p>\n<p><strong>\u0412\u044b\u0432\u043e\u0434<\/strong><br \/>\u0415\u0441\u043b\u0438 \u043b\u043e\u0433\u0438\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 \u0434\u043e\u043c\u0435\u043d\u0430\u043c\u0438 \u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u0441\u0430\u043c\u0438\u0445 \u0434\u043e\u043c\u0435\u043d\u043e\u0432 &#8212; \u0432\u044b\u0434\u0435\u043b\u0438 \u0435\u0451 \u044f\u0432\u043d\u043e CrossDomainCoordinator &#8212; \u043a\u0430\u043a \u0434\u043e\u043c\u0435\u043d, \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u0435\u0437 \u0441\u0432\u043e\u0438\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439. \u0414\u043b\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0434\u043e\u043c\u0435\u043d\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5fb\/251\/c87\/5fb251c876e9e8a28c8f5099466dfc3a.png\" alt=\"\u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043d\u0430 Rust, \" title=\"\u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043d\u0430 Rust, \" width=\"862\" height=\"496\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/5fb\/251\/c87\/5fb251c876e9e8a28c8f5099466dfc3a.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5fb\/251\/c87\/5fb251c876e9e8a28c8f5099466dfc3a.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043d\u0430 Rust, <\/figcaption><\/div>\n<\/figure>\n<details class=\"spoiler\">\n<summary>\u0432\u0441\u0435\u0433\u043e-\u0442\u043e 700+ \u0441\u0442\u0440\u043e\u043a \u0443\u0447\u0435\u0431\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">\/\/! # Shared Kernel \/\/! \/\/! \u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435, \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u044f\u0434\u0440\u043e. \/\/! \/\/! ## \u041f\u0440\u0430\u0432\u0438\u043b\u0430: \/\/! - \u0422\u043e\u043b\u044c\u043a\u043e \u0444\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \/\/! - \u041d\u0438\u043a\u0430\u043a\u0438\u0445 enum \u0441 \u0431\u0438\u0437\u043d\u0435\u0441-\u0441\u0435\u043c\u0430\u043d\u0442\u0438\u043a\u043e\u0439 (Carrier, RefundReason \u0438 \u0442.\u0434.) \/\/! - \u041d\u0438\u043a\u0430\u043a\u0438\u0445 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u044b\u0445 \u043f\u043e\u043b\u0438\u0442\u0438\u043a \/\/! \/\/! ## \u041f\u043e\u0447\u0435\u043c\u0443: \/\/! \u042d\u0442\u043e shared kernel \u043f\u043e DDD. \u041b\u044e\u0431\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0437\u0434\u0435\u0441\u044c \u0437\u0430\u0442\u0440\u0430\u0433\u0438\u0432\u0430\u0435\u0442 \u0432\u0441\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443. \/\/! \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043a\u0430\u043a \"\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\" \u2014 \u043f\u043e\u0447\u0442\u0438 \u043d\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f.  use rust_decimal::Decimal; use uuid::Uuid;  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 pub type CustomerId = Uuid; pub type ProductId = Uuid; pub type OrderId = Uuid; pub type WarehouseId = Uuid; pub type ReservationId = Uuid; pub type DeliveryId = Uuid; pub type RefundId = Uuid; pub type FreezeId = Uuid;  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u0414\u0435\u043d\u0435\u0436\u043d\u044b\u0435 \u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 pub type Money = Decimal; pub type Quantity = u32; pub type Weight = f32;  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u041e\u0431\u0449\u0438\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct Address {     pub street: String,     pub city: String,     pub zip: String,     pub country: String, } ```  ---  ###  `src\/domain\/pricing\/src\/lib.rs`  ```rust \/\/! # Pricing Domain \/\/! \/\/! \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0430\u0441\u0447\u0451\u0442\u043e\u043c \u0446\u0435\u043d, \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u043e\u0439 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u043e\u043c \u0441\u0440\u0435\u0434\u0441\u0442\u0432. \/\/! \/\/! ## \u0417\u0430\u0432\u0438\u0441\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442 `shared\/` \/\/! - `Money`, `OrderId`, `CustomerId` \/\/! \/\/! ## \u041d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u0434\u043e\u043c\u0435\u043d\u043e\u0432  use crate::shared::{CustomerId, ProductId, OrderId, Money, Quantity}; use uuid::Uuid;  #[derive(Debug, Clone)] pub struct PriceRequest {     pub customer_id: CustomerId,     pub items: Vec&lt;(ProductId, Quantity)&gt;,     pub promo_code: Option&lt;String&gt;,     pub loyalty_discount: Option&lt;Money&gt;, }  #[derive(Debug, Clone, serde::Serialize)] pub struct PriceBreakdown {     pub base: Money,     pub discount: Money,     pub tax: Money,     pub final_price: Money, }  #[derive(Debug, Clone)] pub struct RefundRequest {     pub order_id: OrderId,     pub amount: Money,     pub reason: RefundReason, }  #[derive(Debug, Clone, PartialEq)] pub enum RefundReason {     CustomerCancelled,     Fraudulent,     SystemError, }  pub type PaymentHoldId = Uuid;  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 pub fn calculate_prices(request: PriceRequest) -&gt; PriceBreakdown {     \/\/ \u0423\u043f\u0440\u043e\u0449\u0451\u043d\u043d\u044b\u0439 \u0440\u0430\u0441\u0447\u0451\u0442     let base: Money = request.items.iter().map(|(_, q)| Money::from(*q)).sum();     let discount = request.loyalty_discount.unwrap_or(Money::zero());     let tax = base * rust_decimal_macros::dec!(0.1);     let final_price = base - discount + tax;      PriceBreakdown {         base,         discount,         tax,         final_price,     } }  pub fn refund_payment(request: RefundRequest) -&gt; Result&lt;RefundId, PricingError&gt; {     \/\/ \u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 \u043f\u043b\u0430\u0442\u0451\u0436\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439     Ok(Uuid::new_v4()) }  pub fn hold_payment(customer_id: CustomerId, amount: Money) -&gt; Result&lt;PaymentHoldId, PricingError&gt; {     Ok(Uuid::new_v4()) }  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u041e\u0448\u0438\u0431\u043a\u0438 \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 #[derive(Debug, thiserror::Error)] pub enum PricingError {     #[error(\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043b\u0430\u0442\u0435\u0436\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b\")]     PaymentSystemError,     #[error(\"\u0421\u0443\u043c\u043c\u0430 \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f\")]     NegativeAmount, } ```  ---  ###  `src\/domain\/inventory\/src\/lib.rs`  ```rust \/\/! # Inventory Domain \/\/! \/\/! \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u0437\u0435\u0440\u0432\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c, \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u043e\u0439 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u0438 \u0438 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u043e\u043c \u0442\u043e\u0432\u0430\u0440\u0430.  use crate::shared::{ProductId, Quantity, WarehouseId, ReservationId, Money, Address}; use uuid::Uuid;  #[derive(Debug, Clone)] pub struct ReserveRequest {     pub items: Vec&lt;(ProductId, Quantity)&gt;,     pub warehouse_id: WarehouseId,     pub priority: Priority, }  #[derive(Debug, Clone, serde::Serialize)] pub struct ItemAvailability {     pub product_id: ProductId,     pub available: Quantity,     pub warehouse_id: WarehouseId, }  #[derive(Debug, Clone)] pub struct TransferRequest {     pub reservation_id: ReservationId,     pub from: WarehouseId,     pub to: WarehouseId, }  #[derive(Debug, Clone, PartialEq)] pub enum Priority {     Low,     Normal,     High, }  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 pub fn check_availability(items: Vec&lt;(ProductId, Quantity)&gt;) -&gt; Vec&lt;ItemAvailability&gt; {     items.into_iter()         .map(|(id, _)| ItemAvailability {             product_id: id,             available: 10, \/\/ \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u0435             warehouse_id: Uuid::new_v4().into(),         })         .collect() }  pub fn reserve(request: ReserveRequest) -&gt; Result&lt;ReservationId, InventoryError&gt; {     Ok(Uuid::new_v4()) }  pub fn cancel_reservation(reservation_id: ReservationId) -&gt; Result&lt;Vec&lt;(ProductId, Quantity)&gt;, InventoryError&gt; {     Ok(vec![(Uuid::new_v4(), 2)]) }  pub fn transfer_reservation(request: TransferRequest) -&gt; Result&lt;(), InventoryError&gt; {     Ok(()) }  pub fn confirm_reservation(reservation_id: ReservationId) -&gt; Result&lt;(), InventoryError&gt; {     Ok(()) }  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u041e\u0448\u0438\u0431\u043a\u0438 \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 #[derive(Debug, thiserror::Error)] pub enum InventoryError {     #[error(\"\u0422\u043e\u0432\u0430\u0440 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\")]     NotFound,     #[error(\"\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043d\u0430 \u0441\u043a\u043b\u0430\u0434\u0435\")]     OutOfStock, } ```  ---  ###  `src\/domain\/delivery\/src\/lib.rs`  ```rust \/\/! # Delivery Domain \/\/! \/\/! \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u043e\u0439, \u0440\u0430\u0441\u0447\u0451\u0442\u043e\u043c, \u043e\u0442\u043c\u0435\u043d\u043e\u0439, \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u043e\u043c.  use crate::shared::{Address, Weight, Money, DeliveryId, ReservationId, OrderId, WarehouseId, CustomerId}; use uuid::Uuid; use time::OffsetDateTime;  #[derive(Debug, Clone)] pub struct DeliveryRequest {     pub address: Address,     pub items: Vec&lt;(ProductId, Weight)&gt;,     pub priority: Priority, }  #[derive(Debug, Clone, serde::Serialize)] pub struct ShippingOptions {     pub cost: Money,     pub warehouse_id: WarehouseId,     pub estimated_days: u32,     pub carrier: Carrier, }  #[derive(Debug, Clone, serde::Serialize)] pub struct CancellationFee {     pub amount: Money,     pub reason: String, }  #[derive(Debug, Clone, serde::Serialize)] pub struct ReturnLabel {     pub tracking_number: String,     pub carrier: Carrier,     pub expires_at: OffsetDateTime, }  #[derive(Debug, Clone, PartialEq)] pub enum Carrier {     DHL,     FedEx,     UPS, }  #[derive(Debug, Clone, PartialEq)] pub enum Priority {     Low,     Normal,     High, }  #[derive(Debug, Clone, PartialEq)] pub enum DeliveryStatus {     Pending,     InTransit,     Delivered, }  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 pub fn calculate_shipping(request: DeliveryRequest) -&gt; Result&lt;ShippingOptions, DeliveryError&gt; {     Ok(ShippingOptions {         cost: rust_decimal_macros::dec!(10.00),         warehouse_id: Uuid::new_v4(),         estimated_days: 3,         carrier: Carrier::DHL,     }) }  pub fn schedule_delivery(order_id: OrderId, option: ShippingOptions) -&gt; Result&lt;DeliveryId, DeliveryError&gt; {     Ok(Uuid::new_v4()) }  pub fn cancel_delivery(delivery_id: DeliveryId) -&gt; Result&lt;CancellationFee, DeliveryError&gt; {     Ok(CancellationFee {         amount: rust_decimal_macros::dec!(5.00),         reason: \"Early cancellation fee\".to_string(),     }) }  pub fn create_return_label(delivery_id: DeliveryId) -&gt; Result&lt;ReturnLabel, DeliveryError&gt; {     Ok(ReturnLabel {         tracking_number: \"RTN123456789\".to_string(),         carrier: Carrier::DHL,         expires_at: OffsetDateTime::now_utc() + time::Duration::days(7),     }) }  pub fn get_status(delivery_id: DeliveryId) -&gt; Result&lt;DeliveryStatus, DeliveryError&gt; {     Ok(DeliveryStatus::Pending) }  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u041e\u0448\u0438\u0431\u043a\u0438 \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 #[derive(Debug, thiserror::Error)] pub enum DeliveryError {     #[error(\"\u0414\u043e\u0441\u0442\u0430\u0432\u043a\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u0430\")]     NotFound,     #[error(\"\u041d\u0435\u043b\u044c\u0437\u044f \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u0437\u0430\u043a\u0430\u0437\")]     CannotCancelDelivered, } ```  ---  ###  `src\/domain\/loyalty\/src\/lib.rs`  ```rust \/\/! # Loyalty Domain \/\/! \/\/! \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435\u043c, \u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c, \u0437\u0430\u043c\u043e\u0440\u043e\u0437\u043a\u043e\u0439 \u0431\u0430\u043b\u043b\u043e\u0432.  use crate::shared::{CustomerId, Money}; use time::OffsetDateTime; use uuid::Uuid;  #[derive(Debug, Clone)] pub struct PointsRequest {     pub customer_id: CustomerId,     pub order_total: Money, }  #[derive(Debug, Clone, serde::Serialize)] pub struct LoyaltyPoints {     pub amount: u32,     pub tier_multiplier: f32,     pub expires_at: OffsetDateTime, }  #[derive(Debug, Clone)] pub struct PointsTransaction {     pub customer_id: CustomerId,     pub points: i32,     pub reason: String, }  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 pub fn calculate_points(request: PointsRequest) -&gt; LoyaltyPoints {     let amount = (request.order_total.to_f32().unwrap() * 0.01) as u32;     LoyaltyPoints {         amount,         tier_multiplier: 1.0,         expires_at: OffsetDateTime::now_utc() + time::Duration::days(365),     } }  pub fn apply_points(customer_id: CustomerId, points: u32) -&gt; Result&lt;Money, LoyaltyError&gt; {     Ok(Money::from(points \/ 10)) }  pub fn rollback_points(transaction: PointsTransaction) -&gt; Result&lt;(), LoyaltyError&gt; {     Ok(()) }  pub fn freeze_points(customer_id: CustomerId, points: u32, duration: std::time::Duration) -&gt; Result&lt;FreezeId, LoyaltyError&gt; {     Ok(Uuid::new_v4()) }  pub fn unfreeze_points(freeze_id: FreezeId) -&gt; Result&lt;(), LoyaltyError&gt; {     Ok(()) }  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u041e\u0448\u0438\u0431\u043a\u0438 \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 #[derive(Debug, thiserror::Error)] pub enum LoyaltyError {     #[error(\"\u0411\u0430\u043b\u043b\u044b \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b\")]     NotFound,     #[error(\"\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u0430\u043b\u043b\u043e\u0432\")]     InsufficientPoints, } ```  ---  ###  `src\/application\/coordination\/events.rs`  ```rust \/\/! # \u0421\u043e\u0431\u044b\u0442\u0438\u044f \/\/! \/\/! \u041f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0432 CrossDomainCoordinator. \/\/! \/\/! \u0412\u0441\u0435 \u0442\u0438\u043f\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0442\u043e\u043b\u044c\u043a\u043e shared:: \u0438 \u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0435 \u0442\u0438\u043f\u044b.  use crate::shared::*;  #[derive(Debug, Clone)] pub struct OrderCancelledEvent {     pub order_id: OrderId,     pub customer_id: CustomerId,     pub delivery_id: DeliveryId,     pub reservation_id: ReservationId,     pub points: u32,     pub total: Money,     pub delivery_status: DeliveryStatus, }  #[derive(Debug, Clone)] pub struct PaymentFailedEvent {     pub order_id: OrderId,     pub customer_id: CustomerId,     pub reservation_id: ReservationId,     pub delivery_id: DeliveryId,     pub points: u32,     pub amount: Money,     pub attempt_number: u8,     pub failure_reason: PaymentError, }  #[derive(Debug, Clone)] pub struct InventoryShortageEvent {     pub order_id: OrderId,     pub warehouse_id: WarehouseId,     pub items: Vec&lt;(ProductId, Quantity)&gt;,     pub reservation_id: ReservationId,     pub address: Address,     pub original_shipping_cost: Money, }  #[derive(Debug, Clone)] pub struct PaymentRetryEvent {     pub reservation_id: ReservationId,     pub delivery_id: DeliveryId,     pub customer_id: CustomerId,     pub freeze_id: FreezeId, }  #[derive(Debug, Clone)] pub struct OrderCancelledCompleteEvent {     pub order_id: OrderId,     pub refund_id: RefundId,     pub returned_items: Vec&lt;(ProductId, Quantity)&gt;,     pub cancellation_fee: Money, } ```  ---  ### `src\/application\/coordination\/mod.rs`  ```rust \/\/! # CrossDomainCoordinator \/\/! \/\/! \u0426\u0435\u043d\u0442\u0440 \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0446\u0438\u0438. \/\/! \/\/! ## \u041f\u043e\u0447\u0435\u043c\u0443 \u0437\u0434\u0435\u0441\u044c \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0435\u043d\u0430 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c: \/\/! \/\/! - **\u0421\u0438\u0441\u0442\u0435\u043c\u0430 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0446\u0438\u043e\u043d\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u0430\u044f, \u0430 \u043d\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e-\u0441\u043b\u043e\u0436\u043d\u0430\u044f**: \/\/!   - \u0414\u043e\u043c\u0435\u043d\u044b \u2014 \u043f\u0440\u043e\u0441\u0442\u044b\u0435, \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u0435. \/\/!   - \u0421\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u2014 \u0432 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0435 \u043e\u0442\u043a\u0430\u0442\u0430, \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0437\u043c\u0435, \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445. \/\/! \/\/! - **\u041c\u043d\u043e\u0433\u043e \u043a\u0440\u043e\u0441\u0441-\u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u0438\u0442\u0438\u043a**: \/\/!   - \u041f\u0440\u0438 \u043e\u0442\u043c\u0435\u043d\u0435: \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u0442\u0430\u0442\u0443\u0441 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438, \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432\u043e\u0437\u0432\u0440\u0430\u0442, \u043e\u0442\u043a\u0430\u0442\u0438\u0442\u044c \u0431\u0430\u043b\u043b\u044b. \/\/!   - \u041f\u0440\u0438 \u043e\u0448\u0438\u0431\u043a\u0435 \u043f\u043b\u0430\u0442\u0435\u0436\u0430: \u0437\u0430\u043c\u043e\u0440\u043e\u0437\u0438\u0442\u044c \u0431\u0430\u043b\u043b\u044b, \u043e\u0442\u043b\u043e\u0436\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0443. \/\/! \/\/! - **Event-driven \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435**: \/\/!   - Retry, hold, unfreeze \u2014 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u0431\u044b\u0442\u0438\u044f. \/\/! \/\/! \u2192 \u041f\u043e\u044d\u0442\u043e\u043c\u0443 `CrossDomainCoordinator` \u2014 \u044d\u0442\u043e **\u044f\u0434\u0440\u043e \u0441\u0438\u0441\u0442\u0435\u043c\u044b**.  use std::sync::Arc; use crate::application::coordination::events::*; use crate::domain::pricing; use crate::domain::inventory; use crate::domain::delivery; use crate::domain::loyalty;  pub struct CrossDomainCoordinator {     pub pricing: Arc&lt;dyn PricingService&gt;,     pub inventory: Arc&lt;dyn InventoryService&gt;,     pub delivery: Arc&lt;dyn DeliveryService&gt;,     pub loyalty: Arc&lt;dyn LoyaltyService&gt;,     pub event_bus: Arc&lt;dyn EventBus&gt;, }  impl CrossDomainCoordinator {     pub fn new(         pricing: Arc&lt;dyn PricingService&gt;,         inventory: Arc&lt;dyn InventoryService&gt;,         delivery: Arc&lt;dyn DeliveryService&gt;,         loyalty: Arc&lt;dyn LoyaltyService&gt;,         event_bus: Arc&lt;dyn EventBus&gt;,     ) -&gt; Self {         Self { pricing, inventory, delivery, loyalty, event_bus }     }      pub async fn handle_order_cancelled(&amp;self, event: OrderCancelledEvent) -&gt; Result&lt;(), Box&lt;dyn std::error::Error&gt;&gt; {         let delivery_status = self.delivery.get_status(event.delivery_id).await?;          let cancellation_fee = match delivery_status {             delivery::DeliveryStatus::Pending =&gt; Money::zero(),             delivery::DeliveryStatus::InTransit =&gt; {                 let fee = self.delivery.cancel_delivery(event.delivery_id).await?;                 let label = self.delivery.create_return_label(event.delivery_id).await?;                 self.notify_customer(event.customer_id, &amp;label).await;                 fee.amount             }             delivery::DeliveryStatus::Delivered =&gt; return Err(\"Cannot cancel delivered order\".into()),         };          let (inv, loy) = tokio::join!(             self.inventory.cancel_reservation(event.reservation_id),             self.loyalty.rollback_points(loyalty::PointsTransaction {                 customer_id: event.customer_id,                 points: -(event.points as i32),                 reason: format!(\"Order {} cancelled\", event.order_id),             })         );          let refund_amount = event.total - cancellation_fee;         let refund_id = self.pricing.refund_payment(pricing::RefundRequest {             order_id: event.order_id,             amount: refund_amount,             reason: pricing::RefundReason::CustomerCancelled,         }).await?;          self.event_bus.publish(OrderCancelledCompleteEvent {             order_id: event.order_id,             refund_id,             returned_items: inv?,             cancellation_fee,         }).await?;          Ok(())     }      pub fn handle_payment_failed(&amp;self, event: PaymentFailedEvent) -&gt; Result&lt;(), Box&lt;dyn std::error::Error&gt;&gt; {         self.inventory.soft_release(event.reservation_id)?;         self.delivery.put_on_hold(event.delivery_id)?;         self.loyalty.freeze_points(event.customer_id, event.points, std::time::Duration::from_secs(86400))?;          if event.attempt_number &gt; 1 {             self.inventory.cancel_reservation(event.reservation_id)?;             self.delivery.cancel_delivery(event.delivery_id)?;             self.loyalty.rollback_points(loyalty::PointsTransaction {                 customer_id: event.customer_id,                 points: -(event.points as i32),                 reason: \"Payment failed after multiple attempts\".to_string(),             })?;         }          Ok(())     }      pub fn handle_payment_retry(&amp;self, event: PaymentRetryEvent) -&gt; Result&lt;(), Box&lt;dyn std::error::Error&gt;&gt; {         self.inventory.restore_reservation(event.reservation_id)?;         self.delivery.remove_hold(event.delivery_id)?;         self.loyalty.unfreeze_points(event.freeze_id)?;         Ok(())     }      async fn notify_customer(&amp;self, _customer_id: CustomerId, _label: &amp;delivery::ReturnLabel) {         tracing::info!(\"\u0412\u043e\u0437\u0432\u0440\u0430\u0442\u043d\u0430\u044f \u043d\u0430\u043a\u043b\u0430\u0434\u043d\u0430\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430\");     } } ```  ---  ### `src\/infrastructure\/web\/handlers.rs` (\u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442)  ```rust pub async fn create_order(     State(state): State&lt;SharedState&gt;,     Json(req): Json&lt;CreateOrderRequest&gt;, ) -&gt; Result&lt;Json&lt;serde_json::Value&gt;, (StatusCode, String)&gt; {     let customer_id: CustomerId = req.customer_id.parse().map_err(|_| (StatusCode::BAD_REQUEST, \"Invalid\"))?;     let items: Vec&lt;(ProductId, Quantity)&gt; = req.items         .into_iter()         .map(|(id, q)| Ok((id.parse()?, q)))         .collect::&lt;Result&lt;_, _&gt;&gt;()         .map_err(|_| (StatusCode::BAD_REQUEST, \"Invalid\"))?;      let address = req.address.into();      let order_id = state.create_order_use_case         .execute(customer_id, items, address, None)         .await         .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;      Ok(Json(json!({ \"order_id\": order_id.to_string() }))) }  \/\/ CreateOrderInteractor \/\/ application\/use_cases\/create_order.rs use std::sync::Arc; use crate::application::ports::*;  pub trait CreateOrderUseCase: Send + Sync {     async fn execute(         &amp;self,         customer_id: CustomerId,         items: Vec&lt;(ProductId, Quantity)&gt;,         address: Address,         use_loyalty_points: Option&lt;u32&gt;,     ) -&gt; Result&lt;OrderId&gt;; }  pub struct CreateOrderInteractor {     pricing: Arc&lt;dyn PricingService&gt;,     inventory: Arc&lt;dyn InventoryService&gt;,     delivery: Arc&lt;dyn DeliveryService&gt;,     loyalty: Arc&lt;dyn LoyaltyService&gt;,     repository: Arc&lt;dyn OrderRepository&gt;, }  impl CreateOrderInteractor {     pub fn new(         pricing: Arc&lt;dyn PricingService&gt;,         inventory: Arc&lt;dyn InventoryService&gt;,         delivery: Arc&lt;dyn DeliveryService&gt;,         loyalty: Arc&lt;dyn LoyaltyService&gt;,         repository: Arc&lt;dyn OrderRepository&gt;,     ) -&gt; Self {         Self { pricing, inventory, delivery, loyalty, repository }     } }  #[async_trait] impl CreateOrderUseCase for CreateOrderInteractor {     async fn execute(...) -&gt; Result&lt;OrderId&gt; {         \/\/ ... \u043b\u043e\u0433\u0438\u043a\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0437\u0430\u043a\u0430\u0437\u0430     } }  \/\/ main.rs use std::sync::Arc;  \/\/ 1. \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u0440\u0442\u043e\u0432 (adapters) let pricing = Arc::new(MockPricingService); let inventory = Arc::new(MockInventoryService); let delivery = Arc::new(MockDeliveryService); let loyalty = Arc::new(MockLoyaltyService); let repository = Arc::new(InMemoryOrderRepository::new()); let event_bus = Arc::new(MockEventBus);  \/\/ 2. \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440 let coordinator = Arc::new(CrossDomainCoordinator::new(     pricing.clone(),     inventory.clone(),     delivery.clone(),     loyalty.clone(),     event_bus, ));  \/\/ 3. \u0421\u043e\u0437\u0434\u0430\u0451\u043c use case \u0441 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 let create_order_use_case: Arc&lt;dyn CreateOrderUseCase&gt; = Arc::new(CreateOrderInteractor::new(     pricing,     inventory,     delivery,     loyalty,     repository, ));  let state = Arc::new(ApplicationState {     create_order_use_case,                cancel_order_use_case,     confirm_payment_use_case,     retry_payment_use_case, }); let app = Router::new()     .route(\"\/orders\", post(handlers::create_order))     .with_state(state); \/\/ \u2190 Axum \u043f\u0435\u0440\u0435\u0434\u0430\u0441\u0442 state \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438   \/\/ ApplicationState \/\/ src\/infrastructure\/web\/state.rs pub struct ApplicationState {     pub create_order_use_case: Arc&lt;dyn CreateOrderUseCase&gt;,     pub cancel_order_use_case: Arc&lt;dyn CancelOrderUseCase&gt;,     \/\/ ... \u0434\u0440\u0443\u0433\u0438\u0435 use cases }  pub type SharedState = Arc&lt;ApplicationState&gt;;  \/\/ state.create_order_use_case \/\/ infrastructure\/web\/handlers.rs pub async fn create_order(     State(state): State&lt;SharedState&gt;,  \/\/ \u2190 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c state     Json(req): Json&lt;CreateOrderRequest&gt;, ) -&gt; Result&lt;Json&lt;Value&gt;, (StatusCode, String)&gt; {     \/\/ \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c use case     let order_id = state.create_order_use_case         .execute(customer_id, items, address, None)         .await?;          Ok(Json(json!({ \"order_id\": order_id.to_string() }))) }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>TL;DR: \u043c\u043e\u0442\u0430\u0439\u0442\u0435 \u043a\u043e\u0434 \u0441\u0440\u0430\u0437\u0443 \u0434\u043e \u0441\u043b\u043e\u0432\u0430 &#171;coordination&#187;<\/p>\n<p>\u041d\u0430 \u0447\u0442\u043e \u044d\u0442\u043e \u043f\u043e\u0445\u043e\u0436\u0435?<\/p>\n<ul>\n<li>\n<p>\u0412 \u041e\u041e\u041f \u0430\u043d\u0430\u043b\u043e\u0433\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0430\u0442\u0442\u0435\u0440\u043d &#171;\u0447\u0438\u0441\u0442\u0430\u044f \u0432\u044b\u0434\u0443\u043c\u043a\u0430&#187;<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0424\u041f \u0430\u043d\u0430\u043b\u043e\u0433\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0430\u0431\u043e\u0440 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u0431\u0435\u0440\u0443\u0449\u0438\u0445 \u043d\u0430 \u0441\u0435\u0431\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0447\u0443 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u043d\u0430 Rust \u0434\u043e\u043c\u0435\u043d\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0438 \u0432\u044b\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u043a\u0440\u0430\u0441\u0438\u0432\u043e!<\/p>\n<details class=\"spoiler\">\n<summary>\u041d\u0435\u043c\u043d\u043e\u0433\u043e \u0444\u0438\u043b\u043e\u0441\u043e\u0444\u0438\u0438, \u0437\u0430\u043d\u0443\u0434\u043d\u044b\u0445 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0439 \u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0439 \u0441 \u0442\u0438\u043f\u043e\u0432\u044b\u043c\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430\u043c\u0438<\/summary>\n<div class=\"spoiler__content\">\n<h4>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 &#171;\u043c\u0435\u0436\u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442&#187;?<\/h4>\n<ul>\n<li>\n<p>\u041e\u0431\u044b\u0447\u043d\u044b\u0439 \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442:<\/p>\n<blockquote>\n<p><em>&#171;\u0426\u0435\u043d\u0430 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439&#187;<\/em>, <em>&#171;\u041d\u0435\u043b\u044c\u0437\u044f \u0437\u0430\u0440\u0435\u0437\u0435\u0440\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435, \u0447\u0435\u043c \u0435\u0441\u0442\u044c&#187;<\/em> <\/p>\n<\/blockquote>\n<\/li>\n<li>\n<p>\u041c\u0435\u0436\u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442:<\/p>\n<blockquote>\n<p><em>&#171;\u0415\u0441\u043b\u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0430 \u0432 \u043f\u0443\u0442\u0438 \u2014 \u043d\u0435\u043b\u044c\u0437\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0437\u0430\u043a\u0430\u0437, \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u043d\u0443\u044e \u043d\u0430\u043a\u043b\u0430\u0434\u043d\u0443\u044e&#187;<\/em><br \/><em>&#171;\u041f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0435 \u043f\u043b\u0430\u0442\u0435\u0436\u0430 \u2014 \u0437\u0430\u043c\u043e\u0440\u043e\u0437\u0438\u0442\u044c \u0431\u0430\u043b\u043b\u044b, \u043f\u0440\u0438 \u0432\u0442\u043e\u0440\u043e\u0439 \u2014 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u0441\u0451&#187;<\/em><br \/><em>&#171;\u0415\u0441\u043b\u0438 \u0442\u043e\u0432\u0430\u0440\u0430 \u043d\u0435\u0442 \u2014 \u043d\u0430\u0439\u0442\u0438 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0441\u043a\u043b\u0430\u0434, \u043f\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0443, \u0441\u043f\u0440\u043e\u0441\u0438\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u0435\u0441\u043b\u0438 \u0434\u043e\u0440\u043e\u0436\u0435&#187;<\/em> <\/p>\n<\/blockquote>\n<\/li>\n<li>\n<p><strong>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435<\/strong>:<\/p>\n<blockquote>\n<p><em>&#171;\u041c\u0435\u0436\u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0439 (\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043d\u044b\u0439) \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u2014 \u044d\u0442\u043e \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0434\u043e\u043c\u0435\u043d\u043e\u0432 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0445 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\u043c \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438.&#187;<\/em> <\/p>\n<\/blockquote>\n<\/li>\n<\/ul>\n<hr\/>\n<h4>\u041f\u043e\u0447\u0435\u043c\u0443 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043d\u0435 \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442<\/h4>\n<ul>\n<li>\n<p>DDD \u0443\u0447\u0438\u0442: &#171;\u0432\u0441\u0451 \u0432 \u0434\u043e\u043c\u0435\u043d\u0435&#187;, &#171;use case \u2014 \u0442\u043e\u043d\u043a\u0438\u0439&#187;, &#171;\u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u043a\u0440\u043e\u0441\u0441-\u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432&#187;<\/p>\n<\/li>\n<li>\n<p>\u041d\u043e:<\/p>\n<ul>\n<li>\n<p>\u041d\u0435\u0442 <code>OrderId<\/code> \u0443 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u043e\u0442\u043c\u0435\u043d\u044b<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0442 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u0430 \u0434\u043b\u044f &#171;\u043f\u043b\u0430\u0442\u0435\u0436\u0430 \u0441 retry&#187;<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u043b\u044c\u0437\u044f \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0443 \u0432 <code>Order::cancel()<\/code> \u2014 \u043e\u043d\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 <code>DeliveryStatus<\/code>, <code>PaymentAttempts<\/code>, <code>LoyaltyPoints<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430<\/strong>:<\/p>\n<blockquote>\n<p>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 <strong>\u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438<\/strong>, \u043d\u043e \u043d\u0435 <strong>\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b<\/strong>. <\/p>\n<\/blockquote>\n<\/li>\n<li>\n<p><strong>\u0412\u044b\u0432\u043e\u0434<\/strong>:<\/p>\n<blockquote>\n<p>\u041c\u0435\u0436\u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0435 \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u2014 \u044d\u0442\u043e <strong>\u043d\u0435 \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0430 \u043f\u0440\u0438\u0437\u043d\u0430\u043a \u0437\u0440\u0435\u043b\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b<\/strong>. <\/p>\n<\/blockquote>\n<\/li>\n<\/ul>\n<hr\/>\n<h4>\u041a\u0443\u0434\u0430 \u0434\u0435\u0432\u0430\u0442\u044c \u044d\u0442\u0443 \u043b\u043e\u0433\u0438\u043a\u0443?<\/h4>\n<p>\u0420\u0430\u0437\u0431\u043e\u0440 \u0430\u043d\u0442\u0438\u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432 \u0438 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th data-colwidth=\"239\" width=\"239\">\n<p align=\"left\">\u041f\u043e\u043f\u044b\u0442\u043a\u0430<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041f\u043e\u0447\u0435\u043c\u0443 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td data-colwidth=\"239\" width=\"239\">\n<p align=\"left\"><strong>\u041f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u0432\u00a0<\/strong><code><strong>Order<\/strong><\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>Order<\/code>\u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0437\u043d\u0430\u0442\u044c \u043f\u0440\u043e<code>DeliveryStatus<\/code>,<code>LoyaltyFreezeId<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"239\" width=\"239\">\n<p align=\"left\"><strong>\u041f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u0432 use case<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">Use case \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f &#171;\u0442\u043e\u043b\u0441\u0442\u044b\u043c&#187;, \u0434\u0443\u0431\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043b\u043e\u0433\u0438\u043a\u0430<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"239\" width=\"239\">\n<p align=\"left\"><strong>\u0420\u0430\u0437\u043c\u0430\u0437\u0430\u0442\u044c \u043f\u043e \u0434\u043e\u043c\u0435\u043d\u0430\u043c<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041a\u0430\u0436\u0434\u044b\u0439 \u0434\u0435\u043b\u0430\u0435\u0442 \u0441\u0432\u043e\u044e \u0447\u0430\u0441\u0442\u044c \u2014 \u043d\u043e \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0446\u0435\u043b\u043e\u0441\u0442\u043d\u043e\u0441\u0442\u044c<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"239\" width=\"239\">\n<p align=\"left\"><strong>\u0421\u043e\u0437\u0434\u0430\u0442\u044c\u00a0<\/strong><code><strong>OrderService<\/strong><\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u042d\u0442\u043e \u043d\u0435 \u0434\u043e\u043c\u0435\u043d, \u044d\u0442\u043e \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440 \u2014 \u043d\u043e \u0432 \u041e\u041e\u041f \u043c\u044b \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u044d\u0442\u043e &#171;\u0441\u0435\u0440\u0432\u0438\u0441&#187; \u0438 \u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0432\u0442\u043e\u0440\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u044b\u043c<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p> <strong>\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/strong>:<\/p>\n<blockquote>\n<p>\u041d\u0443\u0436\u043d\u043e <strong>\u044f\u0432\u043d\u043e \u0432\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043d\u044b\u0439 \u0434\u043e\u043c\u0435\u043d<\/strong> \u2014 \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c. <\/p>\n<\/blockquote>\n<hr\/>\n<h4>\u041f\u0440\u043e\u0446\u0435\u0441\u0441\u043d\u044b\u0439 \u0434\u043e\u043c\u0435\u043d: \u043d\u043e\u0432\u044b\u0439 \u0442\u0438\u043f \u0434\u043e\u043c\u0435\u043d\u0430<\/h4>\n<ul>\n<li>\n<p><strong>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435<\/strong>:<\/p>\n<blockquote>\n<p>\u041f\u0440\u043e\u0446\u0435\u0441\u0441\u043d\u044b\u0439 \u0434\u043e\u043c\u0435\u043d \u2014 \u044d\u0442\u043e \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u0437\u043d\u0430\u043d\u0438\u0439, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0430\u044f \u0437\u0430 <strong>\u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0435 \u0446\u0438\u043a\u043b\u044b, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0438 \u043a\u0440\u043e\u0441\u0441-\u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0438<\/strong>. <\/p>\n<\/blockquote>\n<\/li>\n<li>\n<p><strong>\u041e\u0442\u043b\u0438\u0447\u0438\u044f \u043e\u0442 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0434\u043e\u043c\u0435\u043d\u0430<\/strong>:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u041a\u0440\u0438\u0442\u0435\u0440\u0438\u0439<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0421\u0443\u0449\u043d\u043e\u0441\u0442\u043d\u044b\u0439 \u0434\u043e\u043c\u0435\u043d<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041f\u0440\u043e\u0446\u0435\u0441\u0441\u043d\u044b\u0439 \u0434\u043e\u043c\u0435\u043d<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0426\u0435\u043d\u0442\u0440<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0421\u0443\u0449\u043d\u043e\u0441\u0442\u044c (<code>Order<\/code>)<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u0440\u043e\u0446\u0435\u0441\u0441 (<code>OrderCancellation<\/code>)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0415\u0441\u0442\u044c (<code>OrderId<\/code>)<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435\u0442 (\u0438\u043b\u0438 \u0432\u0442\u043e\u0440\u0438\u0447\u0435\u043d)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0410\u0433\u0440\u0435\u0433\u0430\u0442, \u0411\u0414<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0412\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f, \u0441\u043e\u0431\u044b\u0442\u0438\u044f<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u042d\u043a\u0441\u043f\u0435\u0440\u0442\u0438\u0437\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0411\u0438\u0437\u043d\u0435\u0441-\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0418\u043d\u0436\u0435\u043d\u0435\u0440\u044b, SRE, \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043d\u044b\u0435 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">Entity, Aggregate<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0430\u0431\u043e\u0440 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<\/li>\n<li>\n<p><strong>\u041f\u0440\u0438\u043c\u0435\u0440\u044b \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043d\u044b\u0445 \u0434\u043e\u043c\u0435\u043d\u043e\u0432<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c \u0437\u0430\u043a\u0430\u0437\u0430<\/p>\n<\/li>\n<li>\n<p>\u041f\u043b\u0430\u0442\u0451\u0436 \u0441 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u043c\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0430\u043c\u0438<\/p>\n<\/li>\n<li>\n<p>\u0412\u043e\u0437\u0432\u0440\u0430\u0442 \u0442\u043e\u0432\u0430\u0440\u0430<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u043c\u0438<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<hr\/>\n<h4>\u041a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043d\u044b\u0439 \u0434\u043e\u043c\u0435\u043d?<\/h4>\n<h3>\u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b:<\/h3>\n<ol>\n<li>\n<p><strong>\u041e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440 (\u0432 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0435)<\/strong>\u2192 <code>CrossDomainCoordinator<\/code>, \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441 \u044f\u0432\u043d\u044b\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438<\/p>\n<\/li>\n<li>\n<p><strong>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441<\/strong>\u2192 <code>order-orchestrator<\/code>, <code>payment-retry-service<\/code><\/p>\n<\/li>\n<li>\n<p><strong>Workflow Engine<\/strong>\u2192 Temporal, Cadence, AWS Step Functions<\/p>\n<\/li>\n<\/ol>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><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\/articles\/937380\/\"> https:\/\/habr.com\/ru\/articles\/937380\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0422\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442, \u043a\u043e\u0433\u0434\u0430 \u043e\u043d\u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u0441\u0430\u043c\u0438\u0445 \u0434\u043e\u043c\u0435\u043d\u043e\u0432<\/p>\n<p>\u042f \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u0441 \u0442\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439:<br \/> \u043b\u043e\u0433\u0438\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 \u0434\u043e\u043c\u0435\u043d\u0430\u043c\u0438 \u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u0441\u0430\u043c\u0438\u0445 \u0434\u043e\u043c\u0435\u043d\u043e\u0432<br \/> \u0430 \u0432 \u043a\u043d\u0438\u0436\u043a\u0430\u0445 \u043e\u0431 \u044d\u0442\u043e\u043c \u043d\u0435 \u043f\u0438\u0448\u0443\u0442<\/p>\n<p>\u042f \u0441\u0442\u0440\u043e\u0438\u043b \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043f\u043e DDD, \u0432\u0441\u0435 \u043a\u0440\u0430\u0441\u0438\u0432\u043e:<\/p>\n<ul>\n<li>\n<p>\u0434\u043e\u043c\u0435\u043d\u044b<\/p>\n<\/li>\n<li>\n<p>\u0430\u0433\u0440\u0435\u0433\u0430\u0442\u044b<\/p>\n<\/li>\n<li>\n<p>use cases<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0431\u044b\u0442\u0438\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0442\u043e\u043c \u043f\u0440\u0438\u0448\u0451\u043b \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439: &#171;\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0437\u0430\u043a\u0430\u0437&#187;<\/p>\n<p>\u042f \u0434\u0443\u043c\u0430\u043b: &#171;\u041d\u0443, Order::cancel(), \u0432\u044b\u0437\u043e\u0432\u0443 inventory.release(), pricing.refund(), \u0438 \u0433\u043e\u0442\u043e\u0432\u043e&#187;<\/p>\n<p>\u041d\u043e, \u0445\u043c\u043c&#8230;<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0430 \u0443\u0436\u0435 \u0432 \u043f\u0443\u0442\u0438 \u2014 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u043d\u0443\u044e \u043d\u0430\u043a\u043b\u0430\u0434\u043d\u0443\u044e<br \/>\u0415\u0441\u043b\u0438 \u043f\u043b\u0430\u0442\u0451\u0436 \u043f\u0430\u0434\u0430\u043b \u0434\u0432\u0430\u0436\u0434\u044b \u2014 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u0441\u0451, \u0430 \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u0439 \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u2014 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043c\u043e\u0440\u043e\u0437\u0438\u0442\u044c \u0431\u0430\u043b\u043b\u044b<br \/>\u0415\u0441\u043b\u0438 \u0442\u043e\u0432\u0430\u0440\u0430 \u043d\u0435\u0442 \u2014 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0440\u0435\u0437\u0435\u0440\u0432 \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u043a\u043b\u0430\u0434, \u043f\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0443, \u0441\u043f\u0440\u043e\u0441\u0438\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u0435\u0441\u043b\u0438 \u0434\u043e\u0440\u043e\u0436\u0435<br \/>\u0415\u0441\u043b\u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u043b \u043f\u043b\u0430\u0442\u0451\u0436 \u2014 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0440\u0435\u0437\u0435\u0440\u0432 \u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0443<\/p>\n<p>\u0418 \u044f \u043f\u043e\u043d\u044f\u043b:<\/p>\n<p>\u0421\u0430\u043c\u0430\u044f \u0441\u043b\u043e\u0436\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u2014 \u043d\u0435 \u0432 \u0434\u043e\u043c\u0435\u043d\u0430\u0445, \u0430 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438. \u0412 \u043a\u043d\u0438\u0436\u043a\u0430\u0445 \u043f\u043e DDD, Clean Architecture, Hexagonal \u2014 \u043e\u0431 \u044d\u0442\u043e\u043c \u043d\u0435 \u043f\u0438\u0448\u0443\u0442. \u0422\u0430\u043c \u0443\u0447\u0430\u0442:<\/p>\n<ul>\n<li>\n<p>&#171;Use case \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0442\u043e\u043d\u043a\u0438\u043c&#187;<\/p>\n<\/li>\n<li>\n<p>&#171;\u0414\u043e\u043c\u0435\u043d \u044d\u0442\u043e \u0446\u0435\u043d\u0442\u0440 \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u0438&#187;<\/p>\n<\/li>\n<li>\n<p>&#171;\u041c\u0435\u0436\u0434\u0443 \u0434\u043e\u043c\u0435\u043d\u0430\u043c\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0438\u043b\u0438 \u0432\u044b\u0437\u043e\u0432\u044b API c JSON (\u0442.\u0435. \u0442\u0438\u043f\u044b \u043d\u0430 \u0433\u0440\u0430\u043d\u0438\u0446\u0435 \u0442\u0435\u0440\u044f\u044e\u0442\u0441\u044f, \u0437\u043d\u0430\u0447\u0438\u0442 \u0431\u0438\u0437\u043d\u0435\u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0433\u0440\u0430\u043d\u0438\u0446\u0443 \u043d\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044f\u0442)&#187; <\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u044f \u043f\u043e\u0439\u0434\u0443 \u043f\u043e \u043a\u043d\u0438\u0436\u043a\u0430\u043c \u0438 \u0432\u043e\u0442\u043a\u043d\u0443 \u044d\u0442\u043e\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0432 \u043e\u0431\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u0438 Order, \u0442\u043e \u0442\u043e\u0442 \u0441\u0442\u0430\u043d\u0435\u0442 &#171;\u0431\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c&#187;<\/p>\n<ul>\n<li>\n<p>\u0417\u0430\u0432\u0438\u0441\u0435\u0442\u044c \u043e\u0442 4 \u0434\u043e\u043c\u0435\u043d\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u0417\u043d\u0430\u0442\u044c \u043f\u0440\u043e \u0441\u0442\u0430\u0442\u0443\u0441 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e retry, hold, freeze<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0440\u0443\u0448\u0430\u0442\u044c SRP<\/p>\n<\/li>\n<li>\n<p>\u0410 \u0437\u0430\u043e\u0434\u043d\u043e \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c anti corruption layer \u0442.\u043a. \u043d\u0430 \u0432\u0445\u043e\u0434 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0439\u0442\u0438 \u0447\u0442\u043e \u0443\u0433\u043e\u0434\u043d\u043e, \u044f \u043b\u0438\u0448\u0430\u044e\u0441\u044c \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0439 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430, \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u043d\u044b\u0445 \u0432 \u0442\u0438\u043f\u0430\u0445<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u043e \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u0433\u043e\u0432\u043e\u0440\u0438\u0442, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0442\u043e?<\/p>\n<p>\u042f \u0432\u0432\u0451\u043b \u0442\u043e, \u0447\u0435\u0433\u043e \u043d\u0435 \u0431\u044b\u043b\u043e \u0432 \u0443\u0447\u0435\u0431\u043d\u0438\u043a\u0430\u0445:<\/p>\n<p><strong>CrossDomainCoordinator<\/strong><\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0430 \u0441\u0435\u0431\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 \u043b\u043e\u0433\u0438\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043b\u0438\u0448\u043d\u0438\u0435, \u0447\u0443\u0436\u0435\u0440\u043e\u0434\u043d\u044b\u0435 \u0434\u043b\u044f \u0431\u0438\u0437\u043d\u0435\u0441 \u0434\u043e\u043c\u0435\u043d\u043e\u0432  <\/p>\n<\/li>\n<li>\n<p>\u0417\u043d\u0430\u0435\u0442, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0434\u043e\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e<\/p>\n<\/li>\n<li>\n<p>\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0430\u043c\u0438: retry, hold, freeze<\/p>\n<\/li>\n<li>\n<p>\u041f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0434\u043b\u044f \u0430\u0443\u0434\u0438\u0442\u0430 <\/p>\n<p><strong>SharedKernel<\/strong><\/p>\n<\/li>\n<li>\n<p>\u0421\u0430\u043c\u0430\u044f \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0434\u043b\u044f \u0432\u0441\u0435\u0445, \u043a\u0430\u043a \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0430 \u041a\u043e\u043c\u043f\u0430\u043d\u0438\u0438<\/p>\n<p>\u0412\u043a\u0440\u0430\u0442\u0446\u0435:<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"rust\">if status == InTransit {     self.delivery.cancel_with_fee(...).await?;     self.delivery.create_return_label(...).await?; }  let (inv, loy) = tokio::join!(     self.inventory.cancel_reservation(...),     self.loyalty.rollback_points(...), );  self.pricing.refund_payment(...).await?; self.event_bus.publish(...).await;  Ok(()) }<\/code><\/pre>\n<p>src\/<br \/> \u251c\u2500\u2500 domain\/<br \/> \u2502   \u251c\u2500\u2500 pricing\/<br \/> \u2502   \u2502   \u2514\u2500\u2500 src\/<a href=\"http:\/\/lib.rs\" rel=\"noopener noreferrer nofollow\">lib.rs<\/a><br \/> \u2502   \u251c\u2500\u2500 inventory\/<br \/> \u2502   \u2502   \u2514\u2500\u2500 src\/<a href=\"http:\/\/lib.rs\" rel=\"noopener noreferrer nofollow\">lib.rs<\/a><br \/> \u2502   \u251c\u2500\u2500 delivery\/<br \/> \u2502   \u2502   \u2514\u2500\u2500 src\/<a href=\"http:\/\/lib.rs\" rel=\"noopener noreferrer nofollow\">lib.rs<\/a><br \/> \u2502   \u2514\u2500\u2500 loyalty\/<br \/> \u2502       \u2514\u2500\u2500 src\/<a href=\"http:\/\/lib.rs\" rel=\"noopener noreferrer nofollow\">lib.rs<\/a><br \/> \u251c\u2500\u2500 application\/<br \/> \u2502   \u251c\u2500\u2500 coordination\/<br \/> \u2502   \u2502   \u251c\u2500\u2500 <a href=\"http:\/\/mod.rs\" rel=\"noopener noreferrer nofollow\">mod.rs<\/a><br \/> \u2502   \u2502   \u251c\u2500\u2500 <a href=\"http:\/\/handlers.rs\" rel=\"noopener noreferrer nofollow\">handlers.rs<\/a><br \/> \u2502   \u2502   \u2514\u2500\u2500 <a href=\"http:\/\/events.rs\" rel=\"noopener noreferrer nofollow\">events.rs<\/a><br \/> \u2502   \u2514\u2500\u2500 use_cases\/<br \/> \u2502       \u251c\u2500\u2500 create_<a href=\"http:\/\/order.rs\" rel=\"noopener noreferrer nofollow\">order.rs<\/a><br \/> \u2502       \u251c\u2500\u2500 cancel_<a href=\"http:\/\/order.rs\" rel=\"noopener noreferrer nofollow\">order.rs<\/a><br \/> \u2502       \u251c\u2500\u2500 confirm_order_<a href=\"http:\/\/payment.rs\" rel=\"noopener noreferrer nofollow\">payment.rs<\/a><br \/> \u2502       \u2514\u2500\u2500 retry_<a href=\"http:\/\/payment.rs\" rel=\"noopener noreferrer nofollow\">payment.rs<\/a><br \/> \u251c\u2500\u2500 infrastructure\/<br \/> \u2502   \u251c\u2500\u2500 web\/<br \/> \u2502   \u2502   \u251c\u2500\u2500 <a href=\"http:\/\/handlers.rs\" rel=\"noopener noreferrer nofollow\">handlers.rs<\/a><br \/> \u2502   \u2502   \u251c\u2500\u2500 <a href=\"http:\/\/routes.rs\" rel=\"noopener noreferrer nofollow\">routes.rs<\/a><br \/> \u2502   \u2502   \u2514\u2500\u2500 <a href=\"http:\/\/state.rs\" rel=\"noopener noreferrer nofollow\">state.rs<\/a><br \/> \u2502   \u251c\u2500\u2500 adapters\/<br \/> \u2502   \u2502   \u251c\u2500\u2500 mock_*.rs<br \/> \u2502   \u2502   \u2514\u2500\u2500 in_memory_<a href=\"http:\/\/repository.rs\" rel=\"noopener noreferrer nofollow\">repository.rs<\/a><br \/> \u2502   \u2514\u2500\u2500 persistence\/<br \/> \u2502       \u251c\u2500\u2500 <a href=\"http:\/\/mod.rs\" rel=\"noopener noreferrer nofollow\">mod.rs<\/a><br \/> \u2502       \u251c\u2500\u2500 order_<a href=\"http:\/\/repository.rs\" rel=\"noopener noreferrer nofollow\">repository.rs<\/a><br \/> \u2502       \u2514\u2500\u2500 schema.sql<br \/> \u2514\u2500\u2500 shared\/<a href=\"http:\/\/lib.rs\" rel=\"noopener noreferrer nofollow\">lib.rs<\/a><\/p>\n<p>\u0412 \u043a\u043e\u0434\u0435 \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e:<\/p>\n<ul>\n<li>\n<p>\u0434\u043e\u043c\u0435\u043d\u044b \u043f\u0440\u043e\u0441\u0442\u044b\u0435, \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445, \u0447\u0435\u043c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f (\u043b\u043e\u0433\u0438\u043a\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0432 \u0442\u0438\u043f\u0430\u0445), \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0447\u0438\u0441\u0442\u044b\u043c\u0438: inventory, delivery, loyalty \u2014 \u043d\u0435 \u0437\u043d\u0430\u044e\u0442 \u0434\u0440\u0443\u0433 \u043e \u0434\u0440\u0443\u0433\u0435<\/p>\n<\/li>\n<li>\n<p>\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440 \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0447\u0442\u0438 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0438\u0437 \u0438\u043d\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 (\u043f\u0440\u0430\u0432\u0438\u043b) \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f, \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u0432\u043d\u0443\u0442\u0440\u0438, \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u043c\u0435\u0441\u0442\u043e, \u0433\u0434\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u0437\u0430\u0432\u0438\u0441\u044f\u0449\u0438\u0435 \u043e\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0434\u043e\u043c\u0435\u043d\u043e\u0432<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435, \u044f \u0441\u0445\u0430\u043b\u044f\u0432\u0438\u043b \u0438 \u043d\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0434\u043b\u044f \u0434\u043e\u043c\u0435\u043d\u043e\u0432 \u043b\u043e\u0433\u0438\u043a\u0443, \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0438. \u041d\u0443, \u0438 \u0442\u0430\u043a \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u0447\u0442\u043e \u043e\u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f. <\/p>\n<p><strong>\u0412\u044b\u0432\u043e\u0434<\/strong><br \/>\u0415\u0441\u043b\u0438 \u043b\u043e\u0433\u0438\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 \u0434\u043e\u043c\u0435\u043d\u0430\u043c\u0438 \u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u0441\u0430\u043c\u0438\u0445 \u0434\u043e\u043c\u0435\u043d\u043e\u0432 &#8212; \u0432\u044b\u0434\u0435\u043b\u0438 \u0435\u0451 \u044f\u0432\u043d\u043e CrossDomainCoordinator &#8212; \u043a\u0430\u043a \u0434\u043e\u043c\u0435\u043d, \u0442\u043e\u043b\u044c\u043a\u043e \u0431\u0435\u0437 \u0441\u0432\u043e\u0438\u0445 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439. \u0414\u043b\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0434\u043e\u043c\u0435\u043d\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043d\u0430 Rust, <\/figcaption><\/div>\n<\/figure>\n<details class=\"spoiler\">\n<summary>\u0432\u0441\u0435\u0433\u043e-\u0442\u043e 700+ \u0441\u0442\u0440\u043e\u043a \u0443\u0447\u0435\u0431\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">\/\/! # Shared Kernel \/\/! \/\/! \u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435, \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u044f\u0434\u0440\u043e. \/\/! \/\/! ## \u041f\u0440\u0430\u0432\u0438\u043b\u0430: \/\/! - \u0422\u043e\u043b\u044c\u043a\u043e \u0444\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \/\/! - \u041d\u0438\u043a\u0430\u043a\u0438\u0445 enum \u0441 \u0431\u0438\u0437\u043d\u0435\u0441-\u0441\u0435\u043c\u0430\u043d\u0442\u0438\u043a\u043e\u0439 (Carrier, RefundReason \u0438 \u0442.\u0434.) \/\/! - \u041d\u0438\u043a\u0430\u043a\u0438\u0445 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u044b\u0445 \u043f\u043e\u043b\u0438\u0442\u0438\u043a \/\/! \/\/! ## \u041f\u043e\u0447\u0435\u043c\u0443: \/\/! \u042d\u0442\u043e shared kernel \u043f\u043e DDD. \u041b\u044e\u0431\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0437\u0434\u0435\u0441\u044c \u0437\u0430\u0442\u0440\u0430\u0433\u0438\u0432\u0430\u0435\u0442 \u0432\u0441\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443. \/\/! \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043a\u0430\u043a \"\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\" \u2014 \u043f\u043e\u0447\u0442\u0438 \u043d\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f.  use rust_decimal::Decimal; use uuid::Uuid;  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 pub type CustomerId = Uuid; pub type ProductId = Uuid; pub type OrderId = Uuid; pub type WarehouseId = Uuid; pub type ReservationId = Uuid; pub type DeliveryId = Uuid; pub type RefundId = Uuid; pub type FreezeId = Uuid;  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u0414\u0435\u043d\u0435\u0436\u043d\u044b\u0435 \u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 pub type Money = Decimal; pub type Quantity = u32; pub type Weight = f32;  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u041e\u0431\u0449\u0438\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct Address {     pub street: String,     pub city: String,     pub zip: String,     pub country: String, } ```  ---  ###  `src\/domain\/pricing\/src\/lib.rs`  ```rust \/\/! # Pricing Domain \/\/! \/\/! \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0430\u0441\u0447\u0451\u0442\u043e\u043c \u0446\u0435\u043d, \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u043e\u0439 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u043e\u043c \u0441\u0440\u0435\u0434\u0441\u0442\u0432. \/\/! \/\/! ## \u0417\u0430\u0432\u0438\u0441\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442 `shared\/` \/\/! - `Money`, `OrderId`, `CustomerId` \/\/! \/\/! ## \u041d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u0434\u043e\u043c\u0435\u043d\u043e\u0432  use crate::shared::{CustomerId, ProductId, OrderId, Money, Quantity}; use uuid::Uuid;  #[derive(Debug, Clone)] pub struct PriceRequest {     pub customer_id: CustomerId,     pub items: Vec&lt;(ProductId, Quantity)&gt;,     pub promo_code: Option&lt;String&gt;,     pub loyalty_discount: Option&lt;Money&gt;, }  #[derive(Debug, Clone, serde::Serialize)] pub struct PriceBreakdown {     pub base: Money,     pub discount: Money,     pub tax: Money,     pub final_price: Money, }  #[derive(Debug, Clone)] pub struct RefundRequest {     pub order_id: OrderId,     pub amount: Money,     pub reason: RefundReason, }  #[derive(Debug, Clone, PartialEq)] pub enum RefundReason {     CustomerCancelled,     Fraudulent,     SystemError, }  pub type PaymentHoldId = Uuid;  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 pub fn calculate_prices(request: PriceRequest) -&gt; PriceBreakdown {     \/\/ \u0423\u043f\u0440\u043e\u0449\u0451\u043d\u043d\u044b\u0439 \u0440\u0430\u0441\u0447\u0451\u0442     let base: Money = request.items.iter().map(|(_, q)| Money::from(*q)).sum();     let discount = request.loyalty_discount.unwrap_or(Money::zero());     let tax = base * rust_decimal_macros::dec!(0.1);     let final_price = base - discount + tax;      PriceBreakdown {         base,         discount,         tax,         final_price,     } }  pub fn refund_payment(request: RefundRequest) -&gt; Result&lt;RefundId, PricingError&gt; {     \/\/ \u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 \u043f\u043b\u0430\u0442\u0451\u0436\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439     Ok(Uuid::new_v4()) }  pub fn hold_payment(customer_id: CustomerId, amount: Money) -&gt; Result&lt;PaymentHoldId, PricingError&gt; {     Ok(Uuid::new_v4()) }  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u041e\u0448\u0438\u0431\u043a\u0438 \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 #[derive(Debug, thiserror::Error)] pub enum PricingError {     #[error(\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u043b\u0430\u0442\u0435\u0436\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b\")]     PaymentSystemError,     #[error(\"\u0421\u0443\u043c\u043c\u0430 \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f\")]     NegativeAmount, } ```  ---  ###  `src\/domain\/inventory\/src\/lib.rs`  ```rust \/\/! # Inventory Domain \/\/! \/\/! \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u0437\u0435\u0440\u0432\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c, \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u043e\u0439 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u0438 \u0438 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u043e\u043c \u0442\u043e\u0432\u0430\u0440\u0430.  use crate::shared::{ProductId, Quantity, WarehouseId, ReservationId, Money, Address}; use uuid::Uuid;  #[derive(Debug, Clone)] pub struct ReserveRequest {     pub items: Vec&lt;(ProductId, Quantity)&gt;,     pub warehouse_id: WarehouseId,     pub priority: Priority, }  #[derive(Debug, Clone, serde::Serialize)] pub struct ItemAvailability {     pub product_id: ProductId,     pub available: Quantity,     pub warehouse_id: WarehouseId, }  #[derive(Debug, Clone)] pub struct TransferRequest {     pub reservation_id: ReservationId,     pub from: WarehouseId,     pub to: WarehouseId, }  #[derive(Debug, Clone, PartialEq)] pub enum Priority {     Low,     Normal,     High, }  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 pub fn check_availability(items: Vec&lt;(ProductId, Quantity)&gt;) -&gt; Vec&lt;ItemAvailability&gt; {     items.into_iter()         .map(|(id, _)| ItemAvailability {             product_id: id,             available: 10, \/\/ \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u0435             warehouse_id: Uuid::new_v4().into(),         })         .collect() }  pub fn reserve(request: ReserveRequest) -&gt; Result&lt;ReservationId, InventoryError&gt; {     Ok(Uuid::new_v4()) }  pub fn cancel_reservation(reservation_id: ReservationId) -&gt; Result&lt;Vec&lt;(ProductId, Quantity)&gt;, InventoryError&gt; {     Ok(vec![(Uuid::new_v4(), 2)]) }  pub fn transfer_reservation(request: TransferRequest) -&gt; Result&lt;(), InventoryError&gt; {     Ok(()) }  pub fn confirm_reservation(reservation_id: ReservationId) -&gt; Result&lt;(), InventoryError&gt; {     Ok(()) }  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u041e\u0448\u0438\u0431\u043a\u0438 \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 #[derive(Debug, thiserror::Error)] pub enum InventoryError {     #[error(\"\u0422\u043e\u0432\u0430\u0440 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\")]     NotFound,     #[error(\"\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043d\u0430 \u0441\u043a\u043b\u0430\u0434\u0435\")]     OutOfStock, } ```  ---  ###  `src\/domain\/delivery\/src\/lib.rs`  ```rust \/\/! # Delivery Domain \/\/! \/\/! \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u043e\u0439, \u0440\u0430\u0441\u0447\u0451\u0442\u043e\u043c, \u043e\u0442\u043c\u0435\u043d\u043e\u0439, \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u043e\u043c.  use crate::shared::{Address, Weight, Money, DeliveryId, ReservationId, OrderId, WarehouseId, CustomerId}; use uuid::Uuid; use time::OffsetDateTime;  #[derive(Debug, Clone)] pub struct DeliveryRequest {     pub address: Address,     pub items: Vec&lt;(ProductId, Weight)&gt;,     pub priority: Priority, }  #[derive(Debug, Clone, serde::Serialize)] pub struct ShippingOptions {     pub cost: Money,     pub warehouse_id: WarehouseId,     pub estimated_days: u32,     pub carrier: Carrier, }  #[derive(Debug, Clone, serde::Serialize)] pub struct CancellationFee {     pub amount: Money,     pub reason: String, }  #[derive(Debug, Clone, serde::Serialize)] pub struct ReturnLabel {     pub tracking_number: String,     pub carrier: Carrier,     pub expires_at: OffsetDateTime, }  #[derive(Debug, Clone, PartialEq)] pub enum Carrier {     DHL,     FedEx,     UPS, }  #[derive(Debug, Clone, PartialEq)] pub enum Priority {     Low,     Normal,     High, }  #[derive(Debug, Clone, PartialEq)] pub enum DeliveryStatus {     Pending,     InTransit,     Delivered, }  \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \/\/ \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 pub fn calculate_shipping(request: DeliveryRequest) -&gt; Result&lt;ShippingOptions, DeliveryError&gt; {     Ok(ShippingOptions {         cost: rust_decimal_macros::dec!(10.00),         warehouse_id: Uuid::new_v4(),         estimated_days: 3,         carrier: Carrier::DHL,     }) }  pub fn schedule_delivery(order_id: OrderId, option:<\/code><\/pre>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\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-470839","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/470839","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=470839"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/470839\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=470839"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=470839"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=470839"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}