Tdd что это означает для чайников

TDD: Что пошло не так?

Эта статья является переводом материала «TDD: What went wrong or did it?».

В сфере разработки программного обеспечения уже давно хвалят Test Driven Development (TDD, разработка через тестирование). Однако в последнее время было сказано много резких слов в адрес TDD, поскольку его обвиняют в плохом проектировании программного обеспечения и невыполнении многих своих обещаний. Кульминацией этой тенденции стал пост Дэвида Хайнемайера Ханссона «TDD is dead. Long live testing.» (TDD мертв. Да здравствует тестирование).

Как это возможно, что одна и та же техника, которая так выгодна для стольких разработчиков, так губительна для других? В этой статье Владислав Кононов расскажет о трех заблуждениях, которые могли бы объяснить это явление.

Начнем с самого тонкого и самого деструктивного.

TDD это не «Проектирование через тестирование»

TDD расшифровывается как “Разработка через тестирование”. К сожалению, многие неверно истолковывают это как “Проектирование, основанное на тестировании”. Эта неточность может показаться невинной, но поверьте мне, это не так. Позвольте мне объяснить.

Если вы разрабатываете в первую очередь для тестируемости, вы получаете то, за что платите, — тестируемый код. Чаще всего этот дизайн будет полностью не связан с бизнес-областью и требованиями проекта. Он будет напоминать огромный граф объектов, полный случайных сложностей. но он будет проверяемым. Тестируемый тестами, которые тонут в моках (имеется в виду mock как тестовый двойник), и полностью сломается после изменения одного кусочка в реализации. Это то, что называется “повреждением, вызванным тестом”, и это ярко показано в блоге Дэвида Хайнемайера Ханссона «TDD is dead. Long live testing.»:

Нынешний фанатичный опыт TDD приводит к тому, что основное внимание уделяется модульным тестам, потому что это тесты, способные управлять дизайном кода (первоначальное обоснование для test-first – сначала тестирование, потом реализация). Я не думаю, что это здорово. Test-first приводят к чрезмерно сложной сети промежуточных объектов и косвенных обращений, чтобы избежать «медленных» действий. Например, попасть в базу данных. Или файл IO. Или пройти через браузер, чтобы протестировать всю систему. Это породило некоторые поистине ужасные архитектурные уродства. Густые джунгли служебных объектов, командных шаблонов и прочего.

TDD это не (только) о модульных тестах

Основное внимание уделяется автоматическим тестам, и их можно разделить на три типа: модульные тесты, интеграционные тесты и сквозные тесты. Я не верю, что каждый проект нуждается в каждом из них. Опять же, это решение должно определяться вашей проблемной областью:

Вы имеете дело со сложной бизнес-логикой? Вам действительно нужны модульные тесты здесь.

Вы выполняете только простые операции CRUD? Используйте интеграционные тесты или сквозные тесты.

Сценарий ETL? Достаточно сквозных тестов.

. И, говоря о модульных тестах, что вообще такое модуль? Переходим к третьему заблуждению.

Еще одно распространенное заблуждение заключается в том, что модульные тесты должны проверять отдельные классы, и все зависимости класса должны быть имитированы. Такой подход является неточным. Это рецепт для сильной связи между тестами и реализацией. Эта связь подорвет все ваши усилия по рефакторингу, нарушив тем самым одно из фундаментальных обещаний TDD.

Определение модуля, которое мне нравится больше всего, принадлежит Рою Ошерову, автору книги The Art of Unit Testing:

Функциональные варианты тестирования отделяют тесты от реализации. Это сделает рефакторинг возможным и потребует значительно меньше тестовых двойников.

Отсутствие буквы D в TDD

В конечном счете, есть еще одно наблюдение, которым я хочу поделиться, потому что оно суммирует все вышеупомянутые заблуждения.

Общепризнанно, что хорошо спроектированный код также поддается тестированию. Однако это соотношение не является коммутативным: хорошо спроектированный код можно тестировать, но не весь тестируемый код хорошо спроектирован. Доказательство тривиально:

P.S TDD 2.0

TDD был «заново открыт» Кентом Беком более десяти лет назад. Возможно, пора снова открыть TDD. Помимо модульных тестов, новая спецификация должна касаться других типов автоматизированных тестов, которые в то время были недоступны. И, конечно же, вместо того, чтобы работать против, TDD должен тесно сотрудничать с бизнес-областью.

