{"id":315502,"date":"2020-12-24T21:00:26","date_gmt":"2020-12-24T21:00:26","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=315502"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=315502","title":{"rendered":"Trunk Based Development \u0438 Spring Boot, \u0438\u043b\u0438 \u0432\u0435\u0442\u0432\u0438\u0441\u044c \u043e\u043d\u043e \u0432\u0441\u0435 \u043f\u043e \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0438"},"content":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! <\/p>\n<p>\u0417\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0430\u0441\u044c \u043e\u0441\u0435\u043d\u044c, \u0437\u0438\u043c\u0430 \u0432\u0441\u0442\u0443\u043f\u0438\u043b\u0430 \u0432 \u0441\u0432\u043e\u0438 \u0437\u0430\u043a\u043e\u043d\u043d\u044b\u0435 \u043f\u0440\u0430\u0432\u0430, \u043b\u0438\u0441\u0442\u044c\u044f \u0443\u0436\u0435 \u0434\u0430\u0432\u043d\u043e \u043e\u043f\u0430\u043b\u0438 \u0438 \u043f\u0435\u0440\u0435\u043f\u0443\u0442\u0430\u043d\u043d\u044b\u0435 \u0432\u0435\u0442\u0432\u0438 \u043a\u0443\u0441\u0442\u0430\u0440\u043d\u0438\u043a\u043e\u0432 \u043d\u0430\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u044e\u0442 \u043c\u0435\u043d\u044f  \u043d\u0430 \u043c\u044b\u0441\u043b\u0438 \u043e \u043c\u043e\u0451\u043c \u0440\u0430\u0431\u043e\u0447\u0435\u043c Git \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438\u2026  \u041d\u043e \u0432\u043e\u0442 \u043d\u0430\u0447\u0430\u043b\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442: \u043d\u043e\u0432\u0430\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430, \u0447\u0438\u0441\u0442\u044b\u0439, \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0432\u044b\u043f\u0430\u0432\u0448\u0438\u0439 \u0441\u043d\u0435\u0433 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439. &#171;\u0422\u0443\u0442 \u0432\u0441\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e \u0434\u0440\u0443\u0433\u043e\u043c\u0443&#187; &#8212; \u0434\u0443\u043c\u0430\u044e \u044f \u0438 \u043d\u0430\u0447\u0438\u043d\u0430\u044e &#171;\u0433\u0443\u0433\u043b\u0438\u0442\u044c&#187; \u043f\u0440\u043e Trunk Based Development. <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u043d\u0438\u043a\u0430\u043a \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c git flow, \u0432\u0430\u043c \u043d\u0430\u0434\u043e\u0435\u043b\u0438 \u043a\u0443\u0447\u0438 \u044d\u0442\u0438\u0445 \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0445 \u0432\u0435\u0442\u043e\u043a \u0438 \u043f\u0440\u0430\u0432\u0438\u043b \u0434\u043b\u044f \u043d\u0438\u0445, \u0435\u0441\u043b\u0438 \u0432 \u0432\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432\u0435\u0442\u043a\u0438 \u0432\u0438\u0434\u0430 &#171;develop\/ivanov&#187;, \u0442\u043e \u0434\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u0432 \u043f\u043e\u0434 \u043a\u0430\u0442!  \u0422\u0430\u043c \u044f \u043f\u0440\u043e\u0431\u0435\u0433\u0443\u0441\u044c \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u043c Trunk Based Development \u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f Spring Boot.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/eg\/ge\/bd\/eggebdf6kbkduv9iws-ieolkk8a.jpeg\" width=\"300\" height=\"300\"><figcaption><\/figcaption><\/figure>\n<h3>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h3>\n<p>Trunk Based Development (<a href=\"https:\/\/trunkbaseddevelopment.com\/\" rel=\"noopener noreferrer nofollow\">TBD<\/a>) \u044d\u0442\u043e \u043f\u043e\u0434\u0445\u043e\u0434, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u0441\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u0435\u0434\u0435\u0442\u0441\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0432\u0435\u0442\u043a\u0438 trunk (\u0441\u0442\u0432\u043e\u043b). \u0427\u0442\u043e\u0431\u044b \u0432\u043e\u043f\u043b\u043e\u0442\u0438\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0432 \u0436\u0438\u0437\u043d\u044c, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0440\u0435\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c:<\/p>\n<p>1) \u041b\u044e\u0431\u044b\u0435 \u043a\u043e\u043c\u043c\u0438\u0442\u044b \u0432 trunk \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u043b\u043e\u043c\u0430\u0442\u044c \u0441\u0431\u043e\u0440\u043a\u0443.<\/p>\n<p>2) \u041b\u044e\u0431\u044b\u0435 \u043a\u043e\u043c\u043c\u0438\u0442\u044b \u0432 trunk \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u043c\u0438, \u043d\u0430 \u0441\u0442\u043e\u043b\u044c\u043a\u043e, \u0447\u0442\u043e review \u043d\u043e\u0432\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 10 \u043c\u0438\u043d\u0443\u0442.<\/p>\n<p>3) \u0420\u0435\u043b\u0438\u0437 \u0432\u044b\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 trunk.<\/p>\n<p>\u0414\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043b\u0438\u0441\u044c? \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435. <\/p>\n<h3>\u041d\u0430\u0447\u0430\u043b\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438<\/h3>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/bg\/uv\/xo\/bguvxomr-sh8adso67_szytvwy0.png\" width=\"200\" height=\"200\"><figcaption><\/figcaption><\/figure>\n<h4>Initial commit<\/h4>\n<p>\u042f \u043d\u0435 \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u043b \u043d\u0438 \u0447\u0435\u0433\u043e \u043b\u0443\u0447\u0448\u0435 \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f &#171;\u043e\u043f\u043e\u0432\u0435\u0449\u0430\u0442\u0435\u043b\u044c&#187;, REST \u0441\u0435\u0440\u0432\u0438\u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0435 \u0432 \u0432\u0438\u0434\u0435 json, \u0430 \u043e\u043d \u0443\u0436\u0435 \u043e\u043f\u043e\u0432\u0435\u0449\u0430\u0435\u0442 \u043a\u043e\u0433\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 <a href=\"https:\/\/start.spring.io\/\" rel=\"noopener noreferrer nofollow\">spring initializr<\/a>.  \u042f \u0441\u0434\u0435\u043b\u0430\u043b Maven Project, \u044f\u0437\u044b\u043a Java \u0432\u0435\u0440\u0441\u0438\u044f 8, Spring Boot 2.4.0. \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435:<\/p>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438<\/summary>\n<div class=\"spoiler__content\">\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p>\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435<\/p>\n<\/th>\n<th>\n<p>\u0422\u0438\u043f<\/p>\n<\/th>\n<th>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p>Spring Configuration Processor<\/p>\n<\/td>\n<td>\n<p>DEVELOPER TOOLS<\/p>\n<\/td>\n<td>\n<p>Generate metadata for developers to offer contextual help and &#171;code completion&#187; when working with custom configuration keys (ex.application.properties\/.yml files).<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p>Validation<\/p>\n<\/td>\n<td>\n<p>I\/O<\/p>\n<\/td>\n<td>\n<p>JSR-303 validation with Hibernate validator.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p>Spring Web<\/p>\n<\/td>\n<td>\n<p>WEB<\/p>\n<\/td>\n<td>\n<p>Build web, including RESTful, applications using Spring MVC. Uses Apache Tomcat as the default embedded container.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p>Lombok<\/p>\n<\/td>\n<td>\n<p>DEVELOPER TOOLS<\/p>\n<\/td>\n<td>\n<p>Java annotation library which helps to reduce boilerplate code.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<\/details>\n<p>\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c git \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0438 \u043f\u0443\u0448\u0438\u043c \u043d\u0430 <a href=\"https:\/\/github.com\/\" rel=\"noopener noreferrer nofollow\">GitHub<\/a> \u0438\u043b\u0438 \u043a\u0443\u0434\u0430 \u0432\u0430\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f. \u041e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u0432\u0435\u0442\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0437\u0432\u0430\u0442\u044c \u043f\u043e \u0441\u0432\u043e\u0435\u043c\u0443 \u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0438\u044e: main, master \u0438\u043b\u0438 \u0434\u0430\u0436\u0435 \u0442\u0430\u043a \u0438 \u043d\u0430\u0437\u0432\u0430\u0442\u044c &#8212; trunk, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0435\u043c \u0441\u0440\u0430\u0437\u0443 \u0431\u044b\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u0447\u0435\u043c \u0432\u044b \u0442\u0443\u0442 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0435\u0441\u044c.  \u0412\u0441\u0435. \u041f\u043e\u0441\u0430\u0434\u0438\u043b\u0438 \u0434\u0435\u0440\u0435\u0432\u0446\u0435. \u0422\u0435\u043f\u0435\u0440\u044c \u0431\u0443\u0434\u0435\u043c \u0431\u0435\u0440\u0435\u0436\u0435\u043d\u043e \u0435\u0433\u043e \u0432\u044b\u0440\u0430\u0449\u0438\u0432\u0430\u0442\u044c. <\/p>\n<h4>\u041f\u0435\u0440\u0432\u0430\u044f \u0444\u0438\u0447\u0430<\/h4>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0435\u0440\u0432\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u0447\u0442\u0443.  \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0438\u0448\u0435\u043c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432 \u0432\u0438\u0434\u0435 <a href=\"https:\/\/www.baeldung.com\/configuration-properties-in-spring-boot\" rel=\"noopener noreferrer nofollow\">ConfigurationProperties<\/a>.  \u0423 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u043a\u0430 \u0431\u0443\u0434\u0443\u0442  \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u0432\u0430 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430:  sender-email &#8212; \u043f\u043e\u0447\u0442\u043e\u0432\u044b\u0439 \u0430\u0434\u0440\u0435\u0441 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044f \u0438 email-subject &#8212; \u0442\u0435\u043c\u0430 \u043f\u0438\u0441\u044c\u043c\u0430 \u0432 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>NotificationProperties<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\"> @Getter  @Setter  @Component  @Validated \/\/\u0433\u043e\u0432\u043e\u0440\u0438\u043c, \u0447\u0442\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c\u0441\u044f  @ConfigurationProperties(prefix = \"notification\")  public class NotificationProperties {       @Email \/\/\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0447\u0442\u043e \u044d\u0442\u043e \u043f\u043e\u0447\u0442\u0430      @NotBlank \/\/\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0447\u0442\u043e \u043f\u043e\u043b\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043e      private String senderEmail;       @NotBlank      private String emailSubject;  } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f \u043d\u0430 \u043f\u043e\u0447\u0442\u0443, \u0434\u0435\u043b\u0430\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u0433\u043b\u0443\u0448\u0443, \u0442\u0430\u043a  \u043a\u0430\u043a \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u044d\u0442\u043e\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0441\u044f \u0431\u044b \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439. <\/p>\n<blockquote>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043d\u0430\u043c \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f.<\/p>\n<\/blockquote>\n<details class=\"spoiler\">\n<summary>EmailSender<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Slf4j @Component public class EmailSender {     \/**      * \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u0447\u0442\u0443 \u043f\u043e\u043d\u0430\u0440\u043e\u0448\u043a\u0443      *\/     public void sendEmail(String from, String to, String subject, String text){         log.info(\"Send email\\nfrom: {}\\nto: {}\\nwith subject: {}\\nwith\\n text: {}\", from, to, subject, text);     } } <\/code><\/pre>\n<p> <\/p>\n<\/div>\n<\/details>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c\u043a\u0443 \u0434\u043b\u044f \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f: <\/p>\n<details class=\"spoiler\">\n<summary>Notification<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Getter @Setter @Builder @AllArgsConstructor public class Notification {     private String text;     private String recipient; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f: <\/p>\n<details class=\"spoiler\">\n<summary>NotificationService<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Service @RequiredArgsConstructor public class NotificationService {      private final EmailSender emailSender;      private final NotificationProperties notificationProperties;      public void notify(Notification notification){         String from = notificationProperties.getNotificationSenderEmail();         String to = notification.getRecipient();         String subject = notificationProperties.getNotificationEmailSubject();         String text = notification.getText();         emailSender.sendEmail(from, to, subject, text);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440: <\/p>\n<details class=\"spoiler\">\n<summary>NotificationController<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@RestController @RequiredArgsConstructor public class NotificationController {      private final NotificationService notificationService;      @PostMapping(\"\/notification\/notify\")     public void notify(Notification notification){         notificationService.sendNotification(notification);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0415\u0449\u0451 \u043d\u0430\u043c \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0442\u0435\u0441\u0442\u044b, \u0431\u0435\u0437 \u043d\u0438\u0445 TBD \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f. \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0442\u0435\u0441\u0442 \u0434\u043b\u044f NotificationService: <\/p>\n<details class=\"spoiler\">\n<summary>NotificationServiceTest<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@SpringBootTest class NotificationServiceTest {      @Autowired     NotificationService notificationService;      @Autowired     NotificationProperties properties;      @MockBean     EmailSender emailSender;      @Test     void emailNotification() {         Notification notification = Notification.builder()                 .recipient(\"test@email.com\")                 .text(\"some text\")                 .build();          notificationService.notify(notification);          ArgumentCaptor&lt;string&gt; emailCapture = ArgumentCaptor.forClass(String.class);         verify(emailSender, times(1))                 .sendEmail(emailCapture.capture(),emailCapture.capture(),emailCapture.capture(),emailCapture.capture());         assertThat(emailCapture.getAllValues())                 .containsExactly(properties.getSenderEmail(),                                 notification.getRecipient(),                                 properties.getEmailSubject(),                                 notification.getText()                 );     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u0434\u043b\u044f NotificationController  <\/p>\n<details class=\"spoiler\">\n<summary>NotificationControllerTest<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@WebMvcTest(controllers = NotificationController.class) class NotificationControllerTest {      @Autowired     MockMvc mockMvc;      @Autowired     ObjectMapper objectMapper;      @MockBean     NotificationService notificationService;      @SneakyThrows     @Test     void testNotify() {         ArgumentCaptor&lt;notification&gt; notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class);         Notification notification = Notification.builder()                 .recipient(\"test@email.com\")                 .text(\"some text\")                 .build();          mockMvc.perform(post(\"\/notification\/notify\")                 .contentType(MediaType.APPLICATION_JSON)                 .content(objectMapper.writeValueAsString(notification)))                 .andExpect(status().isOk());          verify(notificationService, times(1)).notify(notificationArgumentCaptor.capture());         assertThat(notificationArgumentCaptor.getValue())                 .usingRecursiveComparison()                 .isEqualTo(notification);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u043b\u0438, \u0441\u0434\u0435\u043b\u0430\u043b\u0438 rebase, \u043f\u0440\u043e\u0433\u043d\u0430\u043b\u0438 \u0441\u0431\u043e\u0440\u043a\u0443 \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0438 \u0437\u0430\u043f\u0443\u0448\u0438\u043b\u0438 \u0432 trunk &#8212; \u044d\u0442\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c  \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u043e\u0439\u0442\u0438 \u0432 \u043f\u0440\u0438\u0432\u044b\u0447\u043a\u0443 \u0438 \u0434\u0435\u043b\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0447\u0430\u0449\u0435.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u044f \u043e\u0447\u0435\u043d\u044c \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0435\u0440\u0432\u044b\u0439 \u043a\u043e\u043c\u043c\u0438\u0442 \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a\u0438\u043c,  \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0431\u044b\u043b \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u043c\u0435\u043d\u044c\u0448\u0435 \u0438 \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u043b \u043d\u0430\u0448\u0435\u043c\u0443 \u0432\u0442\u043e\u0440\u043e\u043c\u0443 \u043f\u0440\u0430\u0432\u0438\u043b\u0443 &#8212; code review \u043c\u0435\u043d\u044c\u0448\u0435 \u0447\u0435\u043c \u0437\u0430 10 \u043c\u0438\u043d\u0443\u0442. <\/p>\n<h3>\u041f\u0440\u043e\u0444\u0438\u043b\u0438<\/h3>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/tv\/yb\/tf\/tvybtfzsv0ertmdg02xfopktcom.png\" width=\"200\" height=\"100\"><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0438 \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435 \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u0435\u043c\u0430 &#8212; \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <a href=\"https:\/\/www.baeldung.com\/spring-profiles\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u043e\u0444\u0438\u043b\u0435\u0439<\/a>. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432\u0441\u0435 \u0432\u0430\u0448\u0435 \u0432\u043e\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c, \u0447\u0442\u043e \u043d\u0430\u043c \u0432\u0434\u0440\u0443\u0433 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u043b\u043e\u0441\u044c \u043e\u043f\u043e\u0432\u0435\u0449\u0430\u0442\u044c \u043a\u043e\u0433\u043e-\u0442\u043e \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e.  \u041d\u0443 \u0447\u0442\u043e \u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u043f\u043e\u0434 \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443. <\/p>\n<details class=\"spoiler\">\n<summary>NotificationTask<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Component @EnableScheduling @RequiredArgsConstructor public class NotificationTask {      private final NotificationService notificationService;      private final NotificationProperties notificationProperties;      @Scheduled(fixedDelay = 1000)     public void notifySubscriber(){         notificationService.notify(Notification.builder()                 .recipient(notificationProperties.getSubscriberEmail())                 .text(\"Notification is worked\")                 .build());     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u043e\u0433\u043e\u043d\u0438\u043c \u043d\u0430\u0448\u0438 \u0442\u0435\u0441\u0442\u044b \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430: <\/p>\n<p><strong>&#171;org.mockito.exceptions.verification.TooManyActualInvocations&#187;<\/strong>. <\/p>\n<p>\u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u0432\u0435\u0434\u044c \u0432 \u043d\u0430\u0448\u0435\u043c \u0442\u0435\u0441\u0442\u0435 \u043e\u0436\u0438\u0434\u0430\u043b\u0441\u044f \u043e\u0434\u0438\u043d \u0432\u044b\u0437\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u0430 sendEmail, \u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0431\u043e\u043b\u044c\u0448\u0435,  \u0442\u0430\u043a \u043a\u0430\u043a \u0442\u0435\u043f\u0435\u0440\u044c \u044d\u0442\u043e\u0442 \u0436\u0435 \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0437\u0430\u0434\u0430\u0447\u0435. <\/p>\n<p>\u041d\u0435 \u043f\u043e\u0440\u044f\u0434\u043e\u043a. \u041c\u043e\u0436\u043d\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0432\u044b\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0435 <strong>initialDelay<\/strong>, \u0447\u0442\u043e \u0431\u044b \u0442\u0435\u0441\u0442 \u0443\u0441\u043f\u0435\u043b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f \u0440\u0430\u043d\u044c\u0448\u0435 \u0447\u0435\u043c \u0437\u0430\u0434\u0430\u0447\u0430, \u043d\u043e \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043a\u043e\u0441\u0442\u044b\u043b\u044c. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u043a\u0430\u043a \u0432\u044b \u0443\u0436\u0435 \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435 \u0434\u043e\u0433\u0430\u0434\u0430\u043b\u0438\u0441\u044c \u043c\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c \u043f\u0440\u043e\u0444\u0438\u043b\u044c.  \u0412\u044b\u043d\u0435\u0441\u0435\u043c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e <strong>@EnableScheduling<\/strong> \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e <strong>@Profile<\/strong> \u0433\u0434\u0435 \u0441\u043a\u0430\u0436\u0435\u043c, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438 \u0432\u0441\u0435\u0433\u0434\u0430, \u043a\u0440\u043e\u043c\u0435 \u043a\u0430\u043a \u0432 \u043f\u0440\u043e\u0444\u0438\u043b\u0435 &#171;test&#187;. <\/p>\n<details class=\"spoiler\">\n<summary>SchedulingConfig<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Profile(\"!test\") @Configuration @EnableScheduling public class SchedulingConfig {} <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u0445, \u0432 <strong>application.yam<\/strong>l \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0444\u0438\u043b\u044f: <\/p>\n<details class=\"spoiler\">\n<summary>application.yaml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>spring:   profiles:     active: test notification:   email-subject: Auto notification   sender-email: robot@somecompany.com <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c, \u0432 \u0442\u0435\u0441\u0442\u0430\u0445, \u0437\u0430\u0434\u0430\u0447\u0438 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f,  \u043d\u043e \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u0437 main \u043c\u0435\u0442\u043e\u0434\u0430, \u0442\u043e \u0437\u0430\u0434\u0430\u0447\u0438 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u0440\u0430\u0432\u043d\u043e \u0442\u0438\u043a\u0430\u0442\u044c. <\/p>\n<p>\u0412 \u0441\u0432\u043e\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u0435 \u044f \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u043f\u0440\u043e\u0444\u0438\u043b\u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043d\u043e \u043d\u0438 \u043a\u0442\u043e \u0432\u0430\u043c \u043d\u0435 \u0437\u0430\u043f\u0440\u0435\u0442\u0438\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0434\u043b\u044f \u0441\u0432\u043e\u0438\u0445 \u0446\u0435\u043b\u0435\u0439, \u0433\u043b\u0430\u0432\u043d\u043e\u0435, \u043a\u0430\u043a \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0441 \u043d\u0438\u043c\u0438 \u043d\u0435 \u043c\u0435\u043b\u044c\u0447\u0438\u0442\u044c \u0438 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0438\u0445 \u043c\u043d\u043e\u0433\u043e. <\/p>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043f\u0440\u043e\u0444\u0438\u043b\u0438 \u0442\u043e\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0438\u043b\u0438 \u0432\u044b\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0446\u0435\u043b\u044b\u0439 \u0441\u043b\u043e\u0439 \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u043b\u043e\u0433\u0438\u043a\u0438,  \u043f\u0440\u0438\u0447\u0435\u043c \u043d\u0430 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0439 \u043e\u0441\u043d\u043e\u0432\u0435, \u0442.\u0435. \u0432\u044b \u043d\u0435 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0435 \u0432\u044b\u043a\u0438\u043d\u0443\u0442\u044c \u044d\u0442\u0443 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u0433\u0434\u0430-\u043d\u0438\u0431\u0443\u0434\u044c \u043f\u043e\u0442\u043e\u043c. \u041f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438 \u043c\u043e\u0433\u0443\u0442 \u0441\u043b\u0443\u0436\u0438\u0442\u044c: \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c, \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0438\u043b\u0438 \u043a\u0430\u043a \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e.<\/p>\n<p>\u0414\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0442\u043e\u0447\u0435\u0447\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043b\u0443\u0447\u0448\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c  <a href=\"https:\/\/trunkbaseddevelopment.com\/feature-flags\/\" rel=\"noopener noreferrer nofollow\">Feature flags<\/a>,  \u043d\u043e \u044d\u0442\u043e\u0442 \u0441\u043f\u043e\u0441\u043e\u0431 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438 \u0443\u0436\u0435 \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0440\u0435\u043b\u0438\u0437\u0430. \u0421\u0434\u0435\u043b\u0430\u043b\u0438 rebase, \u043f\u0440\u043e\u0433\u043d\u0430\u043b\u0438 \u0441\u0431\u043e\u0440\u043a\u0443 \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0438 \u0437\u0430\u043f\u0443\u0448\u0438\u043b\u0438 \u0432 trunk.<\/p>\n<h3>\u041f\u0435\u0440\u0432\u044b\u0439 \u0440\u0435\u043b\u0438\u0437<\/h3>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/2k\/yh\/bl\/2kyhbl23hhz8xsfeezpidiaqjey.png\" width=\"200\" height=\"200\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e\u0442\u0432\u043b\u0435\u0447\u0435\u043c\u0441\u044f \u043e\u0442 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u0440\u0435\u043b\u0438\u0437\u0430\u043c\u0438. \u0412 TBD \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u0434\u0432\u0430 \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0432\u044b\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0440\u0435\u043b\u0438\u0437\u044b: \u043f\u0435\u0440\u0432\u044b\u0439 \u0438\u0437 <a href=\"https:\/\/trunkbaseddevelopment.com\/branch-for-release\/\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043b\u0438\u0437\u043d\u043e\u0439 \u0432\u0435\u0442\u043a\u0438<\/a>, \u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u044f\u043c\u043e \u0438\u0437 <a href=\"https:\/\/trunkbaseddevelopment.com\/release-from-trunk\/\" rel=\"noopener noreferrer nofollow\">trunk<\/a>. \u0417\u0434\u0435\u0441\u044c \u044f \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u043f\u0435\u0440\u0432\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u043a\u043e\u043c\u043c\u0438\u0442 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u0440\u0435\u043b\u0438\u0437, \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043a\u0430\u043a \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u043a\u043e\u043c\u043c\u0438\u0442  \u0432 trunk, \u0442\u0430\u043a \u0438 \u043a\u043e\u043c\u043c\u0438\u0442 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u0432 \u043f\u0440\u043e\u0448\u043b\u043e\u043c,   \u0432\u0441\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0442\u043e\u0433\u043e, \u0438\u0437 \u043a\u0430\u043a\u043e\u0439 \u0440\u0435\u0432\u0438\u0437\u0438\u0438 \u043a\u043e\u0434\u0430 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0440\u0435\u043b\u0438\u0437. <\/p>\n<p>\u0414\u043b\u044f git \u0432\u044b\u043a\u0430\u0447\u0430\u0442\u044c \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u043a\u043e\u043c\u043c\u0438\u0442 \u043c\u043e\u0436\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"bash\">git checkout &lt;hash&gt;<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0440\u0435\u043b\u0438\u0437\u043d\u0443\u044e \u0432\u0435\u0442\u043a\u0443, \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u0442\u0430\u0432\u0438\u043c \u043c\u0435\u0442\u043a\u0443 c \u0432\u0435\u0440\u0441\u0438\u0435\u0439, \u0438 \u043f\u0443\u0448\u0438\u043c \u0432 \u0443\u0434\u0430\u043b\u0435\u043d\u043d\u044b\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439.<\/p>\n<pre><code class=\"bash\">git checkout -b Release_1.0.0 git tag 1.0.0 git push -u origin Release_1.0.0 git push origin 1.0.0 <\/code><\/pre>\n<p>\u0413\u043e\u0442\u043e\u0432\u043e! \u041c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u0438\u0437 \u044d\u0442\u043e\u0439 \u0432\u0435\u0442\u043a\u0435 \u0432 staging, \u0430 \u0437\u0430\u0442\u0435\u043c \u0438 \u0432 production.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0435\u0449\u0451 \u043f\u0430\u0440\u043e\u0447\u043a\u0443 \u043f\u0440\u0430\u0432\u0438\u043b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u0440\u0435\u043b\u0438\u0437\u043d\u044b\u043c\u0438 \u0432\u0435\u0442\u043a\u0430\u043c\u0438: <\/p>\n<p>1) \u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u043d\u0435 \u0432\u0435\u0434\u0443\u0442 \u0432 \u0440\u0435\u043b\u0438\u0437\u043d\u043e\u0439 \u0432\u0435\u0442\u043a\u0438 \u043a\u0430\u043a\u0438\u0435-\u043b\u0438\u0431\u043e \u0440\u0430\u0431\u043e\u0442\u044b <\/p>\n<p>2) \u0420\u0435\u043b\u0438\u0437\u043d\u0430\u044f \u0432\u0435\u0442\u043a\u0430 \u043d\u0435 \u0441\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441 trunk <\/p>\n<p>3) \u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u0435\u043d Hotfix, \u0434\u0435\u043b\u0430\u0435\u043c Cherry-pick \u0438\u0437 trunk \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043c\u0435\u0442\u043a\u0443 \u0441 \u043c\u0438\u043d\u043e\u0440\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0435\u0439<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0440\u0435\u043b\u0438\u0437\u043d\u0430\u044f \u0432\u0435\u0442\u043a\u0430 \u043a\u0430\u043a \u0431\u044b &#171;\u0437\u0430\u043c\u043e\u0440\u0430\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f&#187; \u0438 \u043d\u0443\u0436\u043d\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0438\u0437 \u043d\u0435\u0451 \u0440\u0435\u043b\u0438\u0437 \u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0441\u0435\u0431\u0435 \u043a\u043e\u0434 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0420\u0435\u043b\u0438\u0437\u043d\u044b\u0435 \u0432\u0435\u0442\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u0438 \u0434\u0430\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u043d\u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u043d\u0435 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u043c.<\/p>\n<h3>Feature flags<\/h3>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ka\/oj\/33\/kaoj335m2sfcpvmt3bz0woqvaso.png\" width=\"200\" height=\"200\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u043b\u044f \u0432\u0442\u043e\u0440\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0443 \u043d\u0430\u0441 \u0441\u0442\u043e\u0438\u0442 \u0437\u0430\u0434\u0430\u0447\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0430\u0443\u0434\u0438\u0442\u0430 \u0432 \u043d\u0430\u0448\u0443 \u0441\u0438\u0441\u0442\u0435\u043c\u0443:  \u0442\u0435\u043f\u0435\u0440\u044c \u043a\u0430\u0436\u0434\u043e\u0435 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c\u0441\u044f \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445. \u0422\u043e\u043b\u044c\u043a\u043e \u0432\u043e\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e \u043a\u043e\u0433\u0434\u0430 \u043d\u0430 production \u0435\u0451 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442 \u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u044f\u0442. \u0422\u043e\u0433\u0434\u0430, \u0447\u0442\u043e\u0431\u044b \u043d\u0438 \u043a\u043e\u0433\u043e \u043d\u0435 \u0436\u0434\u0430\u0442\u044c \u0438 \u043d\u0435 \u043e\u0442\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c, \u0442\u043e, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0435\u0439\u0447\u0430\u0441, \u043c\u044b \u043e\u0431\u0435\u0440\u043d\u0435\u043c \u0434\u0430\u043d\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432 <strong>feature flag<\/strong>. <\/p>\n<p>\u0415\u0441\u043b\u0438 \u043a\u0440\u0430\u0442\u043a\u043e, \u044d\u0442\u043e\u0442 \u043f\u0440\u0438\u0435\u043c \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u0432\u043d\u0435\u0434\u0440\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0444\u0438\u0447\u0443 \u0443\u0436\u0435 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0440\u0435\u043b\u0438\u0437\u0435, \u0430 \u0432\u043e\u0442 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0435\u0451 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u0430 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438, \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0439\u0434\u0435\u0442 \u043d\u0435 \u0442\u0430\u043a, \u0444\u0438\u0447\u0443 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043d\u043e\u0432\u0430 \u0432\u044b\u043a\u043b\u044e\u0447\u0438\u0442\u044c. <\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445.  \u0411\u0414 \u043d\u0430 production \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 <strong>oracle <\/strong>(\u044d\u0442\u043e \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u0432\u0430\u0436\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430), \u0430 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <strong>h2<\/strong>. <\/p>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 (\u0411\u0414)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>    &lt;dependency&gt;         &lt;groupid&gt;org.springframework.boot&lt;\/groupid&gt;         &lt;artifactid&gt;spring-boot-starter-data-jpa&lt;\/artifactid&gt;     &lt;\/dependency&gt;     &lt;dependency&gt;         &lt;groupid&gt;com.oracle.ojdbc&lt;\/groupid&gt;         &lt;artifactid&gt;ojdbc10&lt;\/artifactid&gt;     &lt;\/dependency&gt;     &lt;dependency&gt;         &lt;groupid&gt;com.h2database&lt;\/groupid&gt;         &lt;artifactid&gt;h2&lt;\/artifactid&gt;     &lt;\/dependency&gt; <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441, \u0433\u0434\u0435 \u0431\u0443\u0434\u0435\u043c \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u043b\u044f \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u0444\u0438\u0447. \u041f\u0440\u0438\u043c\u0435\u043c \u043a\u043e\u043d\u0432\u0435\u043d\u0446\u0438\u044e, \u0447\u0442\u043e \u0432\u0441\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0432 \u044d\u0442\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c <strong>boolean<\/strong>. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0442\u0443\u0434\u0430 \u0444\u043b\u0430\u0433 &#171;persistence&#187;, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0438 \u0432\u044b\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0439 \u0432 \u0431\u0430\u0437\u0443.  <\/p>\n<details class=\"spoiler\">\n<summary>FeatureProperties<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Getter @Setter @Component @ConfigurationProperties(prefix = \"features.active\") public class FeatureProperties {     boolean persistence; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u0440\u0430\u0437\u0443 \u0437\u0430\u043f\u0438\u0448\u0435\u043c \u0432 application.yaml \u0432 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u0445 <strong>features.active.persistence: on<\/strong> (spring \u0441\u0430\u043c \u043f\u043e\u0439\u043c\u0435\u0442, \u0447\u0442\u043e on==true).<\/p>\n<blockquote>\n<p>\u0422\u043e\u043b\u044c\u043a\u043e \u043d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442, \u0447\u0442\u043e\u0431\u044b \u0432\u043a\u043b\u044e\u0447\u0438\u043b\u043e\u0441\u044c \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0432 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.  <\/p>\n<\/blockquote>\n<p>\u041d\u0430\u0448\u0443 \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u0435\u0440\u0435\u0434\u0435\u043b\u044b\u0432\u0430\u0435\u043c \u0432 Entity. <\/p>\n<blockquote>\n<p>\u041e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0439!   <\/p>\n<\/blockquote>\n<details class=\"spoiler\">\n<summary>Notification (Entity)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Entity @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor public class Notification {     @Id     @GeneratedValue     private Long id;     private String text;     private String recipient;     @CreationTimestamp     private LocalDateTime time; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 <\/p>\n<details class=\"spoiler\">\n<summary>NotificationRepository<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public interface NotificationRepository extends CrudRepository&lt;notification, long=\"\"&gt; { } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 NotificationService \u0434\u043e\u0431\u0430\u0432\u0438\u043c NotificationRepository \u0438 FeatureProperties \u043a\u0430\u043a \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u0432 \u043a\u043e\u043d\u0446\u0435 \u043c\u0435\u0442\u043e\u0434\u0430 <strong>notify <\/strong>\u0432\u044b\u0437\u043e\u0432\u0435\u043c \u043c\u0435\u0442\u043e\u0434 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f <strong>save<\/strong>, \u043e\u0431\u0435\u0440\u043d\u0443\u0432 \u0435\u0433\u043e \u0432 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 <strong>if<\/strong>.  <\/p>\n<details class=\"spoiler\">\n<summary>NotificationService (Feature flag)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Service @RequiredArgsConstructor public class NotificationService {      private final EmailSender emailSender;      private final NotificationProperties notificationProperties;      private final FeatureProperties featureProperties;      @Nullable     private final NotificationRepository notificationRepository;      public void notify(Notification notification){         String from = notificationProperties.getSenderEmail();         String to = notification.getRecipient();         String subject = notificationProperties.getEmailSubject();         String text = notification.getText();         emailSender.sendEmail(from, to, subject, text);          if(featureProperties.isPersistence()){             notificationRepository.save(notification);         }     }  } <\/code><\/pre>\n<blockquote>\n<p>\u0417\u0430\u0431\u0435\u0433\u0430\u044f \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0432\u043f\u0435\u0440\u0435\u0434, \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f @Nullable \u0434\u043b\u044f \u043f\u043e\u043b\u044f NotificationRepository \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u0430,    \u0447\u0442\u043e\u0431\u044b Spring \u043d\u0435 \u043f\u0430\u0434\u0430\u043b \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 UnsatisfiedDependencyException, \u0435\u0441\u043b\u0438 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u0442 \u0442\u0430\u043a\u043e\u0439 \u0431\u0438\u043d \u0443 \u0441\u0435\u0431\u044f \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435. <\/p>\n<\/blockquote>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0442\u0435\u0441\u0442\u044b, \u0438 \u0443\u0432\u0438\u0434\u0435\u0442\u044c, \u0447\u0442\u043e \u0432\u0441\u0435 \u043e\u043d\u0438 \u043f\u0440\u043e\u0448\u043b\u0438, \u043d\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u0442\u044c url \u0434\u043b\u044f \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f. <\/p>\n<p>\u0418\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u043a\u0430\u043a \u0438 \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u0447 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e.  \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0433\u0434\u0435 \u0443\u043a\u0430\u0436\u0435\u043c, \u0447\u0442\u043e \u0430\u0432\u0442\u043e\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0430,  \u0435\u0441\u043b\u0438 \u0444\u043b\u0430\u0433 <strong>features.active.persistence: off<\/strong> (spring \u0441\u0430\u043c \u043f\u043e\u0439\u043c\u0435\u0442, \u0447\u0442\u043e off==false).<\/p>\n<details class=\"spoiler\">\n<summary>DataJpaConfig<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Configuration @ConditionalOnProperty(prefix = \"features.active\", name = \"persistence\",                         havingValue = \"false\", matchIfMissing = true) @EnableAutoConfiguration(exclude = {         DataSourceAutoConfiguration.class,         DataSourceTransactionManagerAutoConfiguration.class,         HibernateJpaAutoConfiguration.class}) public class DataJpaConfig { } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0444\u043b\u0430\u0433\u043e\u043c <strong>features.active.persistence: off<\/strong> \u0432 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u0445. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442, \u043d\u043e \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043d\u0438 \u043a\u0430\u043a\u0438\u0445 \u0431\u0438\u043d\u043e\u0432 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441 \u0440\u0430\u0431\u043e\u0442\u043e\u0439 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<blockquote>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0444\u043b\u0430\u0433\u0430\u043c\u0438 \u0432 \u0441\u0440\u0435\u0434\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f, \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c spring \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0434\u043b\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0432\u043e\u0439\u0441\u0442\u0432, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440: <\/p>\n<p>&#8212;spring.config.additional-location=file:\/etc\/config\/features.yaml<\/p>\n<\/p>\n<p>\u0418\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 VM, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<p>-Dfeatures.active.persistence=true<\/p>\n<\/p>\n<\/blockquote>\n<p>\u041f\u0440\u0430\u0432\u0438\u043b \u0441 \u0444\u043b\u0430\u0433\u0430\u043c\u0438 \u0431\u0443\u0434\u0435\u0442 \u0434\u0432\u0430:<\/p>\n<p>1) \u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u0438 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u0444\u043b\u0430\u0433 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0443\u0436\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c<\/p>\n<p> 2) \u041c\u0435\u0441\u0442 \u0432 \u043a\u043e\u0434\u0435, \u0433\u0434\u0435 \u0438\u0434\u0435\u0442 \u0432\u0435\u0442\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443 \u0438 \u0442\u043e\u043c\u0443 \u0436\u0435 feature \u0444\u043b\u0430\u0433\u0443, \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e<\/p>\n<p>\u041f\u043e \u0432\u0442\u043e\u0440\u043e\u043c\u0443 \u043f\u0440\u0430\u0432\u0438\u043b\u0443 \u043f\u043e\u044f\u0441\u043d\u044e \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435. \u0415\u0441\u043b\u0438, \u0432\u0430\u0448\u0430 \u043d\u043e\u0432\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0432 feature \u0444\u043b\u0430\u0433,  \u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0430\u0441 \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u0432\u0438\u0434\u0430: &#171;if (flag) {\u2026}&#187; \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u0435\u0441\u0442\u0430\u0445 \u0441\u0440\u0430\u0437\u0443, \u0442\u043e \u0432\u0430\u043c \u0441\u0442\u043e\u0438\u0442 \u0437\u0430\u0434\u0443\u043c\u0430\u0442\u044c\u0441\u044f \u043b\u0438\u0431\u043e \u043d\u0430\u0434 \u0434\u0438\u0437\u0430\u0439\u043d\u043e\u043c \u0432\u0430\u0448\u0435\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u043b\u0438\u0431\u043e \u043e \u043f\u0440\u0438\u0435\u043c\u0435 &#171;\u0432\u0435\u0442\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0438&#187;, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u0430\u043a \u0440\u0430\u0437 \u0441\u0435\u0439\u0447\u0430\u0441 \u0438 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c. <\/p>\n<h3>Branch by Abstraction<\/h3>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/lc\/ta\/qv\/lctaqvsfng0iufts2quesg9doj8.png\" width=\"200\" height=\"200\"><figcaption><\/figcaption><\/figure>\n<p>\u0412 \u0442\u0440\u0435\u0442\u044c\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438, \u043d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0439. <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u0445, \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u044c \u0442\u0438\u043f \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f: EMAIL, SMS \u0438\u043b\u0438 PUSH. \u0421\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0432\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 &#171;\u043e\u0442\u043f\u0440\u0430\u0432\u0449\u0438\u043a\u0430&#187;  \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u0430 \u0435\u0449\u0451 \u043b\u043e\u0433\u0438\u043a\u0443 \u0432 \u0441\u0430\u043c\u043e\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e.<\/p>\n<p>\u042d\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0441\u0435\u0440\u044c\u0435\u0437\u043d\u0430\u044f \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u043c \u0441 \u043d\u0435\u0439 \u0442\u043e\u0440\u043e\u043f\u0438\u0442\u0441\u044f, \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0442\u0449\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u0434\u0430 \u0442\u0430\u043a \u0447\u0442\u043e\u0431\u044b \u0432 \u0435\u0433\u043e \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043b\u043e \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432. \u041f\u043e\u044d\u0442\u043e\u043c\u0443  \u043c\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u0432 Git \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0432\u0435\u0442\u043a\u0443, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u0434, \u0430 \u0441\u0434\u0435\u043b\u0430\u0435\u043c  \u0432\u0435\u0442\u043a\u0443 \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/martinfowler.com\/bliki\/BranchByAbstraction.html\" rel=\"noopener noreferrer nofollow\">\u0432\u0435\u0442\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0438<\/a>.  <\/p>\n<p>\u0420\u0435\u0446\u0435\u043f\u0442 \u043e\u0442 \u041c\u0430\u0440\u0442\u0438\u043d\u0430 \u0424\u0430\u0443\u043b\u0435\u0440\u0430 \u043f\u0440\u043e\u0441\u0442: <\/p>\n<p>1) \u0412\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u043c\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 <\/p>\n<p>2) \u0417\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0440\u044f\u043c\u043e\u0439 \u0432\u044b\u0437\u043e\u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0435 \u043d\u0430 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0443  <\/p>\n<p>3) \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <\/p>\n<p>4) \u041f\u043e\u0434\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u0430 \u043d\u043e\u0432\u0443\u044e <\/p>\n<p>5) \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0441\u0442\u0430\u0440\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e <\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 NotificationService \u0432\u043c\u0435\u0441\u0442\u043e \u043a\u043b\u0430\u0441\u0441\u0430, \u0430 \u0441\u0430\u043c \u043a\u043b\u0430\u0441\u0441 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u0442\u044c \u0432  EmailNotificationService. \u0412 <strong>Inellij IDEA <\/strong>\u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u0430:<\/p>\n<p>1) \u041f\u0440\u0430\u0432\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043f\u043e \u043a\u043b\u0430\u0441\u0441\u0443, \u0432\u044b\u0431\u0440\u0430\u0442\u044c Refactor\/Extract interface\u2026 <\/p>\n<p>2) \u0412\u044b\u0431\u0440\u0430\u0442\u044c \u043e\u043f\u0446\u0438\u044e &#171;Rename original class and use interface where possible&#187; <\/p>\n<p>3) \u0412 \u043f\u043e\u043b\u0435 &#171;Rename implementation class to&#187; \u0432\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c &#171;EmailNotificationService&#187; <\/p>\n<p>4) \u0412 &#171;Members to from interface&#187; \u043d\u0430\u0436\u0430\u0442\u044c \u0433\u0430\u043b\u043e\u0447\u043a\u0443 \u043d\u0430\u043f\u0440\u043e\u0442\u0438\u0432 \u043c\u0435\u0442\u043e\u0434\u0430 &#171;notify&#187; <\/p>\n<p>5) \u041d\u0430\u0436\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0443 &#171;Refactor&#187;<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432\u0441\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 NotificationService,  \u0430 \u0440\u044f\u0434\u043e\u043c \u0432 \u043f\u0430\u043a\u0435\u0442\u0435 \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f EmailNotificationService \u0433\u0434\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u0430\u0440\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f.<\/p>\n<p>\u0421\u0434\u0435\u043b\u0430\u043b\u0438 rebase, \u043f\u0440\u043e\u0433\u043d\u0430\u043b\u0438 \u0441\u0431\u043e\u0440\u043a\u0443 \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0438 \u0437\u0430\u043f\u0443\u0448\u0438\u043b\u0438 \u0432 trunk.  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u043f\u043e\u043a\u043e\u0439\u043d\u043e \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0443\u0436\u0435 \u043d\u0430\u0434 \u043d\u043e\u0432\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u043b\u0435 \u0441 \u0442\u0438\u043f\u043e\u043c \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f, \u043f\u0443\u0441\u0442\u044c \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e Enum.<\/p>\n<details class=\"spoiler\">\n<summary>NotificationType<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">public enum NotificationType {     EMAIL, SMS, PUSH, UNKNOWN }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0430\u043a \u0436\u0435 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u0432\u0430 \u043d\u043e\u0432\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 &#171;\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044f&#187;:<\/p>\n<p>SmsSender \u0438 PushSender. <\/p>\n<details class=\"spoiler\">\n<summary>Senders<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Slf4j @Component public class SmsSender {     \/**      * \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 \u0442\u0435\u043b\u0435\u0444\u043e\u043d      *\/     public void sendSms(String phoneNumber, String text){         log.info(\"Send sms {}\\nto: {}\\nwith text: {}\", phoneNumber, text);     }     }  @Slf4j @Component public class PushSender {         \/**      * \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 push \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f      *\/     public void push(String id, String text){         log.info(\"Push {}\\nto: {}\\nwith text: {}\", id, text);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041d\u043e\u0432\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043d\u0430\u0437\u043e\u0432\u0435\u043c MultipleNotificationService, \u0438 \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043f\u0438\u0448\u0435\u043c &#171;\u0432 \u043b\u043e\u0431&#187;.<\/p>\n<details class=\"spoiler\">\n<summary>MultipleNotificationService &#8212; switch case<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Service @RequiredArgsConstructor public class MultipleNotificationService implements NotificationService {      private final EmailSender emailSender;      private final PushSender pushSender;      private final SmsSender smsSender;      private final NotificationProperties notificationProperties;      private final NotificationRepository notificationRepository;       @Override     public void notify(Notification notification) {         String from = notificationProperties.getSenderEmail();         String to = notification.getRecipient();         String subject = notificationProperties.getEmailSubject();         String text = notification.getText();          NotificationType notificationType = notification.getNotificationType();         switch (notificationType!=null ? notificationType : NotificationType.UNKNOWN) {             case PUSH:                 pushSender.push(to, text);                 break;             case SMS:                 smsSender.sendSms(to, text);                 break;             case EMAIL:                 emailSender.sendEmail(from, to, subject, text);                 break;             default:                 throw new UnsupportedOperationException(\"Unknown notification type: \" + notification.getNotificationType());          }         notificationRepository.save(notification);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0432 \u0442\u0435\u0441\u0442\u044b, \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043c, \u0447\u0442\u043e NotificationServiceTest \u0441\u0442\u0430\u043b \u043f\u0430\u0434\u0430\u0442\u044c \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439: <\/p>\n<p> <strong>&#171;expected single matching bean but found 2: emailNotificationService, multipleNotificationService&#187;<\/strong>.<\/p>\n<p>\u0412\u044b\u043b\u0435\u0447\u0438\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 <strong>@Primary<\/strong> \u043d\u0430\u0434 \u0441\u0442\u0430\u0440\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 &#8212; EmailNotificationService. <\/p>\n<p>@Primary &#8212; \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u0431\u0438\u043d \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u043d\u044b\u043c \u0434\u043b\u044f \u0438\u043d\u044a\u0435\u043a\u0446\u0438\u0438, \u043d\u043e \u0432 \u0442\u043e\u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u0431\u0438\u043d\u044b \u0441 \u0442\u0435\u043c \u0436\u0435 \u0442\u0438\u043f\u043e\u043c \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0434\u0443\u0442\u0441\u044f \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u0438 \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0432\u043d\u0435\u0434\u0440\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0432 \u0442\u0435\u0441\u0442.<\/p>\n<p>\u0414\u0440\u0443\u0433\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 &#8212; \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u0431\u0440\u0430\u0442\u044c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e <strong>@Service<\/strong> \u0438\u0437 \u043d\u043e\u0432\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u043c \u0441\u0430\u043c\u044b\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0432 \u0435\u0451 \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430,  \u0430 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0438\u043b\u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c Spring \u0442\u0435\u0441\u0442, \u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 unit \u0442\u0435\u0441\u0442, \u0433\u0434\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0441\u0430\u043c\u0438\u043c \u0447\u0435\u0440\u0435\u0437 &#171;new&#187;. <\/p>\n<p>\u042f \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0441\u044c \u043f\u0435\u0440\u0432\u044b\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u043c \u0438 \u043d\u0430\u043f\u0438\u0448\u0443 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 Spring \u0442\u0435\u0441\u0442 \u0434\u043b\u044f \u043d\u043e\u0432\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>MultipleNotificationServiceTest<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@SpringBootTest class MultipleNotificationServiceTest {      @Autowired     MultipleNotificationService multipleNotificationService;      @Autowired     NotificationProperties properties;      @MockBean     EmailSender emailSender;      @MockBean     PushSender pushSender;      @MockBean     SmsSender smsSender;      @Test     void emailNotification() {         Notification notification = Notification.builder()                 .recipient(\"test@email.com\")                 .text(\"some text\")                 .notificationType(NotificationType.EMAIL)                 .build();         multipleNotificationService.notify(notification);          ArgumentCaptor&lt;string&gt; emailCapture = ArgumentCaptor.forClass(String.class);         verify(emailSender, times(1))                 .sendEmail(emailCapture.capture(),emailCapture.capture(),emailCapture.capture(),emailCapture.capture());         assertThat(emailCapture.getAllValues())                 .containsExactly(properties.getSenderEmail(),                         notification.getRecipient(),                         properties.getEmailSubject(),                         notification.getText()                 );     }      @Test     void pushNotification() {         Notification notification = Notification.builder()                 .recipient(\"id:1171110\")                 .text(\"some text\")                 .notificationType(NotificationType.PUSH)                 .build();         multipleNotificationService.notify(notification);          ArgumentCaptor&lt;string&gt; captor = ArgumentCaptor.forClass(String.class);         verify(pushSender, times(1))                 .push(captor.capture(),captor.capture());          assertThat(captor.getAllValues())                 .containsExactly(notification.getRecipient(),  notification.getText());     }      @Test     void smsNotification() {         Notification notification = Notification.builder()                 .recipient(\"+79157775522\")                 .text(\"some text\")                 .notificationType(NotificationType.SMS)                 .build();         multipleNotificationService.notify(notification);          ArgumentCaptor&lt;string&gt; captor = ArgumentCaptor.forClass(String.class);         verify(smsSender, times(1))                 .sendSms(captor.capture(),captor.capture());          assertThat(captor.getAllValues())                 .containsExactly(notification.getRecipient(),  notification.getText());     }      @Test     void unsupportedNotification() {         Notification notification = Notification.builder()                 .recipient(\"+79157775522\")                 .text(\"some text\")                 .build();         assertThrows(UnsupportedOperationException.class, () -&gt; {             multipleNotificationService.notify(notification);         });     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u0434\u0435\u043b\u0430\u043b\u0438 rebase, \u043f\u0440\u043e\u0433\u043d\u0430\u043b\u0438 \u0441\u0431\u043e\u0440\u043a\u0443 \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438, \u0437\u0430\u043f\u0443\u0448\u0438\u043b\u0438 \u0432 trunk, \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u043e \u0448\u0430\u043f\u043a\u0435 \u0437\u0430 switch-case.<\/p>\n<blockquote>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u043a\u0440\u0430\u0441\u0438\u0432\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0448\u0430\u0431\u043b\u043e\u043d &#171;<a href=\"https:\/\/medium.com\/@ravthiru\/strategy-design-pattern-with-in-spring-boot-application-2ff5a7486cd8\" rel=\"noopener noreferrer nofollow\">\u0421\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044f<\/a>&#171;,   \u043d\u043e \u0442\u0443\u0442 \u0435\u0441\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0443 \u0432\u0441\u0435\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 &#171;\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u0435\u0439&#187; \u0440\u0430\u0437\u043d\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b, \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043a\u0430\u043a \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u0438 \u0431\u0443\u0434\u0435\u0442 \u0432  \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438, \u0432\u0435\u0434\u044c \u043e\u0431\u044b\u0447\u043d\u043e \u0442\u0430\u043a\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432\u043d\u0435\u0448\u043d\u0438\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c.  \u0420\u0435\u0448\u0438\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430\u043c\u0438 \u043c\u043e\u0436\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0448\u0430\u0431\u043b\u043e\u043d\u0430 &#171;<a href=\"https:\/\/springframework.guru\/gang-of-four-design-patterns\/adapter-pattern\/\" rel=\"noopener noreferrer nofollow\">\u0410\u0434\u0430\u043f\u0442\u0435\u0440<\/a>&#171;.  \u0420\u0430\u0441\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0437\u0434\u0435\u0441\u044c \u043d\u0435 \u0431\u0443\u0434\u0443, \u0441\u0442\u0430\u0442\u044c\u044f \u0432\u0441\u0451 \u0442\u0430\u043a\u0438 \u043e \u0434\u0440\u0443\u0433\u043e\u043c, \u043d\u043e \u043a\u043e\u0434 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435  \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0443 \u043c\u0435\u043d\u044f \u043d\u0430 <a href=\"https:\/\/github.com\/zizitop13\/spring-branch-by-abstraction\" rel=\"noopener noreferrer nofollow\">GitHub<\/a>.<\/p>\n<\/blockquote>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u0432\u0441\u0435 \u043a\u0440\u0430\u0441\u0438\u0432\u043e, \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0435\u0449\u0451 \u0440\u0430\u0437: rebase, \u043f\u0440\u043e\u0433\u043d\u0430\u043b\u0438 \u0441\u0431\u043e\u0440\u043a\u0443 \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438, \u0437\u0430\u043f\u0443\u0448\u0438\u043b\u0438 \u0432 trunk. <\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u043a\u043e\u0434 \u043d\u0435 \u0432\u044b\u0437\u0432\u0430\u043b \u043d\u0438 \u0443 \u043a\u043e\u0433\u043e \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u0430, \u0438 \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443. \u0414\u0435\u043b\u0430\u0442\u044c \u0431\u0443\u0434\u0435\u043c \u044d\u0442\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u0441\u0435 \u0442\u043e\u0433\u043e \u0436\u0435 feature \u0444\u043b\u0430\u0433\u0430.<\/p>\n<p>\u0412 \u043a\u043b\u0430\u0441\u0441 \u0441 \u0444\u043b\u0430\u0433\u0430\u043c\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u043e\u0432\u044b\u0439:<\/p>\n<pre><code class=\"java\">  boolean multipleSenders;<\/code><\/pre>\n<p>\u041d\u0430\u0434 \u043a\u043b\u0430\u0441\u0441\u043e\u043c EmailNotificationService \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e \u0441 \u0443\u0441\u043b\u043e\u0432\u0438\u0435\u043c (\u043d\u0438 \u0432 \u043a\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435 \u0443\u0434\u0430\u043b\u044f\u0442\u044c @Primary): <\/p>\n<p>&#171;\u0412\u044b\u043a\u043b\u044e\u0447\u0438\u0442\u044c, \u0442\u043e\u043b\u044c\u043a\u043e, \u0435\u0441\u043b\u0438 \u0444\u043b\u0430\u0433 features.active.multiple-senders \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d (matchIfMissing) \u0438 \u0440\u0430\u0432\u0435\u043d false&#187;<\/p>\n<pre><code class=\"java\">@ConditionalOnProperty(prefix = \"features.active\",                         name = \"multiple-senders\",                         havingValue = \"false\",                         matchIfMissing = true)<\/code><\/pre>\n<p>\u041d\u0430\u0434 MultipleNotificationService \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e \u0441 &#171;\u0437\u0435\u0440\u043a\u0430\u043b\u044c\u043d\u044b\u043c&#187; \u0443\u0441\u043b\u043e\u0432\u0438\u0435\u043c:<\/p>\n<p>&#171;\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c, \u0442\u043e\u043b\u044c\u043a\u043e, \u0435\u0441\u043b\u0438 \u0444\u043b\u0430\u0433 features.active.multiple-senders \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d (matchIfMissing) \u0438\u043b\u0438 \u0440\u0430\u0432\u0435\u043d true&#187;<\/p>\n<pre><code class=\"java\">@ConditionalOnProperty(prefix = \"features.active\",                         name = \"multiple-senders\",                         havingValue = \"true\",                        matchIfMissing = true)<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0432 \u0442\u0435\u0441\u0442\u0430\u0445 \u0443 \u043d\u0430\u0441 \u043e\u043a\u0430\u0436\u0443\u0442\u0441\u044f \u043e\u0431\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0430 \u0432\u043e\u0442 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0430.  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u043d\u043e\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u043a\u0430\u0442\u0430\u043d\u0430, \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 feature \u0444\u043b\u0430\u0433\u043e\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0438 \u0441\u0442\u0430\u0440\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e,  \u0430 \u0432\u043e\u0442 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435 \u0442\u0430\u043a\u0438 \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c.<\/p>\n<p>\u0418 \u0441\u043d\u043e\u0432\u0430 rebase, \u043f\u0440\u043e\u0433\u043d\u0430\u043b\u0438 \u0441\u0431\u043e\u0440\u043a\u0443 \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438, \u0437\u0430\u043f\u0443\u0448\u0438\u043b\u0438 \u0432 trunk. \u0412\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043b\u0430 \u0432\u0430\u0448 \u043a\u043e\u0434 \u0438 \u0431\u043b\u0430\u0433\u043e\u043f\u043e\u043b\u0443\u0447\u043d\u043e \u0437\u0430\u0431\u044b\u043b\u0430, \u0447\u0442\u043e \u0443 \u0432\u0430\u0441 \u0435\u0449\u0451 \u0435\u0441\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0430 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0435 \u0441\u043a\u0430\u0437\u0430\u043b\u0438 \u0441 \u043a\u0430\u043a\u0438\u043c \u0442\u0438\u043f\u043e\u043c \u0435\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f. <\/p>\n<p>\u041d\u0430 production \u0437\u0430\u043c\u0435\u0442\u0438\u043b\u0438, \u0447\u0442\u043e \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f, \u043d\u043e \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f feature \u0444\u043b\u0430\u0433\u0443 \u0432\u0441\u0435 \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u043e\u0442\u043a\u0430\u0442\u0438\u043b\u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e. <\/p>\n<p>\u041a\u043e\u043c\u0430\u043d\u0434\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u044b\u0434\u0430\u043b\u0438 \u043b\u043e\u0433\u0438, \u043e\u043d\u0430 \u043f\u0440\u0438\u043d\u044f\u043b\u0430\u0441\u044c \u0437\u0430 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435, \u0438 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u0431\u0434\u0443\u043c\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c Hotfix, \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c code review \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0447\u0442\u043e\u0431\u044b \u0431\u043e\u043b\u0435\u0435 \u043d\u0435 \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u043c\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u043c\u0438\u2026 \u043d\u043e \u044d\u0442\u043e \u0443\u0436\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u0434\u0440\u0443\u0433\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f, \u0430 \u043d\u0430\u043c \u043f\u043e\u0440\u0430 \u043f\u043e\u0434\u0432\u043e\u0434\u0438\u0442\u044c \u0438\u0442\u043e\u0433\u0438.<\/p>\n<h3>\u0418\u0442\u043e\u0433\u0438<\/h3>\n<p>Trunk Based Development &#8212; \u043e\u0442\u043b\u0438\u0447\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u0432\u0435\u0442\u0432\u043b\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0430\u043a\u043e\u043d\u0435\u0446-\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0432\u0430\u043c \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u0441\u044f \u043e\u0442 \u043a\u043e\u0448\u043c\u0430\u0440\u0430 \u0441\u043b\u0438\u044f\u043d\u0438\u044f \u0432\u0435\u0442\u043e\u043a, \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u043d\u0430\u0434 \u043a\u043e\u0434\u043e\u043c, \u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0434\u0438\u0441\u0446\u0438\u043f\u043b\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439, \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442 &#171;\u0442\u0435\u043d\u0435\u0432\u043e\u0435 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435&#187; \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u0435\u043c\u0430 \u0432 \u043e\u0431\u044b\u0434\u0435\u043d\u043d\u043e\u0441\u0442\u044c. <\/p>\n<p>Trunk Based Development &#8212; \u043e\u0447\u0435\u043d\u044c \u0433\u0438\u0431\u043a\u0430\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433\u0438\u044f, \u0443 \u043d\u0435\u0451 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0440\u0438\u0430\u0446\u0438\u0439 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442, \u0438 \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0434\u043b\u044f \u0435\u0451 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Spring Boot, \u043d\u043e \u043d\u0430\u0434\u0435\u044e\u0441\u044c \u044f \u0441\u043c\u043e\u0433 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0441 \u043d\u0438\u043c \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0438 \u0443\u0434\u043e\u0431\u043d\u043e.<\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0432\u0441\u0451, \u0432\u043d\u0438\u0437\u0443 \u0431\u0443\u0434\u0443\u0442 \u0432\u0441\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u0438\u0437 \u0441\u0442\u0430\u0442\u044c\u0438,  \u0441\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435!<\/p>\n<h3>\u0421\u0441\u044b\u043b\u043a\u0438<\/h3>\n<p><a href=\"https:\/\/github.com\/zizitop13\/spring-branch-by-abstraction\" rel=\"noopener noreferrer nofollow\">\u041c\u043e\u0439 \u043a\u043e\u0434 \u043d\u0430 GitHub<\/a><\/p>\n<p><a href=\"https:\/\/trunkbaseddevelopment.com\/\" rel=\"noopener noreferrer nofollow\">TBD<\/a><\/p>\n<p><a href=\"https:\/\/start.spring.io\/\" rel=\"noopener noreferrer nofollow\">spring initializr<\/a><\/p>\n<p><a href=\"https:\/\/www.baeldung.com\/configuration-properties-in-spring-boot\" rel=\"noopener noreferrer nofollow\">ConfigurationProperties<\/a><\/p>\n<p><a href=\"https:\/\/www.baeldung.com\/spring-profiles\" rel=\"noopener noreferrer nofollow\">Spring profiles<\/a><\/p>\n<p><a href=\"https:\/\/trunkbaseddevelopment.com\/feature-flags\/\" rel=\"noopener noreferrer nofollow\">Feature flags<\/a><\/p>\n<p><a href=\"https:\/\/trunkbaseddevelopment.com\/branch-for-release\/\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043b\u0438\u0437\u043d\u0430\u044f \u0432\u0435\u0442\u043a\u0430<\/a><\/p>\n<p><a href=\"https:\/\/trunkbaseddevelopment.com\/release-from-trunk\/\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043b\u0438\u0437 \u0438\u0437 trunk<\/a><\/p>\n<p><a href=\"https:\/\/martinfowler.com\/bliki\/BranchByAbstraction.html\" rel=\"noopener noreferrer nofollow\">Branch by abstraction<\/a><\/p>\n<p><a href=\"https:\/\/medium.com\/@ravthiru\/strategy-design-pattern-with-in-spring-boot-application-2ff5a7486cd8\" rel=\"noopener noreferrer nofollow\">\u0421\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044f<\/a><\/p>\n<p><a href=\"https:\/\/springframework.guru\/gang-of-four-design-patterns\/adapter-pattern\/\" rel=\"noopener noreferrer nofollow\">\u0410\u0434\u0430\u043f\u0442\u0435\u0440<\/a> <\/p>\n<\/p>\n<\/div>\n<p> \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\/post\/534882\/\"> https:\/\/habr.com\/ru\/post\/534882\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! <\/p>\n<p>\u0417\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0430\u0441\u044c \u043e\u0441\u0435\u043d\u044c, \u0437\u0438\u043c\u0430 \u0432\u0441\u0442\u0443\u043f\u0438\u043b\u0430 \u0432 \u0441\u0432\u043e\u0438 \u0437\u0430\u043a\u043e\u043d\u043d\u044b\u0435 \u043f\u0440\u0430\u0432\u0430, \u043b\u0438\u0441\u0442\u044c\u044f \u0443\u0436\u0435 \u0434\u0430\u0432\u043d\u043e \u043e\u043f\u0430\u043b\u0438 \u0438 \u043f\u0435\u0440\u0435\u043f\u0443\u0442\u0430\u043d\u043d\u044b\u0435 \u0432\u0435\u0442\u0432\u0438 \u043a\u0443\u0441\u0442\u0430\u0440\u043d\u0438\u043a\u043e\u0432 \u043d\u0430\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u044e\u0442 \u043c\u0435\u043d\u044f  \u043d\u0430 \u043c\u044b\u0441\u043b\u0438 \u043e \u043c\u043e\u0451\u043c \u0440\u0430\u0431\u043e\u0447\u0435\u043c Git \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438\u2026  \u041d\u043e \u0432\u043e\u0442 \u043d\u0430\u0447\u0430\u043b\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442: \u043d\u043e\u0432\u0430\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430, \u0447\u0438\u0441\u0442\u044b\u0439, \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0432\u044b\u043f\u0430\u0432\u0448\u0438\u0439 \u0441\u043d\u0435\u0433 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439. &#171;\u0422\u0443\u0442 \u0432\u0441\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e \u0434\u0440\u0443\u0433\u043e\u043c\u0443&#187; &#8212; \u0434\u0443\u043c\u0430\u044e \u044f \u0438 \u043d\u0430\u0447\u0438\u043d\u0430\u044e &#171;\u0433\u0443\u0433\u043b\u0438\u0442\u044c&#187; \u043f\u0440\u043e Trunk Based Development. <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u043d\u0438\u043a\u0430\u043a \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c git flow, \u0432\u0430\u043c \u043d\u0430\u0434\u043e\u0435\u043b\u0438 \u043a\u0443\u0447\u0438 \u044d\u0442\u0438\u0445 \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0445 \u0432\u0435\u0442\u043e\u043a \u0438 \u043f\u0440\u0430\u0432\u0438\u043b \u0434\u043b\u044f \u043d\u0438\u0445, \u0435\u0441\u043b\u0438 \u0432 \u0432\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432\u0435\u0442\u043a\u0438 \u0432\u0438\u0434\u0430 &#171;develop\/ivanov&#187;, \u0442\u043e \u0434\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u0432 \u043f\u043e\u0434 \u043a\u0430\u0442!  \u0422\u0430\u043c \u044f \u043f\u0440\u043e\u0431\u0435\u0433\u0443\u0441\u044c \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u043c Trunk Based Development \u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f Spring Boot.<\/p>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<h3>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h3>\n<p>Trunk Based Development (<a href=\"https:\/\/trunkbaseddevelopment.com\/\" rel=\"noopener noreferrer nofollow\">TBD<\/a>) \u044d\u0442\u043e \u043f\u043e\u0434\u0445\u043e\u0434, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u0441\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u0435\u0434\u0435\u0442\u0441\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0432\u0435\u0442\u043a\u0438 trunk (\u0441\u0442\u0432\u043e\u043b). \u0427\u0442\u043e\u0431\u044b \u0432\u043e\u043f\u043b\u043e\u0442\u0438\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0432 \u0436\u0438\u0437\u043d\u044c, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0442\u0440\u0435\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c:<\/p>\n<p>1) \u041b\u044e\u0431\u044b\u0435 \u043a\u043e\u043c\u043c\u0438\u0442\u044b \u0432 trunk \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u043b\u043e\u043c\u0430\u0442\u044c \u0441\u0431\u043e\u0440\u043a\u0443.<\/p>\n<p>2) \u041b\u044e\u0431\u044b\u0435 \u043a\u043e\u043c\u043c\u0438\u0442\u044b \u0432 trunk \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u043c\u0438, \u043d\u0430 \u0441\u0442\u043e\u043b\u044c\u043a\u043e, \u0447\u0442\u043e review \u043d\u043e\u0432\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 10 \u043c\u0438\u043d\u0443\u0442.<\/p>\n<p>3) \u0420\u0435\u043b\u0438\u0437 \u0432\u044b\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 trunk.<\/p>\n<p>\u0414\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043b\u0438\u0441\u044c? \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435. <\/p>\n<h3>\u041d\u0430\u0447\u0430\u043b\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438<\/h3>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<h4>Initial commit<\/h4>\n<p>\u042f \u043d\u0435 \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u043b \u043d\u0438 \u0447\u0435\u0433\u043e \u043b\u0443\u0447\u0448\u0435 \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f &#171;\u043e\u043f\u043e\u0432\u0435\u0449\u0430\u0442\u0435\u043b\u044c&#187;, REST \u0441\u0435\u0440\u0432\u0438\u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0435 \u0432 \u0432\u0438\u0434\u0435 json, \u0430 \u043e\u043d \u0443\u0436\u0435 \u043e\u043f\u043e\u0432\u0435\u0449\u0430\u0435\u0442 \u043a\u043e\u0433\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 <a href=\"https:\/\/start.spring.io\/\" rel=\"noopener noreferrer nofollow\">spring initializr<\/a>.  \u042f \u0441\u0434\u0435\u043b\u0430\u043b Maven Project, \u044f\u0437\u044b\u043a Java \u0432\u0435\u0440\u0441\u0438\u044f 8, Spring Boot 2.4.0. \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435:<\/p>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438<\/summary>\n<div class=\"spoiler__content\">\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p>\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435<\/p>\n<\/th>\n<th>\n<p>\u0422\u0438\u043f<\/p>\n<\/th>\n<th>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p>Spring Configuration Processor<\/p>\n<\/td>\n<td>\n<p>DEVELOPER TOOLS<\/p>\n<\/td>\n<td>\n<p>Generate metadata for developers to offer contextual help and &#171;code completion&#187; when working with custom configuration keys (ex.application.properties\/.yml files).<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p>Validation<\/p>\n<\/td>\n<td>\n<p>I\/O<\/p>\n<\/td>\n<td>\n<p>JSR-303 validation with Hibernate validator.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p>Spring Web<\/p>\n<\/td>\n<td>\n<p>WEB<\/p>\n<\/td>\n<td>\n<p>Build web, including RESTful, applications using Spring MVC. Uses Apache Tomcat as the default embedded container.<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p>Lombok<\/p>\n<\/td>\n<td>\n<p>DEVELOPER TOOLS<\/p>\n<\/td>\n<td>\n<p>Java annotation library which helps to reduce boilerplate code.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<\/details>\n<p>\u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c git \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0438 \u043f\u0443\u0448\u0438\u043c \u043d\u0430 <a href=\"https:\/\/github.com\/\" rel=\"noopener noreferrer nofollow\">GitHub<\/a> \u0438\u043b\u0438 \u043a\u0443\u0434\u0430 \u0432\u0430\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f. \u041e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u0432\u0435\u0442\u043a\u0443 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0437\u0432\u0430\u0442\u044c \u043f\u043e \u0441\u0432\u043e\u0435\u043c\u0443 \u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0438\u044e: main, master \u0438\u043b\u0438 \u0434\u0430\u0436\u0435 \u0442\u0430\u043a \u0438 \u043d\u0430\u0437\u0432\u0430\u0442\u044c &#8212; trunk, \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0435\u043c \u0441\u0440\u0430\u0437\u0443 \u0431\u044b\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u0447\u0435\u043c \u0432\u044b \u0442\u0443\u0442 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0435\u0441\u044c.  \u0412\u0441\u0435. \u041f\u043e\u0441\u0430\u0434\u0438\u043b\u0438 \u0434\u0435\u0440\u0435\u0432\u0446\u0435. \u0422\u0435\u043f\u0435\u0440\u044c \u0431\u0443\u0434\u0435\u043c \u0431\u0435\u0440\u0435\u0436\u0435\u043d\u043e \u0435\u0433\u043e \u0432\u044b\u0440\u0430\u0449\u0438\u0432\u0430\u0442\u044c. <\/p>\n<h4>\u041f\u0435\u0440\u0432\u0430\u044f \u0444\u0438\u0447\u0430<\/h4>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0435\u0440\u0432\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u0447\u0442\u0443.  \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0438\u0448\u0435\u043c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432 \u0432\u0438\u0434\u0435 <a href=\"https:\/\/www.baeldung.com\/configuration-properties-in-spring-boot\" rel=\"noopener noreferrer nofollow\">ConfigurationProperties<\/a>.  \u0423 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u043a\u0430 \u0431\u0443\u0434\u0443\u0442  \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u0432\u0430 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430:  sender-email &#8212; \u043f\u043e\u0447\u0442\u043e\u0432\u044b\u0439 \u0430\u0434\u0440\u0435\u0441 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044f \u0438 email-subject &#8212; \u0442\u0435\u043c\u0430 \u043f\u0438\u0441\u044c\u043c\u0430 \u0432 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>NotificationProperties<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\"> @Getter  @Setter  @Component  @Validated \/\/\u0433\u043e\u0432\u043e\u0440\u0438\u043c, \u0447\u0442\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c\u0441\u044f  @ConfigurationProperties(prefix = \"notification\")  public class NotificationProperties {       @Email \/\/\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0447\u0442\u043e \u044d\u0442\u043e \u043f\u043e\u0447\u0442\u0430      @NotBlank \/\/\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0447\u0442\u043e \u043f\u043e\u043b\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043e      private String senderEmail;       @NotBlank      private String emailSubject;  } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f \u043d\u0430 \u043f\u043e\u0447\u0442\u0443, \u0434\u0435\u043b\u0430\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u0433\u043b\u0443\u0448\u0443, \u0442\u0430\u043a  \u043a\u0430\u043a \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u044d\u0442\u043e\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0441\u044f \u0431\u044b \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439. <\/p>\n<blockquote>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043d\u0430\u043c \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f.<\/p>\n<\/blockquote>\n<details class=\"spoiler\">\n<summary>EmailSender<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Slf4j @Component public class EmailSender {     \/**      * \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u0447\u0442\u0443 \u043f\u043e\u043d\u0430\u0440\u043e\u0448\u043a\u0443      *\/     public void sendEmail(String from, String to, String subject, String text){         log.info(\"Send email\\nfrom: {}\\nto: {}\\nwith subject: {}\\nwith\\n text: {}\", from, to, subject, text);     } } <\/code><\/pre>\n<p> <\/p>\n<\/div>\n<\/details>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c\u043a\u0443 \u0434\u043b\u044f \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f: <\/p>\n<details class=\"spoiler\">\n<summary>Notification<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Getter @Setter @Builder @AllArgsConstructor public class Notification {     private String text;     private String recipient; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f: <\/p>\n<details class=\"spoiler\">\n<summary>NotificationService<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Service @RequiredArgsConstructor public class NotificationService {      private final EmailSender emailSender;      private final NotificationProperties notificationProperties;      public void notify(Notification notification){         String from = notificationProperties.getNotificationSenderEmail();         String to = notification.getRecipient();         String subject = notificationProperties.getNotificationEmailSubject();         String text = notification.getText();         emailSender.sendEmail(from, to, subject, text);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440: <\/p>\n<details class=\"spoiler\">\n<summary>NotificationController<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@RestController @RequiredArgsConstructor public class NotificationController {      private final NotificationService notificationService;      @PostMapping(\"\/notification\/notify\")     public void notify(Notification notification){         notificationService.sendNotification(notification);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0415\u0449\u0451 \u043d\u0430\u043c \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0442\u0435\u0441\u0442\u044b, \u0431\u0435\u0437 \u043d\u0438\u0445 TBD \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f. \u041d\u0430\u043f\u0438\u0448\u0435\u043c \u0442\u0435\u0441\u0442 \u0434\u043b\u044f NotificationService: <\/p>\n<details class=\"spoiler\">\n<summary>NotificationServiceTest<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@SpringBootTest class NotificationServiceTest {      @Autowired     NotificationService notificationService;      @Autowired     NotificationProperties properties;      @MockBean     EmailSender emailSender;      @Test     void emailNotification() {         Notification notification = Notification.builder()                 .recipient(\"test@email.com\")                 .text(\"some text\")                 .build();          notificationService.notify(notification);          ArgumentCaptor&lt;string&gt; emailCapture = ArgumentCaptor.forClass(String.class);         verify(emailSender, times(1))                 .sendEmail(emailCapture.capture(),emailCapture.capture(),emailCapture.capture(),emailCapture.capture());         assertThat(emailCapture.getAllValues())                 .containsExactly(properties.getSenderEmail(),                                 notification.getRecipient(),                                 properties.getEmailSubject(),                                 notification.getText()                 );     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u0434\u043b\u044f NotificationController  <\/p>\n<details class=\"spoiler\">\n<summary>NotificationControllerTest<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@WebMvcTest(controllers = NotificationController.class) class NotificationControllerTest {      @Autowired     MockMvc mockMvc;      @Autowired     ObjectMapper objectMapper;      @MockBean     NotificationService notificationService;      @SneakyThrows     @Test     void testNotify() {         ArgumentCaptor&lt;notification&gt; notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class);         Notification notification = Notification.builder()                 .recipient(\"test@email.com\")                 .text(\"some text\")                 .build();          mockMvc.perform(post(\"\/notification\/notify\")                 .contentType(MediaType.APPLICATION_JSON)                 .content(objectMapper.writeValueAsString(notification)))                 .andExpect(status().isOk());          verify(notificationService, times(1)).notify(notificationArgumentCaptor.capture());         assertThat(notificationArgumentCaptor.getValue())                 .usingRecursiveComparison()                 .isEqualTo(notification);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u043b\u0438, \u0441\u0434\u0435\u043b\u0430\u043b\u0438 rebase, \u043f\u0440\u043e\u0433\u043d\u0430\u043b\u0438 \u0441\u0431\u043e\u0440\u043a\u0443 \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0438 \u0437\u0430\u043f\u0443\u0448\u0438\u043b\u0438 \u0432 trunk &#8212; \u044d\u0442\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c  \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u043e\u0439\u0442\u0438 \u0432 \u043f\u0440\u0438\u0432\u044b\u0447\u043a\u0443 \u0438 \u0434\u0435\u043b\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0447\u0430\u0449\u0435.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u044f \u043e\u0447\u0435\u043d\u044c \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0435\u0440\u0432\u044b\u0439 \u043a\u043e\u043c\u043c\u0438\u0442 \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a\u0438\u043c,  \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0431\u044b\u043b \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u043c\u0435\u043d\u044c\u0448\u0435 \u0438 \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u043b \u043d\u0430\u0448\u0435\u043c\u0443 \u0432\u0442\u043e\u0440\u043e\u043c\u0443 \u043f\u0440\u0430\u0432\u0438\u043b\u0443 &#8212; code review \u043c\u0435\u043d\u044c\u0448\u0435 \u0447\u0435\u043c \u0437\u0430 10 \u043c\u0438\u043d\u0443\u0442. <\/p>\n<h3>\u041f\u0440\u043e\u0444\u0438\u043b\u0438<\/h3>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0438 \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435 \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u0435\u043c\u0430 &#8212; \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <a href=\"https:\/\/www.baeldung.com\/spring-profiles\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u043e\u0444\u0438\u043b\u0435\u0439<\/a>. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432\u0441\u0435 \u0432\u0430\u0448\u0435 \u0432\u043e\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c, \u0447\u0442\u043e \u043d\u0430\u043c \u0432\u0434\u0440\u0443\u0433 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u043b\u043e\u0441\u044c \u043e\u043f\u043e\u0432\u0435\u0449\u0430\u0442\u044c \u043a\u043e\u0433\u043e-\u0442\u043e \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e.  \u041d\u0443 \u0447\u0442\u043e \u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u043f\u043e\u0434 \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443. <\/p>\n<details class=\"spoiler\">\n<summary>NotificationTask<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Component @EnableScheduling @RequiredArgsConstructor public class NotificationTask {      private final NotificationService notificationService;      private final NotificationProperties notificationProperties;      @Scheduled(fixedDelay = 1000)     public void notifySubscriber(){         notificationService.notify(Notification.builder()                 .recipient(notificationProperties.getSubscriberEmail())                 .text(\"Notification is worked\")                 .build());     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u043e\u0433\u043e\u043d\u0438\u043c \u043d\u0430\u0448\u0438 \u0442\u0435\u0441\u0442\u044b \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430: <\/p>\n<p><strong>&#171;org.mockito.exceptions.verification.TooManyActualInvocations&#187;<\/strong>. <\/p>\n<p>\u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u0432\u0435\u0434\u044c \u0432 \u043d\u0430\u0448\u0435\u043c \u0442\u0435\u0441\u0442\u0435 \u043e\u0436\u0438\u0434\u0430\u043b\u0441\u044f \u043e\u0434\u0438\u043d \u0432\u044b\u0437\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u0430 sendEmail, \u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0431\u043e\u043b\u044c\u0448\u0435,  \u0442\u0430\u043a \u043a\u0430\u043a \u0442\u0435\u043f\u0435\u0440\u044c \u044d\u0442\u043e\u0442 \u0436\u0435 \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0437\u0430\u0434\u0430\u0447\u0435. <\/p>\n<p>\u041d\u0435 \u043f\u043e\u0440\u044f\u0434\u043e\u043a. \u041c\u043e\u0436\u043d\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0432\u044b\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0435 <strong>initialDelay<\/strong>, \u0447\u0442\u043e \u0431\u044b \u0442\u0435\u0441\u0442 \u0443\u0441\u043f\u0435\u043b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f \u0440\u0430\u043d\u044c\u0448\u0435 \u0447\u0435\u043c \u0437\u0430\u0434\u0430\u0447\u0430, \u043d\u043e \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043a\u043e\u0441\u0442\u044b\u043b\u044c. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u043a\u0430\u043a \u0432\u044b \u0443\u0436\u0435 \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435 \u0434\u043e\u0433\u0430\u0434\u0430\u043b\u0438\u0441\u044c \u043c\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c \u043f\u0440\u043e\u0444\u0438\u043b\u044c.  \u0412\u044b\u043d\u0435\u0441\u0435\u043c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e <strong>@EnableScheduling<\/strong> \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e <strong>@Profile<\/strong> \u0433\u0434\u0435 \u0441\u043a\u0430\u0436\u0435\u043c, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438 \u0432\u0441\u0435\u0433\u0434\u0430, \u043a\u0440\u043e\u043c\u0435 \u043a\u0430\u043a \u0432 \u043f\u0440\u043e\u0444\u0438\u043b\u0435 &#171;test&#187;. <\/p>\n<details class=\"spoiler\">\n<summary>SchedulingConfig<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"java\">@Profile(\"!test\") @Configuration @EnableScheduling public class SchedulingConfig {} <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u0445, \u0432 <strong>application.yam<\/strong>l \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0444\u0438\u043b\u044f: <\/p>\n<details class=\"spoiler\">\n<summary>application.yaml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>spring:   profiles:     active: test notification:   email-subject: Auto notification   sender-email: robot@somecompany.com <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c, \u0432 \u0442\u0435\u0441\u0442\u0430\u0445, \u0437\u0430\u0434\u0430\u0447\u0438 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f,  \u043d\u043e \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u0437 main \u043c\u0435\u0442\u043e\u0434\u0430, \u0442\u043e \u0437\u0430\u0434\u0430\u0447\u0438 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u0440\u0430\u0432\u043d\u043e \u0442\u0438\u043a\u0430\u0442\u044c. <\/p>\n<p>\u0412 \u0441\u0432\u043e\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u0435 \u044f \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u043f\u0440\u043e\u0444\u0438\u043b\u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043d\u043e \u043d\u0438 \u043a\u0442\u043e \u0432\u0430\u043c \u043d\u0435 \u0437\u0430\u043f\u0440\u0435\u0442\u0438\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0434\u043b\u044f \u0441\u0432\u043e\u0438\u0445 \u0446\u0435\u043b\u0435\u0439, \u0433\u043b\u0430\u0432\u043d\u043e\u0435, \u043a\u0430\u043a \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0441 \u043d\u0438\u043c\u0438 \u043d\u0435 \u043c\u0435\u043b\u044c\u0447\u0438\u0442\u044c \u0438 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0438\u0445 \u043c\u043d\u043e\u0433\u043e. <\/p>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043f\u0440\u043e\u0444\u0438\u043b\u0438 \u0442\u043e\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0438\u043b\u0438 \u0432\u044b\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0446\u0435\u043b\u044b\u0439 \u0441\u043b\u043e\u0439 \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u043b\u043e\u0433\u0438\u043a\u0438,  \u043f\u0440\u0438\u0447\u0435\u043c \u043d\u0430 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0439 \u043e\u0441\u043d\u043e\u0432\u0435, \u0442.\u0435. \u0432\u044b \u043d\u0435 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0435 \u0432\u044b\u043a\u0438\u043d\u0443\u0442\u044c \u044d\u0442\u0443 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u0433\u0434\u0430-\u043d\u0438\u0431\u0443\u0434\u044c \u043f\u043e\u0442\u043e\u043c. \u041f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438 \u043c\u043e\u0433\u0443\u0442 \u0441\u043b\u0443\u0436\u0438\u0442\u044c: \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c, \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0438\u043b\u0438 \u043a\u0430\u043a \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043f\u043e \u0440\u0430\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u044e.<\/p>\n<p>\u0414\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0442\u043e\u0447\u0435\u0447\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043b\u0443\u0447\u0448\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c  <a href=\"https:\/\/trunkbaseddevelopment.com\/feature-flags\/\" rel=\"noopener noreferrer nofollow\">Feature flags<\/a>,  \u043d\u043e \u044d\u0442\u043e\u0442 \u0441\u043f\u043e\u0441\u043e\u0431 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438 \u0443\u0436\u0435 \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0440\u0435\u043b\u0438\u0437\u0430. \u0421\u0434\u0435\u043b\u0430\u043b\u0438 rebase, \u043f\u0440\u043e\u0433\u043d\u0430\u043b\u0438 \u0441\u0431\u043e\u0440\u043a\u0443 \u0441 \u0442\u0435\u0441\u0442\u0430\u043c\u0438 \u0438 \u0437\u0430\u043f\u0443\u0448\u0438\u043b\u0438 \u0432 trunk.<\/p>\n<h3>\u041f\u0435\u0440\u0432\u044b\u0439 \u0440\u0435\u043b\u0438\u0437<\/h3>\n<figure class=\"\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e\u0442\u0432\u043b\u0435\u0447\u0435\u043c\u0441\u044f \u043e\u0442 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u0440\u0435\u043b\u0438\u0437\u0430\u043c\u0438. \u0412 TBD \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u0434\u0432\u0430 \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0432\u044b\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0440\u0435\u043b\u0438\u0437\u044b: \u043f\u0435\u0440\u0432\u044b\u0439 \u0438\u0437 <a href=\"https:\/\/trunkbaseddevelopment.com\/branch-for-release\/\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043b\u0438\u0437\u043d\u043e\u0439 \u0432\u0435\u0442\u043a\u0438<\/a>, \u0432\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u044f\u043c\u043e \u0438\u0437 <a href=\"https:\/\/trunkbaseddevelopment.com\/release-from-trunk\/\" rel=\"noopener noreferrer nofollow\">trunk<\/a>.<\/p>\n<\/p>\n<\/details>\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-315502","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/315502","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=315502"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/315502\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=315502"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=315502"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=315502"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}