{"id":369232,"date":"2024-05-21T03:58:53","date_gmt":"2024-05-21T03:58:53","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=369232"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=369232","title":{"rendered":"<span>\u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u043d\u043e\u0433\u043e PHP \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/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<h2>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0421\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0441\u0430\u043c \u043f\u043e \u0441\u0435\u0431\u0435 \u043c\u043e\u043d\u043e\u043b\u0438\u0442 \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u043d\u0442\u0438\u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u043c \u0438 \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c (\u0438 \u0447\u0430\u0441\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442) \u043f\u0440\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445, \u043e\u0431\u044b\u0447\u043d\u043e &#8212; \u043a\u043e\u0433\u0434\u0430 \u043e\u043d \u0432\u044b\u0431\u0440\u0430\u043d \u043e\u0441\u043e\u0437\u043d\u0430\u043d\u043d\u043e. \u041d\u043e \u0447\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043d\u0435 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043b\u044e\u0434\u0438 \u0435\u0451 \u0432\u044b\u0431\u0440\u0430\u043b\u0438, \u0430 \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 \u043d\u0435\u0451 \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u044d\u0432\u043e\u043b\u044e\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043b.<\/p>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u044f\u0441\u043d\u0438\u043c, \u0447\u0442\u043e \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u0432 \u0432\u0438\u0434\u0443 \u043f\u043e\u0434 &#171;\u0434\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0435\u0439 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430&#187;. \u041a\u0430\u043a\u0430\u044f \u043d\u0430\u0448\u0430 \u043a\u043e\u043d\u0435\u0447\u043d\u0430\u044f \u0446\u0435\u043b\u044c? \u041a\u0430\u043a\u0438\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c <em>\u0431\u0438\u0437\u043d\u0435\u0441-\u0446\u0435\u043b\u0438<\/em>, \u043f\u043e\u0431\u0443\u0436\u0434\u0430\u044e\u0449\u0438\u0435 \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043e\u0432 \u0440\u0435\u0448\u0430\u0442\u044c \u044d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443?<\/p>\n<ol>\n<li>\n<p>\u041c\u0435\u0434\u043b\u0435\u043d\u043d\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u042d\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0438\u0437-\u0437\u0430 \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u0438 (coupling) \u043a\u043e\u0434\u0430, \u0447\u0442\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f:<\/p>\n<ol>\n<li>\n<p>\u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0437\u0430\u043f\u0443\u0442\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 (\u0435\u0441\u0442\u044c \u0432\u0430\u0436\u043d\u0430\u044f<a href=\"https:\/\/dev.to\/maurofrezza\/complex-software-vs-complicated-software-cid\" rel=\"noopener noreferrer nofollow\"> <u>\u0440\u0430\u0437\u043d\u0438\u0446\u0430<\/u><\/a> \u043c\u0435\u0436\u0434\u0443 \u0441\u043b\u043e\u0436\u043d\u044b\u043c (complex) \u0438 \u0437\u0430\u043f\u0443\u0442\u0430\u043d\u043d\u044b\u043c (complicated) \u043a\u043e\u0434\u043e\u043c).<\/p>\n<\/li>\n<li>\n<p>\u0447\u0430\u0441\u0442\u0438 \u043a\u043e\u0434\u0430 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430, \u0447\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0431\u043e\u043b\u0435\u0435 \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432 \u0438 \u043f\u043e\u0432\u044b\u0448\u0430\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u043d\u0430\u0434\u043b\u0435\u0436\u0430\u0449\u0435\u0433\u043e CI\\CD \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0441\u0434\u0432\u0438\u0433\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0438\u043b\u0438 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a) \u043f\u043e\u0447\u0442\u0438 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b \u0438\u0437-\u0437\u0430 \u0432\u044b\u0441\u043e\u043a\u0438\u0445 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u0442\u0440\u0430\u0442.<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p>\u041c\u043e\u043d\u043e\u043b\u0438\u0442 \u043a\u0430\u043a<a href=\"https:\/\/en.wikipedia.org\/wiki\/Single_point_of_failure\" rel=\"noopener noreferrer nofollow\"> <u>\u0435\u0434\u0438\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u043e\u0442\u043a\u0430\u0437\u0430<\/u><\/a> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u0440\u0438\u0441\u043a\u043e\u043c.<\/p>\n<\/li>\n<li>\n<p>\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u043c.<\/p>\n<\/li>\n<\/ol>\n<p>\u0423\u0447\u0438\u0442\u044b\u0432\u0430\u044f \u0432\u044b\u0448\u0435\u0438\u0437\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0435, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0439 \u0446\u0435\u043b\u044c\u044e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <strong>\u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043a \u0431\u043e\u043b\u0435\u0435 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/strong> \u0434\u043b\u044f \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043d\u0438\u0436\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d\u044b\u0445 \u0440\u0438\u0441\u043a\u043e\u0432.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0438 \u0446\u0435\u043b\u044c, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0432\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u043f\u043b\u0430\u043d.<\/p>\n<h2>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h2>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0435\u0434\u044b. \u0414\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u043e\u043d\u043e \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438, \u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0439 \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438 \u0438 \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0443\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0449\u0435 \u043f\u043e\u043d\u044f\u0442\u044c \u043f\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0435:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/88d\/24b\/d0d\/88d24bd0db970edc71ad01fe4f5a5f2a.png\" alt=\"\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0435\u0434\u044b\" title=\"\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0435\u0434\u044b\" width=\"642\" height=\"681\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/88d\/24b\/d0d\/88d24bd0db970edc71ad01fe4f5a5f2a.png\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0435\u0434\u044b<\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u0438\u043f\u0438\u0447\u043d\u044b\u0439 flow \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439: customer \u0434\u0435\u043b\u0430\u0435\u0442 \u0437\u0430\u043a\u0430\u0437 (create order), \u0441\u043e\u0432\u0435\u0440\u0448\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a restaurant service, \u0438 \u0435\u0441\u043b\u0438 \u0437\u0430\u043a\u0430\u0437 \u043f\u0440\u0438\u043d\u044f\u0442, \u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 (delivery) \u0438 \u043e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u0443\u0440\u044c\u0435\u0440. \u041a\u043e\u0433\u0434\u0430 \u043a\u0443\u0440\u044c\u0435\u0440 \u043d\u0430\u0439\u0434\u0435\u043d, \u043e\u043d \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u043e\u0439 \u0447\u0435\u0440\u0435\u0437 \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 (change delivery status): <code>courier_assigned<\/code> -> <code>courier_delivering<\/code> -> <code>successful<\/code>. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0442\u0440\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 (customer, courier, restaurant), \u0430 \u0442\u0430\u043a\u0436\u0435 \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f orders \u0438 deliveries. \u0412 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438, \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a \u043c\u043e\u043d\u043e\u043b\u0438\u0442 \u0441 \u043b\u0438\u0448\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435\u043c \u043d\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u0432.<\/p>\n<p>\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f: <a href=\"https:\/\/github.com\/ilyachase\/monolith-decoupling-example\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/github.com\/ilyachase\/monolith-decoupling-example<\/u><\/a><\/p>\n<h2>\u0412\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u043f\u043b\u0430\u043d<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u043e\u044f\u0441\u043d\u0438\u043c \u0442\u043e, \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043c\u044b \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u00ab\u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c\u00bb \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b:<\/p>\n<ol>\n<li>\n<p>\u041d\u0435 \u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0432 \u043d\u0430\u0448\u0435\u043c \u043a\u043e\u0434\u0435 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0435 service classes, \u043e\u043d\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0442 \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c <em>\u043f\u0440\u044f\u043c\u044b\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u043e\u0432<\/em>. <\/p>\n<\/li>\n<li>\n<p>\u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043c\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c, \u043c\u044b \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u043c \u0438\u0437\u0432\u043b\u0435\u0447\u044c, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e (\u0447\u0435\u0440\u0435\u0437 \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0435 \u0441\u043b\u043e\u0432\u043e <code>use<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u0432\u0441\u0435 service classes \u0438\u043c\u0435\u044e\u0442 \u0434\u043e\u0441\u0442\u0443\u043f <em>\u043a\u043e \u0432\u0441\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u043c<\/em> \u0432 \u0431\u0430\u0437\u0435, \u0430 \u0437\u043d\u0430\u0447\u0438\u0442, \u043d\u0435\u0442 \u0433\u0440\u0430\u043d\u0438\u0446 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043c\u044b \u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043c\u043d\u043e\u0433\u043e \u0443\u0441\u0438\u043b\u0438\u0439. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c <em>\u0438\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u043c<\/em> \u0438 <em>\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u043c<\/em>. \u0421 \u044d\u0442\u043e\u0439 \u0446\u0435\u043b\u044c\u044e \u043c\u044b \u0432\u043d\u0435\u0434\u0440\u0438\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0448\u0430\u0433 \u043f\u0435\u0440\u0435\u0434 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u043c \u043a \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c &#8212; \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u043c \u043d\u0430\u0448 \u043c\u043e\u043d\u043e\u043b\u0438\u0442 \u0432 <strong>\u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u043d\u043e\u043b\u0438\u0442<\/strong>.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u0432\u0435\u0434\u0435\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u044f. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0447\u0430\u0441\u0442\u044c \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043e\u0434\u0430 \u043c\u043e\u0434\u0443\u043b\u0435\u043c \u0442\u043e\u0433\u0434\u0430 \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u0442\u044c \u0434\u0432\u0443\u043c \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u043c:<\/p>\n<ol>\n<li>\n<p>\u0420\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u0434\u0430. \u041c\u043e\u0434\u0443\u043b\u0438 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u0440\u0443\u0433\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e. \u041a\u043e\u0433\u0434\u0430 \u043c\u043e\u0434\u0443\u043b\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0439 \u043c\u043e\u0434\u0443\u043b\u044c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <em>service client<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u041a\u0430\u0436\u0434\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<\/ol>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435:<\/p>\n<ul>\n<li>\n<p><em>\u041c\u043e\u0434\u0443\u043b\u0438 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u0440\u0443\u0433\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e.<\/em> \u0427\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430, \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <a href=\"https:\/\/github.com\/qossmic\/deptrac\" rel=\"noopener noreferrer nofollow\"><u>Deptrac<\/u><\/a>. \u042d\u0442\u043e \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e: \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e <code>deptrac.yaml<\/code>), \u0432 \u043d\u0435\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u0438 \u0438 \u0434\u0430\u043b\u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0439 \u0444\u0430\u0439\u043b \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f \u0433\u0440\u0430\u043d\u0438\u0446. \u0427\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043e, \u0437\u0430\u043f\u0443\u0441\u043a \u044d\u0442\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 CI\\CD (<a href=\"https:\/\/github.com\/features\/actions\" rel=\"noopener noreferrer nofollow\"><u>GitHub actions<\/u><\/a> \u0438\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435). \u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0434\u0430\u043d\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0431\u044b\u043b\u0430 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 (required).<\/p>\n<\/li>\n<li>\n<p><em>\u041a\u043e\u0433\u0434\u0430 \u043e\u0434\u043d\u043e\u043c\u0443 \u043c\u043e\u0434\u0443\u043b\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0439 \u043c\u043e\u0434\u0443\u043b\u044c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f service client.<\/em> \u0418\u0434\u0435\u044f \u043f\u0440\u043e\u0441\u0442\u0430: \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u0441\u0440\u0430\u0437\u0443 \u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 &#8212; \u043e\u0431\u044b\u0447\u043d\u043e \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0441\u043a\u0430\u0447\u043e\u043a, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u043a\u043e\u0434, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <a href=\"https:\/\/symfony.com\/doc\/current\/components\/http_kernel.html#sub-requests\" rel=\"noopener noreferrer nofollow\"><u>sub-requests<\/u><\/a> \u0432\u043c\u0435\u0441\u0442\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. Service client &#8212; \u044d\u0442\u043e \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0435\u0433\u043e \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0442\u0432\u0435\u0442. \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435.<\/p>\n<\/li>\n<li>\n<p><em>\u041a\u0430\u0436\u0434\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445.<\/em> \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 <a href=\"https:\/\/microservices.io\/patterns\/data\/database-per-service.html\" rel=\"noopener noreferrer nofollow\"><u>\u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445<\/u><\/a>, \u0438 \u00abdatabase per service\u00bb \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043d\u0438\u0445. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<\/ul>\n<p>\u0423\u0447\u0438\u0442\u044b\u0432\u0430\u044f \u0432\u044b\u0448\u0435\u0441\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u044d\u0442\u0430\u043f\u044b \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/82d\/52e\/219\/82d52e2190d09a6efc4cae679892b8bd.png\" alt=\"\u042d\u0442\u0430\u043f\u044b \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b\" title=\"\u042d\u0442\u0430\u043f\u044b \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b\" width=\"1063\" height=\"383\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/82d\/52e\/219\/82d52e2190d09a6efc4cae679892b8bd.png\"\/><\/p>\n<div><figcaption>\u042d\u0442\u0430\u043f\u044b \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/figcaption><\/div>\n<\/figure>\n<p>\u041d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e event-driven \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u0441 <a href=\"https:\/\/blog.christianposta.com\/microservices\/the-hardest-part-about-microservices-data\/\" rel=\"noopener noreferrer nofollow\"><u>event streams<\/u><\/a>, <a href=\"https:\/\/teivah.medium.com\/why-is-a-canonical-data-model-an-anti-pattern-441b5c4cbff8\" rel=\"noopener noreferrer nofollow\"><u>bounded context models<\/u><\/a>, <a href=\"https:\/\/debezium.io\/blog\/2019\/02\/19\/reliable-microservices-data-exchange-with-the-outbox-pattern\/\" rel=\"noopener noreferrer nofollow\"><u>outbox pattern<\/u><\/a> \u0438 \u0442.\u0434. (\u043f\u043e\u044d\u0442\u043e\u043c\u0443, \u043e\u043d \u043f\u043e\u0434 \u0437\u0432\u0435\u0437\u0434\u043e\u0447\u043a\u043e\u0439). \u041e\u0434\u043d\u0430\u043a\u043e, \u043c\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u0441\u043f\u043e\u0441\u043e\u0431 \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0442.\u043a. \u044d\u0442\u043e \u0442\u0438\u043f\u0438\u0447\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043f\u0440\u0435\u0442\u0435\u0440\u043f\u0435\u0432\u0430\u044e\u0449\u0438\u0445 \u0442\u0430\u043a\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u044d\u0432\u043e\u043b\u044e\u0446\u0438\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u0430 \u0437\u043d\u0430\u0447\u0438\u0442, \u0441\u0442\u043e\u0438\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u044d\u0442\u043e \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h2>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043c\u044b \u043d\u0430\u0447\u043d\u0435\u043c, \u043d\u0435 \u043c\u043e\u0433\u0443 \u043d\u0435 \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u044c \u0432\u0430\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u0442\u0435\u0441\u0442\u0430\u043c\u0438. \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438, \u043d\u043e \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u043f\u0435\u0440\u0432\u044b\u043c \u0448\u0430\u0433\u043e\u043c \u043f\u0435\u0440\u0435\u0434 \u043b\u044e\u0431\u044b\u043c\u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u043c\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c\u0438 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043b\u043e\u044f \u0442\u0435\u0441\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043d\u0430 near-HTTP \u0443\u0440\u043e\u0432\u043d\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"https:\/\/symfony.com\/doc\/current\/testing.html#application-tests\" rel=\"noopener noreferrer nofollow\"><u>Application tests<\/u><\/a> \u0432 Symfony), \u0438\u043b\u0438 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435 e2e \u0442\u0435\u0441\u0442\u044b.<\/p>\n<h3>\u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u043e\u0442 big ball of mud \u043a modular monolith<\/h3>\n<h4>\u0413\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432<\/h4>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0433\u0440\u0430\u043d\u0438\u0446\u044b \u043c\u0435\u0436\u0434\u0443 \u0447\u0430\u0441\u0442\u044f\u043c\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041e\u043d\u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 (Customer, Restaurant \u0438 Courier), \u043d\u043e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f \u043b\u0438\u0431\u043e \u0437\u0434\u0440\u0430\u0432\u044b\u0439 \u0441\u043c\u044b\u0441\u043b, \u043b\u0438\u0431\u043e \u043d\u0430 Domain Driven Design \u043a\u0430\u043a \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434. \u041d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0432 \u043d\u0430\u0447\u0430\u043b\u0435, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044d\u0442\u043e \u0432\u043b\u0435\u0447\u0435\u0442 \u0437\u0430 \u0441\u043e\u0431\u043e\u0439 \u0431\u043e\u043b\u0435\u0435 \u0432\u044b\u0441\u043e\u043a\u0438\u0439 maintenance cost. \u0418\u0437 <a href=\"https:\/\/cloud.google.com\/architecture\/microservices-architecture-refactoring-monoliths\" rel=\"noopener noreferrer nofollow\"><u>\u0441\u0442\u0430\u0442\u044c\u0438 \u043e\u0442 Google<\/u><\/a>:<\/p>\n<blockquote>\n<p><em>We recommend that you create larger services instead of smaller services until you thoroughly understand the domain.<\/em><\/p>\n<\/blockquote>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0433\u0440\u0430\u043d\u0438\u0446\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b, \u043f\u0435\u0440\u0432\u044b\u043c \u0448\u0430\u0433\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438, \u043f\u043e\u043a\u0430 <strong>\u0431\u0435\u0437 \u0440\u0430\u0441\u043f\u0443\u0442\u044b\u0432\u0430\u043d\u0438\u044f<\/strong> \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 (as is). \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0444\u0430\u0439\u043b\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443:<\/p>\n<pre><code>src\/    Controller\/        CourierApiController.php        CustomerApiController.php    Dto\/        ChangeDeliveryStatusRequest.php        CreateOrderRequest.php    Entity\/        Delivery.php        Order.php        Restaurant.php    Repository\/        DeliveryRepository.php        OrderRepository.php        RestaurantRepository.php    Service\/        CourierService.php        CustomerService.php        RestaurantService.php<\/code><\/pre>\n<p>\u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u044b\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0439, \u0440\u0435\u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u043d\u0430\u0448\u0438 \u043c\u043e\u0434\u0443\u043b\u0438, \u0430 \u0444\u0430\u0439\u043b\u044b, \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u043d\u043e\u0441\u0442\u044c \u043a \u043c\u043e\u0434\u0443\u043b\u044f\u043c \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u0430, \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u043c \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 <code>Common<\/code>:<\/p>\n<pre><code>src\/    Customer\/   &lt;-- module level directory        Controller\/            CustomerApiController.php        Dto\/            CreateOrderRequest.php        Entity\/            Order.php        Repository\/            OrderRepository.php        Service\/            CustomerService.php    Restaurant\/   &lt;-- module level directory        Entity\/            Restaurant.php        Repository\/            RestaurantRepository.php        Service\/            RestaurantService.php    Courier\/      &lt;-- module level directory        Controller\/            CourierApiController.php        Dto\/            ChangeDeliveryStatusRequest.php        Entity\/            Delivery.php        Repository\/            DeliveryRepository.php        Service\/            CourierService.php    Common\/        Exception\/            EntityNotFoundException.php<\/code><\/pre>\n<p>\u0421\u043e\u0432\u0435\u0442: \u0435\u0441\u043b\u0438 \u0432\u0430\u0448\u0430 IDE \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 PSR namespaces, \u043e\u043d\u0430 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0432\u0430\u043c \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043a\u043b\u0430\u0441\u0441\u044b \u043f\u0440\u0438 \u0438\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, PhpStorm <a href=\"https:\/\/www.jetbrains.com\/help\/phpstorm\/tutorial-moving-php-classes.html#a00632a\" rel=\"noopener noreferrer nofollow\"><u>\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442<\/u><\/a> \u0435\u0433\u043e \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438, \u0435\u0441\u043b\u0438 \u0432\u044b <a href=\"https:\/\/www.jetbrains.com\/help\/phpstorm\/composer-page.html\" rel=\"noopener noreferrer nofollow\"><u>\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0435<\/u><\/a> \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 IDE \u0441 Composer.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0438 Symfony \u0434\u043b\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u043d\u0430\u0448\u0435\u0439 \u043d\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b:<\/p>\n<pre><code class=\"diff\"># config\/packages\/doctrine.yaml         naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware         auto_mapping: true         mappings: -            App: +            App\\Courier: +                is_bundle: false +                dir: '%kernel.project_dir%\/src\/Courier\/Entity' +                prefix: 'App\\Courier\\Entity' +                alias: App\\Courier +            App\\Customer:                 is_bundle: false -                dir: '%kernel.project_dir%\/src\/Entity' -                prefix: 'App\\Entity' -                alias: App +                dir: '%kernel.project_dir%\/src\/Customer\/Entity' +                prefix: 'App\\Customer\\Entity' +                alias: App\\Customer +            App\\Restaurant: +                is_bundle: false +                dir: '%kernel.project_dir%\/src\/Restaurant\/Entity' +                prefix: 'App\\Restaurant\\Entity' +                alias: App\\Restaurant  # config\/routes.yaml -controllers: +courier_controllers:     resource: -        path: ..\/src\/Controller\/ -        namespace: App\\Controller +        path: ..\/src\/Courier\/Controller\/ +        namespace: App\\Courier\\Controller +    type: attribute +customer_controllers: +    resource: +        path: ..\/src\/Customer\/Controller\/ +        namespace: App\\Customer\\Controller     type: attribute<\/code><\/pre>\n<p>\u0421\u043e\u0432\u0435\u0442: \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u044d\u0442\u043e\u0442 \u0448\u0430\u0433 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 PR, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u043d \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0441\u0442\u0430\u043d\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 <strong>\u0438\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u043c<\/strong> \u0438 <strong>\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u043c<\/strong>.<\/p>\n<h4>\u0420\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445<\/h4>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0444\u0430\u0439\u043b\u044b \u0441\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u043f\u043e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f\u043c\u0438, \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0448\u0430\u0433\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u043a\u0430\u043a\u0438\u043c \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435:<\/p>\n<ul>\n<li>\n<p>\u0411\u0430\u0437\u0430 <code>customer<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 <code>order<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0411\u0430\u0437\u0430 <code>restaurant<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 <code>restaurant<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0411\u0430\u0437\u0430 <code>courier<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 <code>delivery<\/code>.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043d\u0435 \u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0433\u0440\u0430\u043d\u0438\u0446\u044b \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 &#8212; \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0431\u043e\u043b\u044c\u0448\u0435 \u0443\u0441\u0438\u043b\u0438\u0439 \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u0448\u0438\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u043a \u043a\u0430\u043a\u0438\u043c \u043c\u043e\u0434\u0443\u043b\u044f\u043c. \u041e\u0434\u043d\u0430\u043a\u043e \u0432\u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0435\u0436\u043d\u0435\u0439 \u2014 \u0441\u0443\u0442\u044c \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u0443\u044e \u00ab\u0433\u043e\u0440\u044f\u0447\u0443\u044e \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e\u00bb (hot migration) \u043a\u0430\u0436\u0434\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043f\u043e \u043e\u0447\u0435\u0440\u0435\u0434\u0438: \u0432 \u043a\u043e\u0434\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0435\u0449\u0451 \u043e\u0434\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043e\u0431\u0430 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430, \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e, \u0430 \u0447\u0442\u0435\u043d\u0438\u0435 &#8212; \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u0441\u0442\u0430\u0440\u043e\u0439. \u041f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0441\u0442\u0430\u0440\u043e\u0439 \u0431\u0430\u0437\u044b \u0432 \u043d\u043e\u0432\u0443\u044e. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0434\u0435\u0442\u0430\u043b\u044f\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0433\u043e\u0440\u044f\u0447\u0435\u0439 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 (\u044d\u0442\u043e \u0437\u0430\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438), \u043d\u043e \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439:<\/p>\n<ol>\n<li>\n<p>\u041d\u0430\u0439\u0442\u0438 \u0432 \u043a\u043e\u0434\u0435 \u043c\u0435\u0441\u0442\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u043c\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0430\u0440\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 (\u0432\u0441\u0442\u0430\u0432\u043a\u0430, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435) \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0432 \u043e\u0431\u0435 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0435\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0441\u0442\u0430\u0440\u043e\u0439 \u0431\u0430\u0437\u044b \u0432 \u043d\u043e\u0432\u0443\u044e.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438, \u0437\u0430\u0440\u0435\u043b\u0438\u0437\u0438\u0442\u044c \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 PR, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438, \u0438 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u043e\u0436\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0442\u0430\u0440\u0443\u044e \u0442\u0430\u0431\u043b\u0438\u0446\u0443.<\/p>\n<\/li>\n<\/ol>\n<p>\u041c\u043e\u043c\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c:<\/p>\n<ol>\n<li>\n<p><strong>Joins<\/strong>. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0431\u0430\u0437\u044b, \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f <code>JOIN<\/code> \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u0430. \u0422\u0430\u043a\u0438\u0435 \u043c\u0435\u0441\u0442\u0430 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b.<\/p>\n<\/li>\n<li>\n<p><strong>Foreign keys<\/strong>. \u0421\u0423\u0411\u0414 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u043a\u043e\u043d\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u043a\u043b\u044e\u0447\u0435\u0439, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0431\u0430\u0437\u0430\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u0415\u0441\u043b\u0438 \u0432\u0430\u0448 \u043f\u0440\u043e\u0434\u0443\u043a\u0442 \u043e\u043f\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0442\u0430\u043a\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443, \u0435\u0435 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043a\u043e\u0434\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0421\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0432 highload \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0447\u0430\u0441\u0442\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u043a\u043b\u044e\u0447\u0435\u0439, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0443 \u043d\u0438\u0445 \u0435\u0441\u0442\u044c <a href=\"https:\/\/github.com\/github\/gh-ost\/issues\/331\" rel=\"noopener noreferrer nofollow\"><u>\u0441\u0432\u043e\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b<\/u><\/a>.<\/p>\n<\/li>\n<li>\n<p><strong>Transactions<\/strong>. \u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u044b \u043f\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c \u0431\u0430\u0437\u0430\u043c \u0434\u0430\u043d\u043d\u044b\u0445, \u0421\u0423\u0411\u0414 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441 \u0442\u0430\u043a\u0438\u043c\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f\u043c\u0438. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438, \u0442\u0430\u043a\u0438\u0435 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043b\u0438\u0431\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c, \u043b\u0438\u0431\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435 <a href=\"https:\/\/microservices.io\/patterns\/data\/saga.html\" rel=\"noopener noreferrer nofollow\"><u>saga pattern<\/u><\/a>.<\/p>\n<\/li>\n<\/ol>\n<p>\u041e\u0441\u0442\u0430\u0432\u043b\u044f\u044f \u0432 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0434\u0435\u0442\u0430\u043b\u0438 \u0433\u043e\u0440\u044f\u0447\u0435\u0439 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u0432\u0435\u0441\u0442\u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 Entity managers \u0438 connections:<\/p>\n<pre><code class=\"diff\"># config\/packages\/doctrine.yaml doctrine:     dbal: -        url: '%env(resolve:DATABASE_URL)%' - -        # IMPORTANT: You MUST configure your server version, -        # either here or in the DATABASE_URL env var (see .env file) -        #server_version: '15' - -        profiling_collect_backtrace: '%kernel.debug%' +        connections: +            courier: +                url: '%env(resolve:COURIER_DATABASE_URL)%' +            customer: +                url: '%env(resolve:CUSTOMER_DATABASE_URL)%' +            restaurant: +                url: '%env(resolve:RESTAURANT_DATABASE_URL)%'     orm: -        auto_generate_proxy_classes: true -        enable_lazy_ghost_objects: true -        report_fields_where_declared: true -        validate_xml_mapping: true -        naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware -        auto_mapping: true -        mappings: -            App\\Courier: -                is_bundle: false -                dir: '%kernel.project_dir%\/src\/Courier\/Entity' -                prefix: 'App\\Courier\\Entity' -                alias: App\\Courier -            App\\Customer: -                is_bundle: false -                dir: '%kernel.project_dir%\/src\/Customer\/Entity' -                prefix: 'App\\Customer\\Entity' -                alias: App\\Customer -            App\\Restaurant: -                is_bundle: false -                dir: '%kernel.project_dir%\/src\/Restaurant\/Entity' -                prefix: 'App\\Restaurant\\Entity' -                alias: App\\Restaurant +        entity_managers: +            courier: +                report_fields_where_declared: true +                validate_xml_mapping: true +                connection: courier +                mappings: +                    App\\Courier: +                        is_bundle: false +                        dir: '%kernel.project_dir%\/src\/Courier\/Entity' +                        prefix: 'App\\Courier\\Entity' +                        alias: App\\Courier +            customer: +                report_fields_where_declared: true +                validate_xml_mapping: true +                connection: customer +                mappings: +                    App\\Customer: +                        is_bundle: false +                        dir: '%kernel.project_dir%\/src\/Customer\/Entity' +                        prefix: 'App\\Customer\\Entity' +                        alias: App\\Customer +            restaurant: +                report_fields_where_declared: true +                validate_xml_mapping: true +                connection: restaurant +                mappings: +                    App\\Restaurant: +                        is_bundle: false +                        dir: '%kernel.project_dir%\/src\/Restaurant\/Entity' +                        prefix: 'App\\Restaurant\\Entity' +                        alias: App\\Restaurant  # .env ###> doctrine\/doctrine-bundle ### -DATABASE_URL=\"mysql:\/\/root:${MYSQL_ROOT_PASSWORD}@db:3306\/delivery_service?serverVersion=8.0.33&amp;charset=utf8mb4\" +COURIER_DATABASE_URL=\"mysql:\/\/root:${MYSQL_ROOT_PASSWORD}@db:3306\/courier_service?serverVersion=8.0.33&amp;charset=utf8mb4\" +CUSTOMER_DATABASE_URL=\"mysql:\/\/root:${MYSQL_ROOT_PASSWORD}@db:3306\/customer_service?serverVersion=8.0.33&amp;charset=utf8mb4\" +RESTAURANT_DATABASE_URL=\"mysql:\/\/root:${MYSQL_ROOT_PASSWORD}@db:3306\/restaurant_service?serverVersion=8.0.33&amp;charset=utf8mb4\" ###&lt; doctrine\/doctrine-bundle ###  # config\/doctrine_migrations_courier.yaml +migrations_paths: +  'CourierMigrations': 'src\/Courier\/Migrations'  # config\/doctrine_migrations_customer.yaml +migrations_paths: +  'CustomerMigrations': 'src\/Customer\/Migrations'  # config\/doctrine_migrations_restaurant.yaml +migrations_paths: +  'RestaurantMigrations': 'src\/Restaurant\/Migrations'  # migrate command example: doctrine:migrations:migrate -n --em courier --configuration config\/doctrine_migrations_courier.yaml<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e, \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u043f\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u043a\u043e\u0434\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"diff\"># src\/Customer\/Service\/CustomerService.php     public function __construct(         private RestaurantService $restaurantService,         private CourierService $deliveryService, -        private EntityManagerInterface $entityManager +        private EntityManagerInterface $customerEntityManager     ) {     } ... +        $this->customerEntityManager->persist($newOrder); +        $this->customerEntityManager->flush(); <\/code><\/pre>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u0442\u044c relations \u043c\u0435\u0436\u0434\u0443 entities, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0435\u043f\u0435\u0440\u044c \u043e\u043d\u0438 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0431\u0430\u0437\u0430\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0440\u0430\u0437\u043d\u044b\u043c\u0438 entity managers. \u0421\u0430\u043c\u044b\u0439 <a href=\"https:\/\/stackoverflow.com\/questions\/11463517\/using-relationships-with-multiple-entity-managers\/11494543#11494543\" rel=\"noopener noreferrer nofollow\"><u>\u043f\u0440\u043e\u0441\u0442\u043e\u0439<\/u><\/a> \u0441\u043f\u043e\u0441\u043e\u0431 \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c &#8212; \u043d\u0430\u0447\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"diff\"># src\/Courier\/Entity\/Delivery.php namespace App\\Courier\\Entity;  -use App\\Customer\\Entity\\Order; use App\\Courier\\Repository\\DeliveryRepository; use Doctrine\\ORM\\Mapping as ORM; use Symfony\\Component\\Serializer\\Annotation\\Groups;  #[ORM\\Entity(repositoryClass: DeliveryRepository::class)] class Delivery {     public const STATUS_NEW = 'new'; @@ -28,9 +28,9 @@     #[Groups(['api'])]     private ?string $status = null;  -    #[ORM\\OneToOne(cascade: ['persist', 'remove'])] -    #[ORM\\JoinColumn(nullable: false)] -    private ?Order $RelatedOrder = null; +    #[ORM\\Column(name: 'related_order_id')] +    private ?int $relatedOrderId = null;      public function getId(): ?int     { @@ -49,14 +49,14 @@         return $this;     }  -    public function getRelatedOrder(): ?Order +    public function getRelatedOrderId(): ?int     { -        return $this->RelatedOrder; +        return $this->relatedOrderId;     }  -    public function setRelatedOrder(Order $RelatedOrder): static +    public function setRelatedOrderId(int $relatedOrderId): static     { -        $this->RelatedOrder = $RelatedOrder; +        $this->relatedOrderId = $relatedOrderId;          return $this;     }<\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u0442\u0435, \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u0436\u0435 \u043f\u043e\u0434\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u0442 \u043d\u0430\u0448 \u043a\u043e\u0434 \u0432 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u043e\u0441\u0442\u0438. \u042d\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043c \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0448\u0430\u0433\u0430\u0445.<\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u0434\u0430 \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0448\u0430\u0433\u0430 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c <a href=\"https:\/\/github.com\/ilyachase\/monolith-decoupling-example\/tree\/step2-splt-databases\" rel=\"noopener noreferrer nofollow\"><u>\u0437\u0434\u0435\u0441\u044c<\/u><\/a>.<\/p>\n<h4>\u0418\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0433\u0440\u0430\u043d\u0438\u0446 \u043c\u043e\u0434\u0443\u043b\u0435\u0439<\/h4>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0444\u0430\u0439\u043b\u044b \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u044b \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438, \u0438 \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0430, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u0447\u0430\u0442\u044c \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0441\u0442\u0440\u043e\u0433\u0438\u0435 \u0433\u0440\u0430\u043d\u0438\u0446\u044b \u043c\u0435\u0436\u0434\u0443 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <a href=\"https:\/\/github.com\/qossmic\/deptrac\" rel=\"noopener noreferrer nofollow\"><u>Deptrac<\/u><\/a>: \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 <code>deptrac.yaml<\/code> \u043c\u043e\u0434\u0443\u043b\u0438, \u0430 \u0437\u0430\u0442\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 <code>vendor\/bin\/deptrac<\/code> \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u0433\u0440\u0430\u043d\u0438\u0446 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438. \u042d\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043c \u0432 \u0434\u0432\u0443\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445:<\/p>\n<ul>\n<li>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0444\u0430\u0439\u043b\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u044b \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u0438 \u0432 <code>deptrac.yaml<\/code> \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0439 \u0444\u0430\u0439\u043b deptrac, \u0447\u0442\u043e\u0431\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043f\u043e\u043b\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438 \u0441\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u043f\u043e \u0438\u0445 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0443.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442\u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0435\u043d\u044b, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043a\u043e\u043c\u043c\u0438\u0442\u0438\u0442\u044c \u0444\u0430\u0439\u043b <code>deptrac.yaml<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u044b\u0437\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 deptrac \u0432 CI\\CD, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043d\u0430\u0448\u0438 \u043c\u043e\u0434\u0443\u043b\u0438 \u0432 <code>deptrac.yaml<\/code>:<\/p>\n<pre><code class=\"yaml\">parameters:  paths:    - .\/src  layers:    - name: Common      collectors:        - type: directory          value: src\/Common\/.*    - name: Courier      collectors:        - type: directory          value: src\/Courier\/.*    - name: Customer      collectors:        - type: directory          value: src\/Customer\/.*    - name: Restaurant      collectors:        - type: directory          value: src\/Restaurant\/.*  ruleset:    Courier:      - Common    Customer:      - Common    Restaurant:      - Common<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 <code>vendor\/bin\/deptrac<\/code> \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043e\u0442\u0447\u0435\u0442 \u043e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u0445 \u043c\u0435\u0436\u0434\u0443 \u043d\u0430\u0448\u0438\u043c\u0438 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/73e\/2a0\/db7\/73e2a0db76257f2e0d2ca2dace78cef3.png\" alt=\"\u041e\u0442\u0447\u0435\u0442 Deptrac\" title=\"\u041e\u0442\u0447\u0435\u0442 Deptrac\" width=\"720\" height=\"663\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/73e\/2a0\/db7\/73e2a0db76257f2e0d2ca2dace78cef3.png\"\/><\/p>\n<div><figcaption>\u041e\u0442\u0447\u0435\u0442 Deptrac<\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u043b\u044f \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c service clients \u0438 DTO \u0432 \u043d\u0430\u0448 \u043a\u043e\u0434. \u042d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435 SDK \u0434\u043b\u044f \u043d\u0430\u0448\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u043c \u0432 \u043f\u0430\u043f\u043a\u0443 <code>Common<\/code>. \u0421\u043c\u044b\u0441\u043b \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0441\u043b\u043e\u0439, \u0433\u0434\u0435 \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438, \u0447\u0442\u043e \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u043b\u0435\u0433\u0447\u0435 \u043c\u0435\u043d\u044f\u0442\u044c \u044d\u0442\u043e\u0442 \u0441\u0430\u043c\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0438\u043c \u0431\u0443\u0434\u0443\u0442 \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u044f\u043c\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u0430 \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0441\u0442\u0430\u043d\u0443\u0442 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. \u0422\u0430\u043a\u0436\u0435, \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043c\u043e\u0434\u0443\u043b\u044c <code>Common<\/code> \u043f\u043e\u0437\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Composer.<\/p>\n<p>\u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 service clients \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0438\u0447\u0443 Symfony \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <a href=\"https:\/\/symfony.com\/doc\/current\/components\/http_kernel.html#sub-requests\" rel=\"noopener noreferrer nofollow\"><u>sub-requests<\/u><\/a> \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043f\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0440\u043e\u0443\u0442\u0430\u043c \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0435\u0437 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u043e \u0441\u0435\u0442\u0438. \u0418\u0434\u0435\u044f \u043d\u0435 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u0430 &#8212; \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 Node.js \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <a href=\"https:\/\/github.com\/mcollina\/fastify-undici-dispatcher\" rel=\"noopener noreferrer nofollow\"><u>mcollina\/fastify-undici-dispatcher<\/u><\/a>.<\/p>\n<p>\u0421\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u043e\u0434\u0438\u043d \u043d\u044e\u0430\u043d\u0441 &#8212; sub-requests \u0438\u043c\u0435\u044e\u0442 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043e\u0432\u0435\u0440\u0445\u0435\u0434 \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 \u043f\u0440\u044f\u043c\u044b\u043c\u0438 \u0432\u044b\u0437\u043e\u0432\u0430\u043c\u0438 \u043c\u0435\u0442\u043e\u0434\u043e\u0432. \u041e\u0434\u043d\u0430\u043a\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0441\u0442\u0430\u043b \u0445\u043e\u0442\u044c \u0441\u043a\u043e\u043b\u044c\u043a\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u0437\u0430\u043c\u0435\u0442\u043d\u044b\u043c, \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0432\u0435\u0440\u0448\u0430\u0442\u044c sub-requests \u0442\u044b\u0441\u044f\u0447\u0438 \u0440\u0430\u0437 \u0432 \u0446\u0438\u043a\u043b\u0435, \u0430 \u0435\u0441\u043b\u0438 \u043c\u044b \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043c, \u0447\u0442\u043e \u044d\u0442\u0438 \u0432\u044b\u0437\u043e\u0432\u044b \u043f\u043e\u0437\u0436\u0435 \u0441\u0442\u0430\u043d\u0443\u0442 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438, \u0433\u0434\u0435 \u043e\u0432\u0435\u0440\u0445\u0435\u0434 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u0435, \u0438\u043d\u043e\u0433\u0434\u0430 \u0434\u0430\u0436\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u043c\u0435\u0441\u0442\u0430 \u0438 \u043e\u0442\u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u0442\u044c \u0438\u0445.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u0432\u0435\u0434\u0451\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 service clients:<\/p>\n<pre><code class=\"php\"># src\/Common\/Client\/AbstractSymfonyControllerResolvingClient.php &lt;?php  declare(strict_types=1);  namespace App\\Common\\Client;  use App\\Common\\Exception\\BadPayloadException; use Symfony\\Component\\HttpFoundation\\Request; use Symfony\\Component\\HttpFoundation\\Response; use Symfony\\Component\\HttpKernel\\HttpKernelInterface; use Symfony\\Component\\Serializer\\Encoder\\JsonEncoder; use Symfony\\Component\\Serializer\\Normalizer\\ObjectNormalizer; use Symfony\\Component\\Serializer\\Serializer;  abstract class AbstractSymfonyControllerResolvingClient {    public const IS_INTERNAL_REQUEST_ATTRIBUTE_KEY = 'is-internal-request';     protected readonly Serializer $serializer;     public function __construct(        private readonly HttpKernelInterface $httpKernel,    ) {        $encoders = [new JsonEncoder()];        $normalizers = [new ObjectNormalizer()];         $this->serializer = new Serializer($normalizers, $encoders);    }     protected function sendServiceRequest(        string $uri,        array $query = [],        array $requestBody = [],        string $method = Request::METHOD_GET    ): Response {        foreach ([$query, $requestBody] as $payload) {            $this->validatePayload($payload);        }         $request = new Request(            query: $query,            request: $requestBody,            content: json_encode($requestBody, JSON_THROW_ON_ERROR),        );         $request->setMethod($method);        $request->server->set('REQUEST_URI', $uri);        $request->attributes->set(self::IS_INTERNAL_REQUEST_ATTRIBUTE_KEY, true);         return $this->httpKernel->handle($request, HttpKernelInterface::SUB_REQUEST);    }     private function validatePayload($data): void    {        foreach ($data as $item) {            if (is_array($item)) {                $this->validatePayload($item);            } elseif (!is_scalar($item) &amp;&amp; !is_null($item)) {                throw new BadPayloadException();            }        }    } }<\/code><\/pre>\n<p>\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>validatePayload<\/code>. \u0415\u0433\u043e \u0446\u0435\u043b\u044c &#8212; \u0437\u0430\u043f\u0440\u0435\u0442\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u043d\u0435\u0441\u043a\u0430\u043b\u044f\u0440\u043d\u044b\u0445 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441 sub-requests \u044d\u0442\u043e \u0435\u0449\u0451 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c, \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u044d\u0442\u0443 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0441\u0435\u0439\u0447\u0430\u0441, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u043f\u043b\u0430\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043a HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c.<\/p>\n<p>\u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u044b\u0435 \u0440\u043e\u0443\u0442\u044b Symfony \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c, \u043e\u043d\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0434\u043b\u044f \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u0447\u0435\u0433\u043e \u043c\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u043c. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 Event handler:<\/p>\n<pre><code class=\"php\"># src\/Common\/EventListener\/HideInternalApiListener.php &lt;?php  declare(strict_types=1);  namespace App\\Common\\EventListener;  use App\\Common\\Client\\AbstractSymfonyControllerResolvingClient; use Symfony\\Component\\EventDispatcher\\Attribute\\AsEventListener; use Symfony\\Component\\HttpKernel\\Event\\RequestEvent; use Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;  #[AsEventListener(event: 'kernel.request')] class HideInternalApiListener {    public function onKernelRequest(RequestEvent $event): void    {        $serviceApiUrlPattern = '\/service-';        $comparisonResult = strncmp($event->getRequest()->getPathInfo(), $serviceApiUrlPattern, mb_strlen($serviceApiUrlPattern));        if (0 !== $comparisonResult) {            return;        }         $secretKey = $event->getRequest()->attributes->get(AbstractSymfonyControllerResolvingClient::IS_INTERNAL_REQUEST_ATTRIBUTE_KEY);        if (true !== $secretKey) {            throw new NotFoundHttpException();        }    } }<\/code><\/pre>\n<p>\u041e\u043d \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 URI \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438, \u0435\u0441\u043b\u0438 \u043e\u043d \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 <code>\/service-<\/code> \u0438 \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e <a href=\"https:\/\/symfony.com\/doc\/current\/components\/http_foundation.html#component-foundation-attributes\" rel=\"noopener noreferrer nofollow\"><u>request attribute<\/u><\/a>, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 404.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u0435\u0440\u0432\u044b\u0439 service client:<\/p>\n<pre><code class=\"php\"># src\/Common\/Client\/RestaurantServiceClient.php &lt;?php  declare(strict_types=1);  namespace App\\Common\\Client;  use App\\Common\\Dto\\Order; use App\\Common\\Dto\\Restaurant; use RuntimeException;  class RestaurantServiceClient extends AbstractSymfonyControllerResolvingClient {    public function getRestaurant(int $restaurantId): ?Restaurant    {        $response = $this->sendServiceRequest('\/service-restaurant\/restaurants\/'.$restaurantId);         if (404 === $response->getStatusCode()) {            return null;        }         if (200 !== $response->getStatusCode()) {            throw new RuntimeException('Unexpected response code');        }         return $this->serializer->deserialize($response->getContent(), Restaurant::class, 'json');    }     public function acceptOrder(Order $orderDto): bool    {        $response = $this->sendServiceRequest(            uri: '\/service-restaurant\/order\/actions\/accept',            requestBody: $this->serializer->normalize($orderDto),            method: 'POST'        );         if (200 !== $response->getStatusCode()) {            throw new RuntimeException('Unexpected response code');        }         return $this->serializer->decode(data: $response->getContent(), format: 'json');    } }<\/code><\/pre>\n<p>\u0418 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0435\u0433\u043e \u0432\u043c\u0435\u0441\u0442\u043e \u043f\u0440\u044f\u043c\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430:<\/p>\n<pre><code class=\"diff\"># src\/Customer\/Service\/CustomerService.php readonly class CustomerService {     public function __construct( -        private RestaurantService $restaurantService, -        private CourierService $deliveryService, -        private EntityManagerInterface $entityManager +        private RestaurantServiceClient $restaurantServiceClient, +        private CourierServiceClient $courierServiceClient, +        private EntityManagerInterface $customerEntityManager     ) {     }      public function createOrder(CreateOrderRequest $createOrderRequest): int     { -        if (!($restaurant = $this->restaurantService->getRestaurant($createOrderRequest->getRestaurantId()))) { +        if (!($restaurant = $this->restaurantServiceClient->getRestaurant($createOrderRequest->getRestaurantId()))) {             throw new EntityNotFoundException();         }          $newOrder = (new Order()) -            ->setRestaurant($restaurant) +            ->setRestaurantId($restaurant->getId())             ->setStatus(Order::STATUS_NEW);  -        if ($this->restaurantService->acceptOrder($newOrder)) { +        $this->customerEntityManager->persist($newOrder); +        $this->customerEntityManager->flush(); + +        $orderDto = new OrderDto($newOrder->getId(), $newOrder->getStatus(), $newOrder->getRestaurantId(), $newOrder->getDeliveryId()); + +        if ($this->restaurantServiceClient->acceptOrder($orderDto)) {             $newOrder->setStatus(Order::STATUS_ACCEPTED); -            $newDelivery = $this->deliveryService->createDelivery($newOrder); -            $newOrder->setDelivery($newDelivery); +            $newDelivery = $this->courierServiceClient->createDelivery($orderDto); +            $newOrder->setDeliveryId($newDelivery->getId());         } else {             $newOrder->setStatus(Order::STATUS_DECLINED);         }  -        $this->entityManager->persist($newOrder); -        $this->entityManager->flush(); +        $this->customerEntityManager->persist($newOrder); +        $this->customerEntityManager->flush();          return $newOrder->getId();     } }<\/code><\/pre>\n<p>\u0413\u043e\u0442\u043e\u0432\u043e! \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438\u0437 \u043e\u0442\u0447\u0435\u0442\u0430 Deptrac, \u0441 15 \u0434\u043e 11. \u042d\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u043e \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0433\u0440\u0430\u043d\u0438\u0446\u044b \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438. \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u044e\u0442\u0441\u044f \u0442\u0435\u043c \u0436\u0435 \u043e\u0431\u0440\u0430\u0437\u043e\u043c. \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u043e\u0431\u044b\u0447\u043d\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u044c\u0448\u0435 \u0441\u0438\u043b \u043d\u0430 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432 \u043f\u0430\u043f\u043a\u0443 <code>Common<\/code> \u2014 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, exceptions \u043e\u0431\u0449\u0435\u0433\u043e \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0430, DTO, helpers \u0438 \u0442. \u0434. \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0441\u043e\u043c\u043d\u0435\u043d\u0438\u044f, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0432 \u044d\u0442\u043e\u0442 \u043d\u0435\u0439\u043c\u0441\u043f\u0435\u0439\u0441, \u0430 \u0437\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0441\u0435\u0440\u0432\u0438\u0441.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0432\u0441\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442\u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0435\u043d\u044b, \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0437\u0430\u043a\u043e\u043c\u043c\u0438\u0442\u0438\u0442\u044c \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 <code>deptrac.yaml<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0448\u0430\u0433 \u0432 \u0432\u0430\u0448\u0435\u043c CI\\CD, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c\u0441\u044f \u043e\u0442\u0441\u0442\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/685\/43d\/20c\/68543d20cae4622d9f79b8b8eb50ec33.png\" alt=\"\u0427\u0438\u0441\u0442\u044b\u0439 \u043e\u0442\u0447\u0435\u0442 Deptrac\" title=\"\u0427\u0438\u0441\u0442\u044b\u0439 \u043e\u0442\u0447\u0435\u0442 Deptrac\" width=\"348\" height=\"289\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/685\/43d\/20c\/68543d20cae4622d9f79b8b8eb50ec33.png\"\/><\/p>\n<div><figcaption>\u0427\u0438\u0441\u0442\u044b\u0439 \u043e\u0442\u0447\u0435\u0442 Deptrac<\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u0434\u0430 \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0448\u0430\u0433\u0430 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c <a href=\"https:\/\/github.com\/ilyachase\/monolith-decoupling-example\/tree\/step3-enforcing-modules-boundaries\" rel=\"noopener noreferrer nofollow\"><u>\u0437\u0434\u0435\u0441\u044c<\/u><\/a>.<\/p>\n<h2>\u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u043e\u0442 modular monolith \u043a service-oriented architecture<\/h2>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043c\u043e\u0434\u0443\u043b\u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u044b, \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043a \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u044b\u043c. \u0420\u0430\u0434\u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043b \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0438, \u0437\u0430\u0442\u0435\u043c \u0443\u0434\u0430\u043b\u0438\u043b \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u0438\u0437 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0438 \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u043b \u043f\u0430\u0440\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u043e\u0432. \u0412\u043e\u0442 \u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430:<\/p>\n<pre><code>courier-service\/  &lt;-- Separate service level (complete Symfony application)  src\/    Courier\/      &lt;-- Single module inside an application  ... customer-service\/  src\/    Customer\/  ...  deployment        &lt;-- Infrastructure configurations (e.g. Nginx config) restaurant-service\/  src\/    Restaurant\/  ... .env docker-compose.override.yml docker-compose.yml Dockerfile LICENSE Makefile README.md<\/code><\/pre>\n<p>\u041d\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044f\u0442\u044c \u0432\u0441\u0435 \u043c\u0435\u043b\u043a\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b\u0430\u0445 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u043d\u043e \u0432\u044b\u0434\u0435\u043b\u044e \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f Nginx \u0434\u043b\u044f \u0442\u0430\u043a\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b:<\/p>\n<pre><code class=\"nginx\"># deployment\/nginx\/default.nginx map $request_uri $upstream {    default       invalid;    ~^\/api\/customer\/   customer-service;    ~^\/api\/courier\/   courier-service;    ~^\/api\/restaurant\/   restaurant-service; }  upstream customer-service {    server customer-service:9000; }  upstream courier-service {    server courier-service:9000; }  upstream restaurant-service {    server restaurant-service:9000; }  server {    listen 80 default_server;    root \/usr\/share\/app\/$upstream\/public;     location \/api\/ {        try_files $uri \/index.php$is_args$args;    }     location ~ ^\/index\\.php(\/|$) {        fastcgi_pass $upstream;        fastcgi_split_path_info ^(.+\\.php)(\/.*)$;        include fastcgi_params;         fastcgi_param SCRIPT_FILENAME \/usr\/share\/app\/public$fastcgi_script_name;        fastcgi_param DOCUMENT_ROOT \/usr\/share\/app\/public;         internal;    }     location ~ \\.php$ {        return 404;    }     error_log \/var\/log\/nginx\/error.log;    access_log \/var\/log\/nginx\/access.log; }<\/code><\/pre>\n<p>\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 upstreams \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0431\u043b\u043e\u043a \u0432\u044b\u0431\u043e\u0440\u0430 upstream \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 URI \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<p>\u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043e\u0442 sub-requests \u043a \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c <code>symfony\/http-client<\/code> \u0432 \u043d\u0430\u0448\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u044b, \u0430 \u0437\u0430\u0442\u0435\u043c \u0441\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 service clients, \u0441\u0430\u043c\u0438 service clients \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 API \u0441\u0435\u0440\u0432\u0438\u0441\u0430:<\/p>\n<pre><code class=\"diff\"># restaurant-service\/src\/Common\/Client\/AbstractSymfonyControllerResolvingClient.php -abstract class AbstractSymfonyControllerResolvingClient +abstract class AbstractHttpClient { -    public const IS_INTERNAL_REQUEST_ATTRIBUTE_KEY = 'is-internal-request'; -     protected readonly Serializer $serializer;      public function __construct( -        private readonly HttpKernelInterface $httpKernel, +        private readonly HttpClientInterface $client, +        #[Autowire('%api.secret.key%')] +        private readonly string $apiSecretKey,     ) {         $encoders = [new JsonEncoder()];         $normalizers = [new ObjectNormalizer()]; @@ -32,22 +33,23 @@         array $query = [],         array $requestBody = [],         string $method = Request::METHOD_GET -    ): Response { +    ): ResponseInterface {         foreach ([$query, $requestBody] as $payload) {             $this->validatePayload($payload);         }  -        $request = new Request( -            query: $query, -            request: $requestBody, -            content: json_encode($requestBody, JSON_THROW_ON_ERROR), +        return $this->client->request( +            $method, +            'http:\/\/nginx\/api\/'.$this->getServiceName().$uri, +            [ +                'query' => $query, +                'body' => $this->serializer->serialize($requestBody, JsonEncoder::FORMAT), +                'headers' => [ +                    'Content-Type' => 'application\/json', +                    'X-Api-Secret' => $this->apiSecretKey, +                ], +            ]         ); - -        $request->setMethod($method); -        $request->server->set('REQUEST_URI', $uri); -        $request->attributes->set(self::IS_INTERNAL_REQUEST_ATTRIBUTE_KEY, true); - -        return $this->httpKernel->handle($request, HttpKernelInterface::SUB_REQUEST);     }      private function validatePayload($data): void @@ -60,4 +62,6 @@             }         }     } + +    abstract protected function getServiceName(): string; }  # courier-service\/src\/Common\/Client\/CustomerServiceClient.php -class CustomerServiceClient extends AbstractSymfonyControllerResolvingClient +class CustomerServiceClient extends AbstractHttpClient {     public function changeOrderStatus(int $orderId, string $newOrderStatus): void     { @@ -23,4 +23,9 @@             throw new RuntimeException('Unexpected response code');         }     } + +    protected function getServiceName(): string +    { +        return 'customer'; +    } }  # customer-service\/src\/Customer\/Controller\/ServiceApiController.php +#[Route('\/api\/customer')] class ServiceApiController extends AbstractController {     #[Route('\/service-customer\/orders', methods: 'POST')]<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u0443\u0448\u043b\u0438 \u043e\u0442 sub-requests, \u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c request attributes Symfony \u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b \u043d\u0430\u0448\u0438\u0445 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0434\u0440\u0443\u0433\u043e\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c. \u0414\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0441\u0435\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c, \u0430 \u0437\u0430\u0442\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c \u0436\u0435 <code>HideInternalApiListener<\/code>:<\/p>\n<pre><code class=\"diff\"># courier-service\/config\/services.yaml parameters: +    api.secret.key: '%env(API_SECRET_KEY)%'  # courier-service\/.env +API_SECRET_KEY=539afcb6-1897-4204-a552-f2c7b8fc35d2  # customer-service\/src\/Common\/EventListener\/HideInternalApiListener.php #[AsEventListener(event: 'kernel.request')] -class HideInternalApiListener +readonly class HideInternalApiListener { +    public function __construct( +        #[Autowire('%api.secret.key%')] +        private string $apiSecretKey, +    ) { +    } +     public function onKernelRequest(RequestEvent $event): void     { -        $serviceApiUrlPattern = '\/service-'; +        $serviceApiUrlPattern = '\/api\/customer\/service-customer\/';         $comparisonResult = strncmp($event->getRequest()->getPathInfo(), $serviceApiUrlPattern, mb_strlen($serviceApiUrlPattern));         if (0 !== $comparisonResult) {             return;         }  -        $secretKey = $event->getRequest()->attributes->get(AbstractSymfonyControllerResolvingClient::IS_INTERNAL_REQUEST_ATTRIBUTE_KEY); -        if (true !== $secretKey) { +        $apiSecret = $event->getRequest()->headers->get('X-Api-Secret'); +        if ($this->apiSecretKey !== $apiSecret) {             throw new NotFoundHttpException();         }     }<\/code><\/pre>\n<p>\u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u044d\u0442\u043e \u043d\u0435 production-ready \u043a\u043e\u0434, \u043d\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430. \u041b\u0443\u0447\u0448\u0438\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u043c \u0431\u044b\u043b\u0430 \u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f <a href=\"https:\/\/jwt.io\/\" rel=\"noopener noreferrer nofollow\"><u>JWT<\/u><\/a> \u0434\u043b\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u0434\u0430 \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0448\u0430\u0433\u0430 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c <a href=\"https:\/\/github.com\/ilyachase\/monolith-decoupling-example\/tree\/step4-services\" rel=\"noopener noreferrer nofollow\"><u>\u0437\u0434\u0435\u0441\u044c<\/u><\/a>.<\/p>\n<h2>\u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u043e\u0442 service-oriented \u043a event-driven architecture<\/h2>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u043d\u0430\u0448\u0443 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0430 \u0441\u0442\u0430\u043b\u0430 \u0431\u043b\u0438\u0436\u0435 \u043a event-driven. \u042f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0442\u0430\u043a\u0443\u044e \u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u043a\u0443, \u043f\u043e\u0442\u043e\u043c\u0443 \u043a\u0430\u043a \u0443\u0436\u0435 \u0433\u043e\u0432\u043e\u0440\u0438\u043b\u043e\u0441\u044c \u0440\u0430\u043d\u044c\u0448\u0435, \u043c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0441\u0438\u043b\u044c\u043d\u043e \u0443\u0433\u043b\u0443\u0431\u043b\u044f\u0442\u044c\u0441\u044f \u0432 \u0434\u0430\u043d\u043d\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 (\u044d\u0442\u043e \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u0441\u0442\u0430\u0442\u044c\u0438). \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u043c\u0441\u044f \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u0445, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043e\u0442 \u043f\u0440\u044f\u043c\u044b\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 service API \u043a \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c.<\/p>\n<p>\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u043d\u0443\u0442 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c\u0438, \u0435\u0441\u043b\u0438 \u043c\u044b \u0432\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 sequence \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u044b:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f26\/031\/ce6\/f26031ce6b655085a507828cdc2fd09c.png\" alt=\"Create order action: \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\" title=\"Create order action: \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\" width=\"1600\" height=\"1512\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f26\/031\/ce6\/f26031ce6b655085a507828cdc2fd09c.png\"\/><\/p>\n<div><figcaption>Create order action: \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435<\/figcaption><\/div>\n<\/figure>\n<p>\u042d\u0442\u043e\u0442 flow \u043c\u044b \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u043c \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e (\u044f \u0432\u044b\u0434\u0435\u043b\u0438\u043b \u043c\u0435\u0441\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0442\u0430\u043d\u0443\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438):<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bb4\/59c\/1e1\/bb459c1e1ad578e1a6fcbcb5ed1d4a9b.png\" alt=\"Create order action: \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\" title=\"Create order action: \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\" width=\"720\" height=\"693\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/bb4\/59c\/1e1\/bb459c1e1ad578e1a6fcbcb5ed1d4a9b.png\"\/><\/p>\n<div><figcaption>Create order action: \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435<\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u00abChange delivery status\u00bb:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fc2\/814\/07f\/fc281407f99e8f896b7164fbb7a150db.png\" alt=\"Change delivery status action: \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\" title=\"Change delivery status action: \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\" width=\"1560\" height=\"888\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fc2\/814\/07f\/fc281407f99e8f896b7164fbb7a150db.png\"\/><\/p>\n<div><figcaption>Change delivery status action: \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435<\/figcaption><\/div>\n<\/figure>\n<p>\u0427\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0435\u0436\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u0443\u044e \u0441\u0432\u044f\u0437\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u0432 \u044d\u0442\u043e\u043c flow, \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/299\/450\/2ae\/2994502ae864631d2490e1b4e906e05d.png\" alt=\"Change delivery status action: \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\" title=\"Change delivery status action: \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\" width=\"1560\" height=\"888\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/299\/450\/2ae\/2994502ae864631d2490e1b4e906e05d.png\"\/><\/p>\n<div><figcaption>Change delivery status action: \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435<\/figcaption><\/div>\n<\/figure>\n<p>\u0428\u0430\u0433\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0442 \u0432 \u0441\u0435\u0431\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<ul>\n<li>\n<p>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 async broker \u0438 consumers \u0432 \u043d\u0430\u0448\u0443 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 message-\u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0432 \u043d\u0430\u0448\u0435\u043c \u043d\u0435\u0439\u043c\u0441\u043f\u0435\u0439\u0441\u0435 <code>Common<\/code> \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0438\u043c message handlers.<\/p>\n<\/li>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 message bus \u0432\u043c\u0435\u0441\u0442\u043e service client \u0434\u043b\u044f \u043c\u0435\u0436\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u043e\u0439 \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u0410 \u0442\u0435\u043f\u0435\u0440\u044c \u0448\u0430\u0433 \u0437\u0430 \u0448\u0430\u0433\u043e\u043c. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 Symfony Messenger: <code>composer require symfony\/messenger symfony\/amqp-messenger<\/code><\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0435\u0433\u043e:<\/p>\n<pre><code class=\"yaml\"># other services have the same configuration except queue name and routing framework:  messenger:     serializer:      default_serializer: messenger.transport.symfony_serializer     transports:      async:        dsn: '%env(MESSENGER_TRANSPORT_DSN)%'        options:          queues:            restaurant-service: ~     buses:      default.bus:        default_middleware:          enabled: true          allow_no_handlers: true<\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c async broker \u0438 consumers:<\/p>\n<pre><code class=\"diff\"># docker-compose.yml +  amqp-broker: +    image: rabbitmq:3 +    restart: unless-stopped  ...  +  courier-consumer: +    build: +      context: . +    working_dir: \/usr\/share\/app +    restart: unless-stopped +    command: bin\/console messenger:consume async -vv +    volumes: +      - .\/courier-service\/:\/usr\/share\/app  \/\/ consumers for the rest 2 services are added the same way ...<\/code><\/pre>\n<p>\u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f asynchronous brokers, \u043d\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/www.rabbitmq.com\/tutorials\/amqp-concepts.html#exchange-fanout\" rel=\"noopener noreferrer nofollow\"><u>fanout<\/u><\/a> exchange (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f Symfony \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u0435\u0441\u043b\u0438 \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0434\u0440\u0443\u0433\u043e\u0435) \u0438 queue per service. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u0440\u044f\u0434 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432:<\/p>\n<ol>\n<li>\n<p>Producers \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 broker \u0431\u0435\u0437 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c routing key \u0438 \u043d\u0435 \u0437\u043d\u0430\u044f, \u043a\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u0448\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u043e\u0445\u043e\u0436\u0438 \u043d\u0430 events, \u0447\u0435\u043c \u043d\u0430 background tasks, \u0447\u0442\u043e \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u0442 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0432\u0441\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0438 \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c. \u041d\u0438\u0447\u0435\u0433\u043e \u0441\u0442\u0440\u0430\u0448\u043d\u043e\u0433\u043e, \u0435\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0438\u0441 \u043d\u0435 \u0443\u043c\u0435\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043e\u043e\u0431\u044b\u0442\u0438\u044f \u2014 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0430 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438, \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0438 \u043d\u0430\u0447\u0430\u0442\u044c \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0442\u0430\u043a\u0438\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f.<\/p>\n<\/li>\n<\/ol>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u0435\u0440\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043d\u0430\u0448\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432:<\/p>\n<pre><code class=\"php\"># customer-service\/src\/Common\/Message\/OrderCreated.php &lt;?php  declare(strict_types=1);  namespace App\\Common\\Message;  use App\\Common\\Dto\\Order as OrderDto;  readonly class OrderCreated {    public function __construct(private OrderDto $order)    {    }     public function getOrder(): OrderDto    {        return $this->order;    } }  \/\/ all messages should be part of the \"Common\" namespace of each service \/\/ in our case, for the sake of the example, we just copy it \/\/ but in real application, it can (and should) be a package  # restaurant-service\/src\/Restaurant\/MessageHandler\/OrderCreatedHandler.php &lt;?php  declare(strict_types=1);  namespace App\\Restaurant\\MessageHandler;  use App\\Common\\Message\\OrderAccepted; use App\\Common\\Message\\OrderCreated; use Symfony\\Component\\Messenger\\Attribute\\AsMessageHandler; use Symfony\\Component\\Messenger\\MessageBusInterface;  #[AsMessageHandler] readonly class OrderCreatedHandler {    public function __construct(private MessageBusInterface $messageBus)    {    }     public function __invoke(OrderCreated $message)    {        \/\/ for the sake of the example, let's assume for now that the order can always be served        $this->messageBus->dispatch(new OrderAccepted($message->getOrder()));        \/\/ alternatively, we could dispatch this instead based on our business logic:        \/\/ $this->messageBus->dispatch(new OrderDeclined());    } }<\/code><\/pre>\n<p>\u0418 \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u043a\u043e\u0434 \u0438 \u043d\u0430\u0447\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432\u043c\u0435\u0441\u0442\u043e \u0432\u044b\u0437\u043e\u0432\u0430 service clients:<\/p>\n<pre><code class=\"diff\"># customer-service\/src\/Customer\/Service\/CustomerService.php namespace App\\Customer\\Service;  -use App\\Common\\Client\\CourierServiceClient; use App\\Common\\Client\\RestaurantServiceClient; use App\\Common\\Dto\\Order as OrderDto; use App\\Common\\Exception\\EntityNotFoundException; +use App\\Common\\Message\\OrderCreated; use App\\Customer\\Dto\\CreateOrderRequest; use App\\Customer\\Entity\\Order; use Doctrine\\ORM\\EntityManagerInterface; +use Symfony\\Component\\Messenger\\MessageBusInterface;  readonly class CustomerService {     public function __construct(         private RestaurantServiceClient $restaurantServiceClient, -        private CourierServiceClient $deliveryServiceClient, -        private EntityManagerInterface $customerEntityManager +        private EntityManagerInterface $customerEntityManager, +        private MessageBusInterface $messageBus,     ) {     }  @@ -36,17 +37,11 @@          $orderDto = new OrderDto($newOrder->getId(), $newOrder->getStatus(), $newOrder->getRestaurantId(), $newOrder->getDeliveryId());  -        if ($this->restaurantServiceClient->acceptOrder($orderDto)) { -            $newOrder->setStatus(Order::STATUS_ACCEPTED); -            $newDelivery = $this->deliveryServiceClient->createDelivery($orderDto); -            $newOrder->setDeliveryId($newDelivery->getId()); -        } else { -            $newOrder->setStatus(Order::STATUS_DECLINED); -        } -         $this->customerEntityManager->persist($newOrder);         $this->customerEntityManager->flush();  +        $this->messageBus->dispatch(new OrderCreated($orderDto)); +         return $newOrder;     }<\/code><\/pre>\n<p>\u0413\u043e\u0442\u043e\u0432\u043e! \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0441\u0442\u0430 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0442\u0435\u043c \u0436\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u044d\u043d\u0434\u043f\u043e\u0439\u043d\u0442 \u00abCreate order\u00bb \u0438 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u044c, \u043a\u0430\u043a \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432\u0441\u0435\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5d3\/9e7\/8e8\/5d39e78e817621785e8f2fea4bb279ff.png\" alt=\"\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438\" title=\"\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438\" width=\"859\" height=\"135\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5d3\/9e7\/8e8\/5d39e78e817621785e8f2fea4bb279ff.png\"\/><\/p>\n<div><figcaption>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438<\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u0430\u043a\u0436\u0435 \u044d\u0442\u043e \u0432\u0438\u0434\u043d\u043e \u0432 \u043d\u0430\u0448\u0438\u0445 \u043b\u043e\u0433\u0430\u0445:<\/p>\n<pre><code>customer-service_1     | Matched route \"app_customer_customerapi_createorder\". customer-service_1     | Request: \"GET http:\/\/nginx\/api\/restaurant\/service-restaurant\/restaurants\/2\" restaurant-service_1   | Matched route \"app_restaurant_serviceapi_getrestaurant\". customer-service_1     | Sending message App\\Common\\Message\\OrderCreated with async sender using Symfony\\Component\\Messenger\\Bridge\\Amqp\\Transport\\AmqpTransport customer-consumer_1    | Received message App\\Common\\Message\\OrderCreated customer-consumer_1    | No handler for message App\\Common\\Message\\OrderCreated customer-consumer_1    | App\\Common\\Message\\OrderCreated was handled successfully (acknowledging to transport). courier-consumer_1     | Received message App\\Common\\Message\\OrderCreated courier-consumer_1     | No handler for message App\\Common\\Message\\ courier-consumer_1     | App\\Common\\Message\\OrderCreated was handled successfully (acknowledging to transport). restaurant-consumer_1  | Received message App\\Common\\Message\\OrderCreated restaurant-consumer_1  | Sending message App\\Common\\Message\\OrderAccepted with async sender using Symfony\\Component\\Messenger\\Bridge\\Amqp\\Transport\\AmqpTransport restaurant-consumer_1  | Message App\\Common\\Message\\OrderCreated handled by App\\Restaurant\\MessageHandler\\OrderCreatedHandler::__invoke restaurant-consumer_1  | App\\Common\\Message\\OrderCreated was handled successfully (acknowledging to transport). restaurant-consumer_1  | Received message App\\Common\\Message\\OrderAccepted restaurant-consumer_1  | No handler for message App\\Common\\Message\\OrderAccepted restaurant-consumer_1  | App\\Common\\Message\\OrderAccepted was handled successfully (acknowledging to transport). customer-consumer_1    | Received message App\\Common\\Message\\OrderAccepted courier-consumer_1     | Received message App\\Common\\Message\\OrderAccepted customer-consumer_1    | Message App\\Common\\Message\\OrderAccepted handled by App\\Customer\\MessageHandler\\OrderAcceptedHandler::__invoke customer-consumer_1    | App\\Common\\Message\\OrderAccepted was handled successfully (acknowledging to transport). courier-consumer_1     | No handler for message App\\Common\\Message\\DeliveryCreated courier-consumer_1     | Message App\\Common\\Message\\OrderAccepted handled by App\\Courier\\MessageHandler\\OrderAcceptedHandler::__invoke courier-consumer_1     | Sending message App\\Common\\Message\\DeliveryCreated with async sender using Symfony\\Component\\Messenger\\Bridge\\Amqp\\Transport\\AmqpTransport ...<\/code><\/pre>\n<p>\u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043f\u043e\u0441\u043b\u0435 \u0432\u0441\u0435\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u043a\u0430\u043a courier, \u0442\u0430\u043a \u0438 restaurant \u0441\u0435\u0440\u0432\u0438\u0441\u0443 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043d\u0443\u0436\u043d\u044b service clients, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0438\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u0443\u0436\u0431\u0430\u043c\u0438. \u041d\u0430\u0448 \u043a\u043e\u0434 \u0441\u0442\u0430\u043b \u0447\u0443\u0442\u043e\u0447\u043a\u0443 \u0447\u0438\u0449\u0435!<\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u0434\u0430 \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0448\u0430\u0433\u0430 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c <a href=\"https:\/\/github.com\/ilyachase\/monolith-decoupling-example\/tree\/step5-event-driven\" rel=\"noopener noreferrer nofollow\"><u>\u0437\u0434\u0435\u0441\u044c<\/u><\/a>.<\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044d\u0442\u0430\u043f\u043e\u0432. \u041d\u0430\u0447\u0438\u043d\u0430\u044f \u0441 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044f \u043d\u0430 \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u043d\u043e\u043b\u0438\u0442, \u0437\u0430\u0442\u0435\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0438 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439\u043d\u043e-\u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043e\u0439. \u041c\u044b \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u043b\u0438\u0441\u044c \u043d\u0430 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0434\u0435\u0442\u0430\u043b\u044f\u0445 \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u0441\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u0431\u0443\u0434\u0435\u0442 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0440\u0430\u0431\u043e\u0442\u044b, \u0431\u043e\u043b\u044c\u0448\u0435 edge cases \u0438 \u043f\u0440\u0438\u043d\u044f\u0442\u0438\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u0439. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u044d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e \u043d\u0435 \u043a\u0430\u043a \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044e, \u0430 \u043a\u0430\u043a \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043c\u043e\u0436\u0435\u0442 (\u0438 \u0434\u043e\u043b\u0436\u0435\u043d) \u0431\u044b\u0442\u044c <strong>\u0438\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u043c<\/strong> \u0438 <strong>\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u043c<\/strong>. \u0421\u0430\u043c\u043e\u0439 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439 \u0442\u0430\u043a\u0438\u0445 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0447\u0430\u0441\u0442\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0435 \u0441\u0430\u043c\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435, \u0430 \u043e\u0431\u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u043d\u0430\u0434\u043b\u0435\u0436\u0430\u0449\u0435\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u0430\u043c \u0438 \u0434\u0440\u0443\u0433\u0438\u043c \u0432\u043e\u0432\u043b\u0435\u0447\u0435\u043d\u043d\u044b\u043c \u0441\u0442\u043e\u0440\u043e\u043d\u0430\u043c \u0432\u0435\u0440\u0438\u0442\u044c \u0432 \u0443\u0441\u043f\u0435\u0445 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0444\u043e\u043a\u0443\u0441. \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u044d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u0434\u0430\u0435\u0442 \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0442\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043a\u0430\u043a \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442\u044c.<\/p>\n<p>\u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0438 \u0443\u0434\u0430\u0447\u0438!<\/p>\n<\/p>\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\/796223\/\"> https:\/\/habr.com\/ru\/articles\/796223\/<\/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<h2>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0421\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0441\u0430\u043c \u043f\u043e \u0441\u0435\u0431\u0435 \u043c\u043e\u043d\u043e\u043b\u0438\u0442 \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u043d\u0442\u0438\u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u043c \u0438 \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c (\u0438 \u0447\u0430\u0441\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442) \u043f\u0440\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445, \u043e\u0431\u044b\u0447\u043d\u043e &#8212; \u043a\u043e\u0433\u0434\u0430 \u043e\u043d \u0432\u044b\u0431\u0440\u0430\u043d \u043e\u0441\u043e\u0437\u043d\u0430\u043d\u043d\u043e. \u041d\u043e \u0447\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043d\u0435 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043b\u044e\u0434\u0438 \u0435\u0451 \u0432\u044b\u0431\u0440\u0430\u043b\u0438, \u0430 \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 \u043d\u0435\u0451 \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u044d\u0432\u043e\u043b\u044e\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043b.<\/p>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u044f\u0441\u043d\u0438\u043c, \u0447\u0442\u043e \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u0432 \u0432\u0438\u0434\u0443 \u043f\u043e\u0434 &#171;\u0434\u0435\u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0435\u0439 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430&#187;. \u041a\u0430\u043a\u0430\u044f \u043d\u0430\u0448\u0430 \u043a\u043e\u043d\u0435\u0447\u043d\u0430\u044f \u0446\u0435\u043b\u044c? \u041a\u0430\u043a\u0438\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c <em>\u0431\u0438\u0437\u043d\u0435\u0441-\u0446\u0435\u043b\u0438<\/em>, \u043f\u043e\u0431\u0443\u0436\u0434\u0430\u044e\u0449\u0438\u0435 \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043e\u0432 \u0440\u0435\u0448\u0430\u0442\u044c \u044d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443?<\/p>\n<ol>\n<li>\n<p>\u041c\u0435\u0434\u043b\u0435\u043d\u043d\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u042d\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0438\u0437-\u0437\u0430 \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u0438 (coupling) \u043a\u043e\u0434\u0430, \u0447\u0442\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f:<\/p>\n<ol>\n<li>\n<p>\u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0437\u0430\u043f\u0443\u0442\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 (\u0435\u0441\u0442\u044c \u0432\u0430\u0436\u043d\u0430\u044f<a href=\"https:\/\/dev.to\/maurofrezza\/complex-software-vs-complicated-software-cid\" rel=\"noopener noreferrer nofollow\"> <u>\u0440\u0430\u0437\u043d\u0438\u0446\u0430<\/u><\/a> \u043c\u0435\u0436\u0434\u0443 \u0441\u043b\u043e\u0436\u043d\u044b\u043c (complex) \u0438 \u0437\u0430\u043f\u0443\u0442\u0430\u043d\u043d\u044b\u043c (complicated) \u043a\u043e\u0434\u043e\u043c).<\/p>\n<\/li>\n<li>\n<p>\u0447\u0430\u0441\u0442\u0438 \u043a\u043e\u0434\u0430 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430, \u0447\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0431\u043e\u043b\u0435\u0435 \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e\u0441\u0442\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432 \u0438 \u043f\u043e\u0432\u044b\u0448\u0430\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u043d\u0430\u0434\u043b\u0435\u0436\u0430\u0449\u0435\u0433\u043e CI\\CD \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0441\u0434\u0432\u0438\u0433\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0438\u043b\u0438 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a) \u043f\u043e\u0447\u0442\u0438 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b \u0438\u0437-\u0437\u0430 \u0432\u044b\u0441\u043e\u043a\u0438\u0445 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u0442\u0440\u0430\u0442.<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p>\u041c\u043e\u043d\u043e\u043b\u0438\u0442 \u043a\u0430\u043a<a href=\"https:\/\/en.wikipedia.org\/wiki\/Single_point_of_failure\" rel=\"noopener noreferrer nofollow\"> <u>\u0435\u0434\u0438\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u043e\u0442\u043a\u0430\u0437\u0430<\/u><\/a> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u0440\u0438\u0441\u043a\u043e\u043c.<\/p>\n<\/li>\n<li>\n<p>\u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u043c.<\/p>\n<\/li>\n<\/ol>\n<p>\u0423\u0447\u0438\u0442\u044b\u0432\u0430\u044f \u0432\u044b\u0448\u0435\u0438\u0437\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0435, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0439 \u0446\u0435\u043b\u044c\u044e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <strong>\u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043a \u0431\u043e\u043b\u0435\u0435 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/strong> \u0434\u043b\u044f \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u043d\u0438\u0436\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d\u044b\u0445 \u0440\u0438\u0441\u043a\u043e\u0432.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0438 \u0446\u0435\u043b\u044c, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0432\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u043f\u043b\u0430\u043d.<\/p>\n<h2>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h2>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0435\u0434\u044b. \u0414\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u043e\u043d\u043e \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438, \u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0439 \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438 \u0438 \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0421\u0443\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0449\u0435 \u043f\u043e\u043d\u044f\u0442\u044c \u043f\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0435:<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0435\u0434\u044b<\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u0438\u043f\u0438\u0447\u043d\u044b\u0439 flow \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439: customer \u0434\u0435\u043b\u0430\u0435\u0442 \u0437\u0430\u043a\u0430\u0437 (create order), \u0441\u043e\u0432\u0435\u0440\u0448\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a restaurant service, \u0438 \u0435\u0441\u043b\u0438 \u0437\u0430\u043a\u0430\u0437 \u043f\u0440\u0438\u043d\u044f\u0442, \u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 (delivery) \u0438 \u043e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u0443\u0440\u044c\u0435\u0440. \u041a\u043e\u0433\u0434\u0430 \u043a\u0443\u0440\u044c\u0435\u0440 \u043d\u0430\u0439\u0434\u0435\u043d, \u043e\u043d \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u043e\u0439 \u0447\u0435\u0440\u0435\u0437 \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0441\u0442\u0430\u0442\u0443\u0441\u0430 (change delivery status): <code>courier_assigned<\/code> -> <code>courier_delivering<\/code> -> <code>successful<\/code>. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0442\u0440\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 (customer, courier, restaurant), \u0430 \u0442\u0430\u043a\u0436\u0435 \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f orders \u0438 deliveries. \u0412 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438, \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a \u043c\u043e\u043d\u043e\u043b\u0438\u0442 \u0441 \u043b\u0438\u0448\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435\u043c \u043d\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u0432.<\/p>\n<p>\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f: <a href=\"https:\/\/github.com\/ilyachase\/monolith-decoupling-example\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/github.com\/ilyachase\/monolith-decoupling-example<\/u><\/a><\/p>\n<h2>\u0412\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u043f\u043b\u0430\u043d<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u043e\u044f\u0441\u043d\u0438\u043c \u0442\u043e, \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043c\u044b \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u00ab\u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c\u00bb \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b:<\/p>\n<ol>\n<li>\n<p>\u041d\u0435 \u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0432 \u043d\u0430\u0448\u0435\u043c \u043a\u043e\u0434\u0435 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0435 service classes, \u043e\u043d\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0442 \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c <em>\u043f\u0440\u044f\u043c\u044b\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u043e\u0432<\/em>. <\/p>\n<\/li>\n<li>\n<p>\u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043c\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c, \u043c\u044b \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u043c \u0438\u0437\u0432\u043b\u0435\u0447\u044c, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e (\u0447\u0435\u0440\u0435\u0437 \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0435 \u0441\u043b\u043e\u0432\u043e <code>use<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u0432\u0441\u0435 service classes \u0438\u043c\u0435\u044e\u0442 \u0434\u043e\u0441\u0442\u0443\u043f <em>\u043a\u043e \u0432\u0441\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u043c<\/em> \u0432 \u0431\u0430\u0437\u0435, \u0430 \u0437\u043d\u0430\u0447\u0438\u0442, \u043d\u0435\u0442 \u0433\u0440\u0430\u043d\u0438\u0446 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043c\u044b \u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043c\u043d\u043e\u0433\u043e \u0443\u0441\u0438\u043b\u0438\u0439. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c <em>\u0438\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u043c<\/em> \u0438 <em>\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u043c<\/em>. \u0421 \u044d\u0442\u043e\u0439 \u0446\u0435\u043b\u044c\u044e \u043c\u044b \u0432\u043d\u0435\u0434\u0440\u0438\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0448\u0430\u0433 \u043f\u0435\u0440\u0435\u0434 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u043c \u043a \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c &#8212; \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u043c \u043d\u0430\u0448 \u043c\u043e\u043d\u043e\u043b\u0438\u0442 \u0432 <strong>\u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u043d\u043e\u043b\u0438\u0442<\/strong>.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u0432\u0435\u0434\u0435\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043c\u043e\u0434\u0443\u043b\u044f. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0447\u0430\u0441\u0442\u044c \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043e\u0434\u0430 \u043c\u043e\u0434\u0443\u043b\u0435\u043c \u0442\u043e\u0433\u0434\u0430 \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u0442\u044c \u0434\u0432\u0443\u043c \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u043c:<\/p>\n<ol>\n<li>\n<p>\u0420\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u0434\u0430. \u041c\u043e\u0434\u0443\u043b\u0438 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u0440\u0443\u0433\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e. \u041a\u043e\u0433\u0434\u0430 \u043c\u043e\u0434\u0443\u043b\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0439 \u043c\u043e\u0434\u0443\u043b\u044c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <em>service client<\/em>.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u041a\u0430\u0436\u0434\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<\/ol>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435:<\/p>\n<ul>\n<li>\n<p><em>\u041c\u043e\u0434\u0443\u043b\u0438 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u0440\u0443\u0433\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e.<\/em> \u0427\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430, \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <a href=\"https:\/\/github.com\/qossmic\/deptrac\" rel=\"noopener noreferrer nofollow\"><u>Deptrac<\/u><\/a>. \u042d\u0442\u043e \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e: \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e <code>deptrac.yaml<\/code>), \u0432 \u043d\u0435\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u0438 \u0438 \u0434\u0430\u043b\u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0439 \u0444\u0430\u0439\u043b \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044f \u0433\u0440\u0430\u043d\u0438\u0446. \u0427\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043e, \u0437\u0430\u043f\u0443\u0441\u043a \u044d\u0442\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 CI\\CD (<a href=\"https:\/\/github.com\/features\/actions\" rel=\"noopener noreferrer nofollow\"><u>GitHub actions<\/u><\/a> \u0438\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435). \u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0434\u0430\u043d\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0431\u044b\u043b\u0430 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 (required).<\/p>\n<\/li>\n<li>\n<p><em>\u041a\u043e\u0433\u0434\u0430 \u043e\u0434\u043d\u043e\u043c\u0443 \u043c\u043e\u0434\u0443\u043b\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u043e\u0439 \u043c\u043e\u0434\u0443\u043b\u044c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f service client.<\/em> \u0418\u0434\u0435\u044f \u043f\u0440\u043e\u0441\u0442\u0430: \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u0441\u0440\u0430\u0437\u0443 \u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u043d\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 &#8212; \u043e\u0431\u044b\u0447\u043d\u043e \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0441\u043a\u0430\u0447\u043e\u043a, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u043a\u043e\u0434, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <a href=\"https:\/\/symfony.com\/doc\/current\/components\/http_kernel.html#sub-requests\" rel=\"noopener noreferrer nofollow\"><u>sub-requests<\/u><\/a> \u0432\u043c\u0435\u0441\u0442\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. Service client &#8212; \u044d\u0442\u043e \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0435\u0433\u043e \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0442\u0432\u0435\u0442. \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435.<\/p>\n<\/li>\n<li>\n<p><em>\u041a\u0430\u0436\u0434\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445.<\/em> \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u0435 <a href=\"https:\/\/microservices.io\/patterns\/data\/database-per-service.html\" rel=\"noopener noreferrer nofollow\"><u>\u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445<\/u><\/a>, \u0438 \u00abdatabase per service\u00bb \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043d\u0438\u0445. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u043d \u043e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<\/ul>\n<p>\u0423\u0447\u0438\u0442\u044b\u0432\u0430\u044f \u0432\u044b\u0448\u0435\u0441\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u044d\u0442\u0430\u043f\u044b \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b:<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u042d\u0442\u0430\u043f\u044b \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/figcaption><\/div>\n<\/figure>\n<p>\u041d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e event-driven \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u0441 <a href=\"https:\/\/blog.christianposta.com\/microservices\/the-hardest-part-about-microservices-data\/\" rel=\"noopener noreferrer nofollow\"><u>event streams<\/u><\/a>, <a href=\"https:\/\/teivah.medium.com\/why-is-a-canonical-data-model-an-anti-pattern-441b5c4cbff8\" rel=\"noopener noreferrer nofollow\"><u>bounded context models<\/u><\/a>, <a href=\"https:\/\/debezium.io\/blog\/2019\/02\/19\/reliable-microservices-data-exchange-with-the-outbox-pattern\/\" rel=\"noopener noreferrer nofollow\"><u>outbox pattern<\/u><\/a> \u0438 \u0442.\u0434. (\u043f\u043e\u044d\u0442\u043e\u043c\u0443, \u043e\u043d \u043f\u043e\u0434 \u0437\u0432\u0435\u0437\u0434\u043e\u0447\u043a\u043e\u0439). \u041e\u0434\u043d\u0430\u043a\u043e, \u043c\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u0441\u043f\u043e\u0441\u043e\u0431 \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043d\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0442.\u043a. \u044d\u0442\u043e \u0442\u0438\u043f\u0438\u0447\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043f\u0440\u0435\u0442\u0435\u0440\u043f\u0435\u0432\u0430\u044e\u0449\u0438\u0445 \u0442\u0430\u043a\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u044d\u0432\u043e\u043b\u044e\u0446\u0438\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u0430 \u0437\u043d\u0430\u0447\u0438\u0442, \u0441\u0442\u043e\u0438\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u044d\u0442\u043e \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h2>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043c\u044b \u043d\u0430\u0447\u043d\u0435\u043c, \u043d\u0435 \u043c\u043e\u0433\u0443 \u043d\u0435 \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u043d\u0443\u0442\u044c \u0432\u0430\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043a\u0440\u044b\u0442\u0438\u044f \u0442\u0435\u0441\u0442\u0430\u043c\u0438. \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438, \u043d\u043e \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u043f\u0435\u0440\u0432\u044b\u043c \u0448\u0430\u0433\u043e\u043c \u043f\u0435\u0440\u0435\u0434 \u043b\u044e\u0431\u044b\u043c\u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u043c\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c\u0438 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043b\u043e\u044f \u0442\u0435\u0441\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043d\u0430 near-HTTP \u0443\u0440\u043e\u0432\u043d\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"https:\/\/symfony.com\/doc\/current\/testing.html#application-tests\" rel=\"noopener noreferrer nofollow\"><u>Application tests<\/u><\/a> \u0432 Symfony), \u0438\u043b\u0438 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435 e2e \u0442\u0435\u0441\u0442\u044b.<\/p>\n<h3>\u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u043e\u0442 big ball of mud \u043a modular monolith<\/h3>\n<h4>\u0413\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432<\/h4>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0433\u0440\u0430\u043d\u0438\u0446\u044b \u043c\u0435\u0436\u0434\u0443 \u0447\u0430\u0441\u0442\u044f\u043c\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041e\u043d\u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 (Customer, Restaurant \u0438 Courier), \u043d\u043e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f \u043b\u0438\u0431\u043e \u0437\u0434\u0440\u0430\u0432\u044b\u0439 \u0441\u043c\u044b\u0441\u043b, \u043b\u0438\u0431\u043e \u043d\u0430 Domain Driven Design \u043a\u0430\u043a \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434. \u041d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0432 \u043d\u0430\u0447\u0430\u043b\u0435, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044d\u0442\u043e \u0432\u043b\u0435\u0447\u0435\u0442 \u0437\u0430 \u0441\u043e\u0431\u043e\u0439 \u0431\u043e\u043b\u0435\u0435 \u0432\u044b\u0441\u043e\u043a\u0438\u0439 maintenance cost. \u0418\u0437 <a href=\"https:\/\/cloud.google.com\/architecture\/microservices-architecture-refactoring-monoliths\" rel=\"noopener noreferrer nofollow\"><u>\u0441\u0442\u0430\u0442\u044c\u0438 \u043e\u0442 Google<\/u><\/a>:<\/p>\n<blockquote>\n<p><em>We recommend that you create larger services instead of smaller services until you thoroughly understand the domain.<\/em><\/p>\n<\/blockquote>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0433\u0440\u0430\u043d\u0438\u0446\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b, \u043f\u0435\u0440\u0432\u044b\u043c \u0448\u0430\u0433\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438, \u043f\u043e\u043a\u0430 <strong>\u0431\u0435\u0437 \u0440\u0430\u0441\u043f\u0443\u0442\u044b\u0432\u0430\u043d\u0438\u044f<\/strong> \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 (as is). \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0444\u0430\u0439\u043b\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443:<\/p>\n<pre><code>src\/    Controller\/        CourierApiController.php        CustomerApiController.php    Dto\/        ChangeDeliveryStatusRequest.php        CreateOrderRequest.php    Entity\/        Delivery.php        Order.php        Restaurant.php    Repository\/        DeliveryRepository.php        OrderRepository.php        RestaurantRepository.php    Service\/        CourierService.php        CustomerService.php        RestaurantService.php<\/code><\/pre>\n<p>\u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u044b\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0439, \u0440\u0435\u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u043d\u0430\u0448\u0438 \u043c\u043e\u0434\u0443\u043b\u0438, \u0430 \u0444\u0430\u0439\u043b\u044b, \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u043d\u043e\u0441\u0442\u044c \u043a \u043c\u043e\u0434\u0443\u043b\u044f\u043c \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u0430, \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u043c \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 <code>Common<\/code>:<\/p>\n<pre><code>src\/    Customer\/   &lt;-- module level directory        Controller\/            CustomerApiController.php        Dto\/            CreateOrderRequest.php        Entity\/            Order.php        Repository\/            OrderRepository.php        Service\/            CustomerService.php    Restaurant\/   &lt;-- module level directory        Entity\/            Restaurant.php        Repository\/            RestaurantRepository.php        Service\/            RestaurantService.php    Courier\/      &lt;-- module level directory        Controller\/            CourierApiController.php        Dto\/            ChangeDeliveryStatusRequest.php        Entity\/            Delivery.php        Repository\/            DeliveryRepository.php        Service\/            CourierService.php    Common\/        Exception\/            EntityNotFoundException.php<\/code><\/pre>\n<p>\u0421\u043e\u0432\u0435\u0442: \u0435\u0441\u043b\u0438 \u0432\u0430\u0448\u0430 IDE \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 PSR namespaces, \u043e\u043d\u0430 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0432\u0430\u043c \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043a\u043b\u0430\u0441\u0441\u044b \u043f\u0440\u0438 \u0438\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, PhpStorm <a href=\"https:\/\/www.jetbrains.com\/help\/phpstorm\/tutorial-moving-php-classes.html#a00632a\" rel=\"noopener noreferrer nofollow\"><u>\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442<\/u><\/a> \u0435\u0433\u043e \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438, \u0435\u0441\u043b\u0438 \u0432\u044b <a href=\"https:\/\/www.jetbrains.com\/help\/phpstorm\/composer-page.html\" rel=\"noopener noreferrer nofollow\"><u>\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0435<\/u><\/a> \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 IDE \u0441 Composer.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0438 Symfony \u0434\u043b\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u043d\u0430\u0448\u0435\u0439 \u043d\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b:<\/p>\n<pre><code class=\"diff\"># config\/packages\/doctrine.yaml         naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware         auto_mapping: true         mappings: -            App: +            App\\Courier: +                is_bundle: false +                dir: '%kernel.project_dir%\/src\/Courier\/Entity' +                prefix: 'App\\Courier\\Entity' +                alias: App\\Courier +            App\\Customer:                 is_bundle: false -                dir: '%kernel.project_dir%\/src\/Entity' -                prefix: 'App\\Entity' -                alias: App +                dir: '%kernel.project_dir%\/src\/Customer\/Entity' +                prefix: 'App\\Customer\\Entity' +                alias: App\\Customer +            App\\Restaurant: +                is_bundle: false +                dir: '%kernel.project_dir%\/src\/Restaurant\/Entity' +                prefix: 'App\\Restaurant\\Entity' +                alias: App\\Restaurant  # config\/routes.yaml -controllers: +courier_controllers:     resource: -        path: ..\/src\/Controller\/ -        namespace: App\\Controller +        path: ..\/src\/Courier\/Controller\/ +        namespace: App\\Courier\\Controller +    type: attribute +customer_controllers: +    resource: +        path: ..\/src\/Customer\/Controller\/ +        namespace: App\\Customer\\Controller     type: attribute<\/code><\/pre>\n<p>\u0421\u043e\u0432\u0435\u0442: \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u044d\u0442\u043e\u0442 \u0448\u0430\u0433 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 PR, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u043d \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0441\u0442\u0430\u043d\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 <strong>\u0438\u0442\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u043c<\/strong> \u0438 <strong>\u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u043c<\/strong>.<\/p>\n<h4>\u0420\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445<\/h4>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0444\u0430\u0439\u043b\u044b \u0441\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u043f\u043e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f\u043c\u0438, \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c <\/p>\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-369232","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/369232","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=369232"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/369232\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=369232"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=369232"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=369232"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}