Источник

Что надо знать о TDD и BDD: как тесты помогают разработчикам работать в команде и понять заказчика

Tdd что это означает для чайников. 6130a0afc6f80 bpfull. Tdd что это означает для чайников фото. Tdd что это означает для чайников-6130a0afc6f80 bpfull. картинка Tdd что это означает для чайников. картинка 6130a0afc6f80 bpfull

Java Developer в NIX

Tdd что это означает для чайников. soc facebook red. Tdd что это означает для чайников фото. Tdd что это означает для чайников-soc facebook red. картинка Tdd что это означает для чайников. картинка soc facebook red Tdd что это означает для чайников. soc twitter red. Tdd что это означает для чайников фото. Tdd что это означает для чайников-soc twitter red. картинка Tdd что это означает для чайников. картинка soc twitter red Tdd что это означает для чайников. soc telegram red. Tdd что это означает для чайников фото. Tdd что это означает для чайников-soc telegram red. картинка Tdd что это означает для чайников. картинка soc telegram red

Вам знакома басня про лебедя, рака и щуку? Три совершенно разных существа тянули воз: лебедь пытался взлетать с ним, рак пятился с повозкой назад, а щука упорно тащила телегу на дно. Единства между ними не произошло, поэтому затея была обречена на провал — воз так и не сдвинулся с места.

Так аллегорично можно описать стандартный рабочий процесс, в котором заказчик хочет одно, руководитель проекта понимает задачу по-другому, а специалисты (дизайнеры, программисты, тестировщики) все делают по-своему… Иногда такие проекты доводят до конца. Однако зачастую они, как повозка из упомянутой басни, остаются на месте.

Чтобы в своей профессии вы не повторяли судьбу героев басни, были созданы методологии тестирования Test Driven Development (TDD) и Behavior Driven Development (BDD). Давайте разберемся, как они работают.

TDD и BDD: основные отличия модульного и интеграционного тестирования

Test Driven Development (TDD) — это разработка, основанная на тестировании. Предположим, вы получаете от заказчика запрос на добавление в разрабатываемый продукт нового функционала. Под этот запрос составляется техническая документация в виде тестов: в них согласованы и записаны новые требования, которые заказчик предъявляет к продукту.

Тестирование в TDD происходит через итерации (циклы) и соответствует такому порядку:

Все эти шаги TDD-разработки будут повторяться энное количество раз, пока специалисты не приведут код в соответствие с документацией и не удостоверятся в работоспособности новой функции.

Tdd что это означает для чайников. image3 1. Tdd что это означает для чайников фото. Tdd что это означает для чайников-image3 1. картинка Tdd что это означает для чайников. картинка image3 1

Методология TDD относится к юнит-тестированию (модульному тестированию) и позволяет проверять отдельно взятые части продукта. Чаще всего TDD пишут сами разработчики, тесты реализуются в виде программного кода.

Но как протестировать не отдельный модуль продукта, а сложный сценарий с большим количеством условий и переменных?

В этом случае прибегают к использованию методологии Behavior Driven Development — разработке на основе поведения. В отличие от TDD, этот подход строится на написании нескольких пользовательских сценариев, под которые составляются тесты. BDD позволяет «‎предугадать», как поведет себя пользователь, используя продукт в соответствии с требованиями, которые записаны в технической документации. Порядок прохождения тестов схож с TDD. Единственное отличие — перед прохождением отдельных тестов формулируется ряд предварительных условий (сценариев), при которых они должны быть пройдены.

Tdd что это означает для чайников. image2 1. Tdd что это означает для чайников фото. Tdd что это означает для чайников-image2 1. картинка Tdd что это означает для чайников. картинка image2 1

Сравненение BDD и TDD / TestLodge

Требования для BDD обычно составляет группа экспертов и не в виде программного кода, а словесно — на языке, понятном всем участникам проекта.

Behavior Driven Development относится к методам интеграционного тестирования. Оно позволяет понять, правильно ли взаимодействуют друг с другом отдельно взятые части программы.

Подход также эффективен в end-to-end-тестировании (Е2Е) и дает программистам представление о том, как функционирует вся разрабатываемая ими система. Получается, несмотря на то, что BDD и является расширением TDD-методологии, они имеют разное предназначение и реализуются разным набором инструментов.

В общем, мы друг друга поняли

Методологии BDD- и TDD- тестирования помогают достичь взаимопонимания между заказчиком продукта и всеми участниками, задействованными в его реализации.

Ч еткое следование прописанным заранее спецификациям позволяет избежать подводных камней в виде неоговоренных сценариев или разрозненной трактовки функционала продукта разными специалистами.

Весомое преимущество таких подходов в тестировании — отсутствие невалидных (недостоверных) сценариев. Каждый участник проекта еще на стадии проектирования может увидеть нереализуемые функции и рассказать об этом коллегам. Так можно исключить даже саму возможность создания неэффективного и бесполезного кода.

Еще один плюс — наличие технической документации. TDD и BDD предполагают четко структурированную документацию, которая помогает быстрее адаптироваться новичкам, зашедшим в проект, уже на этапе производства.

Разработка больше не зависит от человеческого фактора: чтобы понять, что происходило в проекте с момента его создания, достаточно открыть нужный файл.

Как составлять тесты?

Давайте подытожим кратким списком рекомендаций по составлению тестов:

Инструменты для реализации юнит-тестирования

Юнит-тестирование на Java осуществляется при помощи фреймворка JUnit. Он относится к семейству фреймворков xUnit и используется преимущественно для Test-Driven- и Behavior-Driven-разработки. На сегодня JUnit 5 — самая свежая версия фреймворка, которая совместима с версиями Java 8 и выше.

Это значит, что фреймворк поддерживает Stream API, лямбды, функциональные интерфейсы и массу других «плюшек», которые таит в себе Java 8+.

Характерным отличием JUnit 5 от своей предыдущей версии является возможность запускать сразу несколько раннеров для одного и того же класса (JUnit4 был способен выполнять только один класс-раннер). JUnit 5 состоит из трех отдельных пакетов, которые можно подключать независимо друг от друга:

Tdd что это означает для чайников. image1 1. Tdd что это означает для чайников фото. Tdd что это означает для чайников-image1 1. картинка Tdd что это означает для чайников. картинка image1 1

JUnit 5 состоит из трех отдельных пакетов, которые можно подключать независимо друг от друга

Экстеншн-модели и аннотации в JUnit 5

Экстеншн-модель в JUnit Jupiter — это разновидность совершенно нового API, позволяющая расширять функционал отдельного теста и добавлять новые условия для работы с ним. Для работы с экстеншн-моделью существуют экстеншн-поинты.

Существует пять основных видов экстеншн-поинтов:

В JUnit пятой версии также расширен функционал Assertions API. Например, теперь вы сможете работать с методом assertAll, который построен на использовании лямбд. Он позволяет производить групповые проверки: каждая следующая проверка выполняется только в том случае, если предыдущая верна:

JUnit 5 также позволяет контролировать выполнение теста в зависимости от внешних условий. Вы можете выбирать ОС, на которой будете проводить тестирование, а также версию Java, на которой будет работать тест. Контролировать можно и то, при каких системных настройках будет запущен тест.

Также JUnit 5 помогает создавать свои собственные аннотации. Для этого необходимо указать @Target (ElementType.METHOD) для нового интерфейса и затем перечислить все аннотации, которые должны сработать при подключении вашей аннотации. Вот несколько примеров таких аннотаций:

Тестируй себя сам

Для любого разработчика очень важно уметь самостоятельно применять методы юнит-тестирования. Такой подход позволяет на ранних этапах уловить непонятные аспекты ТЗ до того, как будет реализован код. Помимо этого, TDD- и BDD- тестирование обеспечивает постоянную коммуникацию внутри команды: и исполнитель, и заказчик, и руководитель всегда будут находиться в одной плоскости понимания проекта. Именно в таком единстве всех участников процесса и заключается главное преимущество использования интеграционного и модульного тестирования.

Этот материал – не редакционный, это – личное мнение его автора. Редакция может не разделять это мнение.

Источник

TDD: методология разработки, которая изменила мою жизнь

На часах 7:15 утра. Наша техподдержка завалена работой. О нас только что рассказали в передаче «Good Morning America» и множество тех, кто впервые посещает наш сайт, столкнулось с ошибками.

У нас настоящий аврал. Мы, прямо сейчас, до того, как потеряем возможность превратить посетителей ресурса в новых пользователей, собираемся выкатить пакет исправлений. Один из разработчиков кое-что подготовил. Он думает, что это поможет справиться с проблемой. Мы размещаем ссылку на обновлённую версию программы, пока ещё не ушедшей в продакшн, в чат компании, и просим всех её протестировать. Работает!

Наши героические инженеры запускают скрипты для развёртывания систем и через считанные минуты обновление уходит в бой. Внезапно число звонков в техподдержку удваивается. Наше срочное исправление что-то поломало, разработчики хватаются за git blame, а инженеры в это время откатывают систему к предыдущему состоянию.

Tdd что это означает для чайников. 715f8a020e1adfe61cb65c6b6bccb191. Tdd что это означает для чайников фото. Tdd что это означает для чайников-715f8a020e1adfe61cb65c6b6bccb191. картинка Tdd что это означает для чайников. картинка 715f8a020e1adfe61cb65c6b6bccb191

Автор материала, перевод которого мы сегодня публикуем, полагает, что всего этого можно было бы избежать благодаря TDD.

Почему я использую TDD?

Я давно уже не попадал в подобные ситуации. И дело не в том, что разработчики перестали совершать ошибки. Дело в том, что уже многие годы в каждой команде, которой я руководил и на которую я оказывал влияние, применялась методология TDD. Ошибки, конечно, всё ещё случаются, но проникновение в продакшн проблем, способных «повалить» проект, снизилось практически до нуля, даже несмотря на то, что частота обновления ПО и количество задач, которые нужно решить в процессе обновления, экспоненциально выросли с тех пор, когда случилось то, о чём я рассказал в начале.

Когда кто-то спрашивает меня о том, почему ему стоит связываться с TDD, я рассказываю ему эту историю, и могу вспомнить ещё с десяток похожих случаев. Одна из важнейших причин, по которым я перешёл на TDD, заключается в том, что эта методология позволяет улучшить покрытие кода тестами, что ведёт к тому, что в продакшн попадают на 40-80% меньше ошибок. Это то, что мне нравится в TDD больше всего. Это снимает с плеч разработчиков целую гору проблем.

Кроме того, стоит отметить, что TDD избавляет разработчиков от страха внесения изменений в код.

В проектах, в работе над которыми я принимаю участие, наборы автоматических модульных и функциональных тестов практически ежедневно предотвращают попадание в продакшн кода, который способен серьёзно нарушить работу этих проектов. Например, сейчас я смотрю на 10 автоматических обновлений библиотеки, сделанных на прошлой неделе, таких, перед выпуском которых без использования TDD, я опасался бы того, что они могут что-то испортить.

Все эти обновления были автоматически интегрированы в код, и они уже используются в продакшне. Я не проверял ни одного из них вручную, и совершенно не беспокоился о том, что они могут плохо отразиться на проекте. При этом, мне, для того чтобы привести этот пример, не пришлось долго думать. Я просто открыл GitHub, взглянул на недавние слияния, и увидел то, о чём рассказал. Та задача, которую раньше решали вручную (или, ещё хуже, задача, которую игнорировали), теперь представляет собой автоматизированный фоновый процесс. Можно попытаться сделать нечто подобное и без хорошего покрытия кода тестами, но я бы не рекомендовал так поступать.

Что такое TDD?

TDD расшифровывается как Test Driven Development (разработка через тестирование). Процесс, реализуемый в ходе применения этой методологии очень прост:

Tdd что это означает для чайников. image loader. Tdd что это означает для чайников фото. Tdd что это означает для чайников-image loader. картинка Tdd что это означает для чайников. картинка image loader

Тесты выявляют ошибки, тесты завершаются успешно, выполняется рефакторинг

Вот основные принципы применения TDD:

Как TDD может помочь сэкономить время, необходимое на разработку программ?

На первый взгляд может показаться, что написание тестов означает значительное увеличение объёма кода проекта, и то, что всё это отнимает у разработчиков много дополнительного времени. В моём случае, поначалу, всё так и было, и я пытался понять, как, в принципе, можно писать тестируемый код, и как добавлять тесты к коду, который был уже написан.

Для TDD характерна определённая кривая обучаемости, и пока новичок карабкается по этой кривой, время, необходимое на разработку, может увеличиться на 15-35%. Часто именно так всё и происходит. Но где-то года через 2 после начала использования TDD начинает происходить нечто невероятное. А именно, я, например, стал, с предварительным написанием модульных тестов, программировать быстрее, чем раньше, когда TDD не пользовался.

Несколько лет назад я реализовывал, в клиентской системе, возможность работы с фрагментами видеоклипа. А именно, речь шла о том, чтобы можно было бы позволить пользователю указывать начало и конец фрагмента записи, и получать ссылку на него, что дало бы возможность ссылаться на конкретное место в клипе, а не на весь этот клип.

Работа у меня не шла. Проигрыватель доходил до конца фрагмента и продолжал её воспроизводить, а я не имел представления о том, почему это так.

Я полагал, что проблема заключается в неправильном подключении прослушивателей событий. Мой код выглядел примерно так:

Процесс поиска проблемы выглядел так: внесение изменений, компиляция, перезагрузка, щелчок, ожидание… Эта последовательность действий повторялась снова и снова.

Для того чтобы проверить каждое из вносимых в проект изменений, нужно было потратить почти минуту, а я испытывал невероятно много вариантов решения задачи (большинство из них — по 2-3 раза).

Закон отладки Мёрфи. То место программы, которое вы никогда не тестировали, так как свято верили в то, что оно не может содержать ошибок, окажется именно тем местом, где вы найдёте ошибку после того, как, совершенно вымотавшись, внесёте в это место изменения лишь из-за того, что уже попробовали всё, о чём только могли подумать.

Я не забыл об этом и годы спустя. И всё — благодаря тому ощущению, которое испытал, всё же найдя ошибку. Вы, наверняка, знаете, о чём я говорю. Со всеми это случалось. И, пожалуй, каждый сможет узнать себя в этом меме.

Tdd что это означает для чайников. image loader. Tdd что это означает для чайников фото. Tdd что это означает для чайников-image loader. картинка Tdd что это означает для чайников. картинка image loader

Вот как я выгляжу, когда программирую

Если бы я писал ту программу сегодня, я бы начал работу над ней примерно так:

Возникает ощущение, что тут куда больше кода, чем в этой строчке:

Но в том-то всё и дело. Этот код действует как спецификация. Это — и документация, и доказательство того, что код работает так, как того требует эта документация. И, так как эта документация существует, если я изменю порядок работы с маркером времени окончания фрагмента, мне не придётся беспокоиться о том, нарушил ли я в ходе внесения этих изменений правильность работы со временем окончания клипа.

Вот, кстати, полезный материал по написанию модульных тестов, таких же, как тот, который мы только что рассмотрели.

Начиная новый проект я, в качестве одного из первых дел, выполняю настройку скрипта-наблюдателя, который автоматически запускает модульные тесты при каждом изменении некоего файла. Я часто программирую, используя два монитора. На одном из них открыта консоль разработчика, в которой выводятся результаты выполнения подобного скрипта, на другом выводится интерфейс среды, в которой я пишу код. Когда я вношу в код изменение, я обычно, в пределах 3 секунд, узнаю о том, рабочим оказалось это изменение или нет.

Для меня TDD — это гораздо больше, чем просто страховка. Это — возможность постоянного и быстрого, в режиме реального времени, получения сведений о состоянии моего кода. Мгновенное вознаграждение в виде пройденных тестов, или мгновенный отчёт об ошибках в том случае, если я сделал что-то не так.

Как методология TDD научила меня писать более качественный код?

Мне хотелось бы сделать одно признание, хоть признавать это и неловко: я не представлял себе, как создавать приложения до того, как я изучил TDD и модульное тестирование. Я не представляю, как меня вообще брали на работу, но, после того, как я провёл собеседования с многими сотнями разработчиков, я могу с уверенностью сказать, что в похожей ситуации находится множество программистов. Методология TDD научила меня почти всему, что я знаю об эффективной декомпозиции и композиции программных компонентов (я имею в виду модули, функции, объекты, компоненты пользовательского интерфейса и прочее подобное).

Причина этого заключается в том, что модульные тесты принуждают программиста к тестированию компонентов в изоляции друг от друга и от подсистем ввода-вывода. Если модулю предоставляются некие входные данные — он должен выдать некие, заранее известные, выходные данные. Если он этого не сделает, тест завершается с ошибкой. Если сделает — тест завершается успешно. Смысл тут заключается в том, что модуль должен работать независимо от остального приложения. Если вы тестируете логику работы состояния, у вас должна быть возможность делать это без вывода чего-либо на экран или сохранения чего-нибудь в базу данных. Если вы тестируете формирование пользовательского интерфейса, то у вас должна быть возможность тестировать его без необходимости загрузки страницы в браузер или обращения к сетевым ресурсам.

Кроме прочего, методология TDD научила меня тому, что жизнь становится гораздо проще в том случае, если при разработке компонентов пользовательского интерфейса стремиться к минимализму. Кроме того, от пользовательского интерфейса следует изолировать бизнес-логику и побочные эффекты. С практической точки зрения это означает, что если вы используете UI-фреймворк, основанный на компонентах, вроде React или Angular, целесообразным может быть создание презентационных компонентов, отвечающих за вывод чего-либо на экран, и компонентов-контейнеров, которые друг с другом не смешиваются.

Презентационный компонент, получающий некие свойства, всегда формирует один и тот же результат. Подобные компоненты можно легко проверить, используя модульные тесты. Это позволяет узнать, правильно ли компонент работает со свойствами, и то, корректна ли некая условная логика, используемая при формировании интерфейса. Например, возможно, компонент, формирующий список, не должен выводить ничего кроме приглашения на добавление в список нового элемента в том случае, если список пуст.

Я знал о принципе разделения ответственности задолго до того, как освоил TDD, но я не знал о том, как разделять ответственность между разными сущностями.

Модульное тестирование позволило мне изучить использование моков для тестирования чего-либо, а затем я узнал, что мокинг — это признак того, что, возможно, с кодом что-то не так. Это меня ошеломило и полностью изменило мой подход к композиции программного обеспечения.

Вся разработка программного обеспечения — это композиция: процесс разбиения больших проблем на множество мелких, легко решаемых проблем, а затем создание решений для этих проблем, которые и формируют приложение. Мокинг, выполняемый ради модульных тестов, указывает на то, что атомарные единицы композиции, на самом деле, не атомарны. Изучение того, как избавиться от моков, не ухудшая покрытие кода тестами, позволило мне узнать о том, как выявлять бесчисленное множество скрытых причин сильной связанности сущностей.

Это позволило мне, как разработчику, профессионально вырасти. Это научило меня тому, как писать гораздо более простой код, который легче расширять, поддерживать, масштабировать. Это относится и к сложности самого кода, и к организации его работы в больших распределённых системах наподобие облачных инфраструктур.

Как TDD помогает экономить рабочее время команд?

Я уже говорил о том, что TDD, в первую очередь, ведёт к улучшению покрытия кода тестами. Причина этого заключается в том, что мы не начинаем писать код реализации некоей возможности до тех пор, пока не напишем тест, проверяющий правильность работы этого будущего кода. Сначала пишем тест. Потом позволяем ему завершиться с ошибкой. Потом пишем код реализации возможности. Тестируем код, получаем сообщение об ошибке, добиваемся правильного прохождения испытаний, выполняем рефакторинг и повторяем этот процесс.

Этот процесс позволяет создать «заграждение», через которое способны «перескочить» лишь очень немногие ошибки. Эта защита от ошибок оказывает удивительное воздействие на весь коллектив разработчиков. Оно избавляет от страха перед командой merge.

Высокий уровень покрытия кода тестами позволяет команде избавиться от желания вручную проконтролировать любое, даже маленькое изменение кодовой базы. Изменения кода становятся естественной частью рабочего процесса.

Избавления от страха внесения изменений в код напоминает смазывание некоей машины. Если этого не делать, машина, в конце концов, остановится — до тех пор, пока её не смажут и снова не запустят.

Без этого страха процесс работы над программами оказывается гораздо более спокойным, чем прежде. Pull-запросы не откладывают до последнего. CI/CD-система запустит тесты, и, если тесты окажутся неудачными, остановит процесс внесения изменений в код проекта. При этом сообщения об ошибках и сведения о том, где именно они произошли, очень сложно будет не заметить.

В этом-то всё и дело.

Уважаемые читатели! Пользуетесь ли вы методикой TDD при работе над своими проектами?

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *