Хорошими тестировщиками не рождаются — ими становятся благодаря упорному труду и постоянному общению. На этом пути таится множество ловушек, способных сорвать самые смелые планы и привести к отставанию проектов от графика.
Кем Кейнер, Джеймс Бах и Брет Петтикорд очень хорошо об этом знают. За их плечами более 50 лет опыта, и они понимают, что необходимо для достижения успеха в тестировании. Они собрали 293 проверенных совета, которые вы можете использовать в своих проектах. Каждый урок начинается с утверждения, относящегося к тестированию программного обеспечения, за которым следует объяснение или пример, показывающий, как, когда и почему применяется этот урок.
В этой книге, говоря «вы», мы обращаемся к нашему основному читателю — к людям, которые работают в компании уже несколько лет и, возможно, недавно были переведены на руководящую должность. Надеемся, в уроках вы отметите много общего со своим опытом, получите новые знания, найдете такие уроки, которые сочтете полезным процитировать вашему руководителю. Мы также надеемся, что вам очень понравятся некоторые из наших утверждений и вы распечатаете их и повесите на стену в своем кабинете и, возможно, отреагируете хотя бы на одно утверждение настолько сильно, что прикрепите его копию на середину своей доски для дартса. (Мы хотим заставить вас размышлять, а не только добиться согласия.)
У тестировщиков-новичков (и у тех из вас, кто только устраивается на эту работу) ощущение, что вы уже сталкивались с тем, о чем мы пишем, будет возникать не слишком часто. Для вас эта книга может послужить неким первым толчком и предостережением, давая представление о том, с какими проблемами сталкиваются тестировщики.
Подсказка. Если вы новичок и ищете книгу, которая помогла бы научиться тестированию и подготовиться к собеседованию, то наша книга вам не подойдет. Если у вас нет других подобных книг, то обратите самое пристальное внимание на главы 3 «Техники тест-дизайна» и 10 «Ваша карьера в области тестирования программного обеспечения». А лучше всего прочесть первые пять глав книги Testing Computer Software.
Программисты, руководители проектов и другие специалисты, которым приходится работать с тестировщиками, найдут в этой книге полезные идеи, позволяющие определить ожидания, которые возлагаются на команду тестирования. Мы надеемся, что это поможет вам оценить работу ее участников и обсудить с ними проблемы, если вы не согласны с их политикой или считаете, что они неразумно тратят свое время.
Мы приняли несколько критериев добавления того или иного урока в книгу.
- Урок должен быть полезным или давать понимание темы.
- Урок должен пройти 90-минутный тест на самостоятельность мышления. Иначе говоря, урок не стоит добавлять в книгу, если его смог придумать практически каждый, кто думал о тестировании в течение 90 минут, не отвлекаясь ни на что другое.
- Урок должен быть основан на нашем реальном опыте. Хотя бы один из нас (а лучше все трое) должен был успешно применять наши рекомендации. По крайней мере двое из нас должны были обжечься, пытаясь следовать практике, которую мы критикуем. (Примечание. Иногда мы приходим к разным выводам, основываясь на разном опыте. Иногда мы выбираем не одну, а две точки зрения. Даже если представлена только одна, нельзя считать, что все трое полностью с ней согласны, — в случае разногласий мы, скорее всего, отдадим предпочтение тому из нас троих, кто имеет наиболее богатый опыт в данной ситуации.)
- Уроки должны гармонировать с опытом наших коллег. Мы собирали подробные отчеты о нем на семинарах по тестированию ПО, проводимых в Лос-Альтосе, круглых столах для менеджеров по тестированию ПО, семинарах по эвристическим и исследовательским методам, семинарах по автоматизации тестирования, проводимых в Остине, семинарах по паттернам тестирования ПО, семинарах по автоматизированному тестированию на основе моделей, на десятках конференций по тестированию ПО и на менее формальных тренингах (например, в ежегодных лагерях консультантов в Крестед-Бьютте).
- Урок должен быть кратким и понятным, но при этом легким для усвоения.
- Урок может быть более длинным, но лишь настолько, чтобы можно было объяснить, как сделать что-то, или предоставить полезный инструмент. Длинные описания и подробная справочная информация приводятся в учебниках.
- Уроки должны быть самодостаточными. Вы должны иметь возможность начать чтение с любого урока.
- В совокупности уроки должны дать вам представление о том, как мы проводим тестирование, а также об образе мышления и логике тестировщиков.
Защита багов
Тестировщик, который не может составить хороший баг-репорт, похож на холодильник, в котором свет горит, только когда дверца закрыта. Ситуация может быть освещена очень хорошо — но не настолько, чтобы это имело значение. Вы информационная служба, но для того, чтобы быть эффективными, вам нужно делать нечто большее, чем просто заполнять шаблоны отчетов и предполагать, что они полностью понятны. Научитесь писать отчеты и представлять итоги тестов так, чтобы это приносило результат. Мы называем это защитой багов.
Урок 55. Вы — то, что вы пишете
Баг-репорты (bug reports, «отчеты о багах») — основной результат работы большинства тестировщиков. Благодаря этим документам читатели формируют представление о вас. Чем лучше отчеты, тем выше ваша репутация.
Программисты черпают из ваших отчетов важную информацию. Хороший отчет улучшает вашу репутацию. Плохой — порождает дополнительную (и, по мнению программистов, ненужную) работу. Если вы тратите много их времени, то они будут избегать вас и работы с вами.
Программисты не единственная ваша аудитория. Баг-репорты иногда читают руководители. Внутрикадровые проблемы быстро привлекают их внимание и раздражают их. Отчеты, которые выглядят обвиняющими, мелочными по тону, плохо объясняющими проблему, содержащими недостаточно исследований или наводящими на мысли о том, что вы раздуваете из мухи слона, создадут негативное впечатление у людей, от которых зависит ваше повышение по службе.
Все в выигрыше, если вы грамотно проводите тестирование и хорошо пишете ответы.
Урок 56. Защита багов способствует их исправлению
Каждый баг-репорт, который вы написали, — это документ, призывающий к исправлению бага.
Некоторые баги никогда не будут исправлены. Ваша ответственность не в том, чтобы убедиться, что все баги будут исправлены. Ваша задача — сообщать о багах таким образом, чтобы тот, кто будет читать отчет, мог понять все последствия проблемы.
Чем лучше вы проведете тестирование и составите отчет, тем выше вероятность того, что баг будет исправлен.
Урок 57. Сделайте ваш баг-репорт эффективным инструментом продаж
Независимо от того, думаете вы об этом таким образом или нет, ваш баг-репорт — это инструмент продаж; он создан для того, чтобы убедить людей расстаться с драгоценными ресурсами ради получения выгоды, которую вы предлагаете. Применительно к багам ресурсы — это время и деньги, а выгода — улучшение качества продукта, возникающее в результате исправления конкретного бага.
Стратегии продаж, как правило, предполагают достижение двух целей.
- Преподнести выгоду так, чтобы ваш потенциальный клиент захотел ее получить. Ваш отчет должен содержать сведения, благодаря которым читатель точно поймет, почему баг нужно исправить. Например, вы можете объяснить, как этот баг мешает нормальному использованию продукта, какие данные он повреждает или как часто люди будут с ним сталкиваться. Вы можете сослаться на рецензию в журнале или иную публикацию, в которой жалуются на подобный баг у конкурентов. Вы можете привести статистику технической поддержки, показывающую, что такие баги, как этот, в других продуктах стоили больших денег. Вы можете показать, что программа прошла данный тест в предыдущем выпуске (в некоторых компаниях это ключевая проблема). Или можете сделать так, чтобы отчет привлек внимание тех, чьей работе мешает этот баг. Во многих случаях (см. ниже) вы можете взять незначительный на первый взгляд баг и обнаружить более серьезные последствия, проведя дополнительное тестирование, вместо того чтобы сообщать о первой версии бага, который вы обнаружили.
- Предвидеть возражения со ссылкой на незначительность бага и парировать их. Многие баги игнорируются как слишком незначительные, невоспроизводимые, непонятные; как те, которые вряд ли когда-либо возникнут в реальном мире; как проблемы, возникающие только при очень специфической конфигурации оборудования, которой ни у кого не будет; как баги, которые слишком рискованно исправлять; или как баги, которые вряд ли побеспокоят реальных пользователей продукта. Вы можете регулярно предупреждать возражения со ссылкой на незначительность выявленных багов, следуя рекомендациям по составлению баг-репортов. Пишите ясно и просто, проверяйте, повторяется ли баг в нескольких конфигурациях; если да, то отразите это в отчете. Другие возражения варьируются в зависимости от бага. Вы можете предвидеть их и включить соответствующую информацию в отчет или подождать, оценить первоначальную реакцию на отчет и добавить информацию по мере проведения баг-ревью. Мы не говорим, что в отчете вы должны доказывать серьезность бага. Старайтесь не говорить: «Я знаю, что вы не собираетесь исправлять этот баг, считая его неважным по этой причине, но вам следует знать об этом». Вместо этого мы предлагаем вот что: если вы в корне не согласны с возражением, то добавьте в баг-репорт некоторые факты, имеющие отношение к делу, например: «Аналогичный баг имелся во второй версии этого продукта. По оценкам руководителя службы технической поддержки, вследствие этого затраты на техподдержку превысили 100 000 долларов».
Урок 58. Ваш отчет об ошибке — это ваш представитель
Обычно вы не присутствуете при получении и прочтении вашего баг-репорта. Когда вы его пишете, то просите программиста (который не является вашим подчиненным) выполнить дополнительную работу. Программистам редко хватает времени для исправления всех багов. Бо́льшую часть этой работы они выполняют в свое личное время — после окончания рабочего дня или в выходные дни. Вы просите их уделить это время найденному вами багу.
В некоторых компаниях (особенно по мере приближения к завершению проекта) различные руководители решают, что нужно исправить. Группа лиц, принимающих решения, может называться советом по контролю изменений (в разных компаниях эта группа называется проектной командой, группой рассмотрения, боевой командой или просто командой баг-ревью). Эти люди понимают, что каждое изменение стоит денег, требует времени и несет в себе риск прекращения работы каких-либо иных компонентов.
Чтобы добиться исправления бага, вам необходимо убедить совет по контролю изменений одобрить исправление или убедить программиста исправить баг самостоятельно (возможно, поздно ночью, когда совет не видит). Баг-репорт — это ваш основной (часто единственный) инструмент убеждения людей в необходимости исправления бага. Вы можете иметь возможность отстаивать свои интересы на заседании совета по контролю изменений, но во многих компаниях на нем присутствует только один тестировщик (возможно, ваш ведущий тестировщик или менеджер по тестированию). То, насколько хорошо этот человек будет защищать ваш баг, будет зависеть от вашего отчета.
Урок 59. Потратьте время на то, чтобы сделать ваши баг-репорты ценными
Баг-репорты читает и использует большое количество людей, поэтому уделите время тому, чтобы сделать каждый отчет информативным и понятным. Это повысит ценность вашей компании.
В большинстве компаний баг-репорты служат нескольким целям. Например:
- предупреждают о дефектах и помогают программистам устранять основные проблемы;
- предупреждают людей о проблемах в спецификациях и (в зависимости от политики компании), возможно, в тестовой документации, документации пользователя или средствах разработки;
- предоставляют справочную информацию для технических писателей, разрабатывающих разделы по устранению неисправностей для руководства пользователя или сайта компании;
- отмечают вопросы, над которыми, возможно, стоит поработать в процессе обучения клиентов;
- предоставляют наиболее важную информацию для послепродажной поддержки клиентов, столкнувшихся с проблемами, которые не были устранены вовсе или устранены не полностью;
- предоставляют руководству информацию о состоянии и качестве разрабатываемого продукта;
- представляют стартовые предложения по улучшению продукта на начало его следующего выпуска.
Урок 60. Любой стейкхолдер должен иметь возможность сообщить о баге
Стейкхолдер (stakeholder) — человек, лично заинтересованный в успехе продукта. Это может быть сотрудник компании, производящей продукт, клиент или пользователь, который в значительной степени зависит от продукта.
Вся ваша компания заинтересована в выпуске высококачественного продукта в рамках бюджета, в срок и с нужными функциями. Любой человек, работающий в компании, убежденный в том, что качество или набор функций не годятся, должен иметь возможность выразить свой протест таким образом, чтобы он дошел до команды разработчиков. Команда тестировщиков никогда не должна препятствовать такому общению, а, наоборот, всегда должна способствовать ему, даже если (особенно если) жалобы поступают не от разработчиков продукта (в том числе от участников ее самой).
Вы можете не показывать записи отслеживания багов всем желающим. Такие данные должны рассматриваться как конфиденциальные, если вы считаете исходный код и другие решения по разработке конфиденциальными. Тем не менее широкий круг людей должен иметь возможность получить информацию из ваших записей.
Урок 61. Будьте осторожны, меняя формулировки в баг-репортах других людей
Добавляйте комментарии, но не редактируйте чужие отчеты без разрешения тех, кто их написал. Вы бы не хотели, чтобы ваше имя стояло под чем-то, чего вы не писали и не одобряли. Того же не хотят и другие люди в вашей компании, которые сообщают о багах, даже те, кто пишет отвратительные баг-репорты.
Изменение формулировок в отчете без разрешения также может привести к потере важной информации.
Всякий раз, когда вы добавляете что-либо в баг-репорт, особенно в чужой, вставляйте комментарий с вашими инициалами и датой. Например, обычно дополнительная информация выносится на новую строку отчета и начинается с фразы наподобие «[CK 12/27/01]». Это также позволит людям задавать уточняющие вопросы нужному человеку.
Урок 62. Сообщайте о замеченных недостатках качества как о багах
«Для кого-то качество — это ценность». (Weinberg, 1992).
У разных людей разные ожидания от продукта, но если какой-то стейкхолдер им разочарован и считает, что тот стал менее ценным из-за чего-то, что он делает или не делает, то должен написать об этом в виде баг-репорта.
Ваша задача как тестировщика — помочь этому человеку составить отчет, в котором его опасения будут изложены четко и убедительно.
Урок 63. Некоторые стейкхолдеры не могут сообщать о багах. Вы — их доверенное лицо
Заказчики коммерческого готового программного обеспечения (например, потребители) не могут сообщать о багах во время разработки, поскольку у них еще нет программы. Другие стейкхолдеры проекта могут быть недоступны. Как тестировщик, вы заменяете отсутствующие заинтересованные стороны. Чтобы понять, о чем сообщать от их имени, и сделать ваши отчеты убедительными, вам необходимо изучить, как эти люди будут использовать продукт и что будут ценить или ненавидеть в продукте такого типа.
Урок 64. Привлеките внимание стейкхолдера к спорным багам
Допустим, вы считаете, что убедить программистов исправить баг будет трудно, но хотите, чтобы это было сделано. В таком случае подумайте, кому еще в компании выгодно, чтобы баг был исправлен. Например, несоответствия в пользовательском интерфейсе программистам могут показаться незначительными. Попытки переубедить руководителей проекта в подобных вопросах — пустая трата времени.
Несоответствия приводят к увеличению затрат на документацию, обучение и техническую поддержку. Кроме того, если они неизбежно проявятся при демонстрации продукта, это может привести к снижению продаж. Если несоответствия влияют на доступность для лиц с ограниченными возможностями, то государственные учреждения, требующие соблюдения норм доступности, могут отказаться от приобретения продукта. Если несоответствия будут очевидны для рецензентов, то это может привести к негативным отзывам в прессе (описанию продукта как небрежно спроектированного или сложного в использовании). Ни один из этих видов затрат не ударил по бюджету программистов.
Напишите баг-репорт (или служебную записку, приложенную к его копии) так, чтобы он привлек внимание людей, бюджет которых пострадает из-за этого бага. Они сами будут доказывать вам, что баг необходимо исправить. Но если они посчитают баг несерьезным, то не будут настаивать на его исправлении. Тогда, возможно, вам следует оставить этот баг в покое и начать выступать за исправление какого-либо другого бага.
Урок 65. Никогда не используйте систему отслеживания багов для контроля работы программистов
Велик соблазн сообщить, что у одного программиста найдено огромное количество багов, что он их постоянно исправляет или пытается все отложить. Однако после того, как вы используете данные системы отслеживания для того, чтобы враждебно покритиковать одного программиста или поставить его в неловкое положение, остальные программисты займут оборонительную позицию относительно этой системы. Как следствие, наиболее вероятно, они будут утверждать, что баги в дизайне — это не баги, что похожие баги — это дубликаты, что о невоспроизводимых багах не следует сообщать и что вы некомпетентны или нечестны в своем тестировании. Это вполне разумно. Как только вы (или кто-либо другой) начнете использовать систему отслеживания багов не в технических, а в политических целях или для управления персоналом, люди будут относиться к ней именно так.
Урок 66. Никогда не используйте систему отслеживания багов при оценке эффективности тестировщика
Если вы (руководитель отдела тестирования) будете поощрять своих подопечных за количество найденных ими багов, вы вряд ли останетесь довольны их работой. Чтобы набрать нужное количество отчетов об ошибках, тестировщики могут начать, к примеру, сообщать о незначительных багах, которые легко найти, или же создавать отдельные отчеты для каждого частного случая одной и той же ошибки. Из-за этого они, скорее всего, перестанут выделять время на обучение других тестировщиков и улучшение системы отслеживания багов (или любой другой). А разработчики, в свою очередь, начнут упускать ошибки проектирования, теряющиеся в множестве отчетов, созданных для количества.
Урок 67. Сообщайте об ошибках своевременно
Не откладывайте написание отчета об ошибке на завтра: вы можете забыть о значимых деталях. Чем дольше вы откладываете, тем меньше вероятность, что ошибка будет исправлена.
Более того, если руководители знают о том, какую часть кода вы тестируете, и при этом не видят сообщений об ошибках в ней, они могут подумать, что код исправен и работает стабильно.
Урок 68. Никогда не рассчитывайте на то, что очевидный баг уже задокументирован
Другие могут подумать так же, и в результате некоторые очевидные баги будут зафиксированы только на этапе бета-тестирования. Если вы думаете, что отчет об ошибке в системе отслеживания уже есть, найдите его и посмотрите, как именно ошибка была описана и каков был отклик. Возможно, ваш дополнительный комментарий будет полезен. А возможно, баг-репорт придется переписать, если он изначально был плохо составлен или же отклонен.
Мы видели, как это происходило с некоторыми серьезными багами. Многие люди знали об этом баге, но считали, что о нем сообщил кто-то другой. В одном случае баг был исправлен только после того, как продукт был выпущен.
Урок 69. Сообщайте об ошибках проектирования
Программа — это часть системы, включающей в себя материальное оборудование, другие программы и людей, для удобства которых она создается. Если программа сложна в использовании, конфликтует с другим ПО или требует специального аппаратного обеспечения, ее ценность становится сомнительной. Может быть, вы единственный член команды разработчиков, который способен заметить ошибку в проектировании и оценить ее влияние на действующую систему в целом. И если не вы сообщите о такой проблеме, то кто это сделает?
Некоторые (в том числе консультирующие специалисты) считают, что тестировщики не должны сообщать об ошибках проектирования, поскольку, во-первых, архитектура программы должна утверждаться на ранних этапах разработки, а во-вторых, тестировщики не обладают необходимыми знаниями в этой области. Мы не согласны ни с самим утверждением, ни с аргументами, его подкрепляющими.
- Поздняя критика проекта. Даже если программа была полностью спроектирована заранее (что вообще редко происходит в реальных проектах в реальном мире), невозможно просчитать наперед все ошибки, связанные с ее применением. Вполне нормально, что погрешности проектирования могут проявиться тогда, когда система будет уже введена в эксплуатацию. Ошибки нужно документировать по мере их обнаружения, а выявить некоторые из них возможно только на финальных этапах работы над продуктом.
- Недостаточная экспертность тестировщиков. С одной стороны, не все тестировщики способны адекватно оценивать проектные решения. С другой стороны, тестировщики — одни из немногих членов команды, которые досконально проверяют работу готовой программы в целом перед ее продажей или запуском в производство. Будьте, однако, осторожны с критикой, если у вас недостаточно опыта в определенной области. Например, прежде чем критиковать пользовательский интерфейс, сначала стоит ознакомиться с руководством по его дизайну, разработанным для вашей системы, и посоветоваться с теми, кто знает о дизайне больше, чем вы. Если же вы уверены в ошибочности того или иного решения, то смело регистрируйте ошибку в системе отслеживания.
Чтобы команда тестировщиков была более эффективной в обнаружении ошибок проектирования, она должна состоять из людей, имеющих за плечами разнообразный опыт: например, человек с опытом работы в конкретной предметной области (то есть обладающий глубоким знанием о том, как и почему возникла необходимость в разработке данного продукта) будет обращать повышенное внимание на проблемы, которые могут затронуть конечного пользователя, — и это только одна сторона вопроса. Если один из тестировщиков раньше занимался проектированием баз данных, другой — сетевой безопасностью, третий — пользовательскими интерфейсами и т. д., то команда в целом будет способна грамотно оценивать различные аспекты проектирования всего продукта.
Урок 70. Ошибки переполнения могут привести к уязвимостям в системе безопасности
Большинство случаев взлома систем через Интернет происходит из-за ошибок, связанных с переполнением буфера (Schneier, 2000a, 2000b). Их можно было бы отлавливать до релиза, если бы тестировщики усиленно не закрывали глаза на граничные случаи, до которых программистам, по их мнению, нет дела. Все, что может повредить данные или помешать программе нормально работать, — потенциальная лазейка в системе безопасности.
Переполнение буфера происходит тогда, когда размер вводимых данных превосходит отведенное под них место. Часть данных, которая выходит за границы, помещается в другие области в памяти. Дальнейшее развитие событий зависит от характера данных и от того, как определенное место в памяти предполагалось использовать. Иногда не происходит ничего, иногда на экране появляются помехи, иногда программа становится неуправляемой, а иногда и вовсе ломается. Умелый взломщик может воспользоваться такими лазейками, чтобы проникнуть в систему, на которой запущена программа, и получить контроль либо над ней, либо над системой в целом.
Предположим, можно сломать программу, введя 65 536 девяток в поле, принимающее значения от 1 до 99. Будет ли кто-то так делать в своем уме? Разумеется, будет. Наверное, не ваши друзья и не программисты, которые не будут утруждать себя исправлением этой ошибки, ссылаясь на то, что «если какой-то идиот сотворил такое, то сам виноват». Но подобные действия будут совершать не только идиоты.
Любой баг, приводящий к серьезным последствиям, должен быть устранен вне зависимости от того, насколько «маловероятно» его появление. Обнаружив уязвимость, хакер может написать вредоносный код для атаки на систему, а этим кодом смогут потом воспользоваться менее опытные хакеры-дилетанты.
Урок 71. Не игнорируйте крайние случаи
Эффективное тестирование часто включает в себя проверки на предельных значениях, ведь именно при их обработке обнаруживаются первые ошибки. Логика проста: если программа адекватно обработала такие значения, значит, скорее всего, она будет стабильно работать и в других случаях. Получается, о качестве программы можно судить по тому, как она реагирует на предельные значения. Например, при проверке поля ввода, которое должно принимать значения от 0 до 999, разумнее всего будет подать на вход 1, 0, 999 и 1000.
Некоторые программисты закатывают глаза, сталкиваясь с тестами на одном или нескольких предельных значениях, называя их «патологическими» случаями. Вероятность того, что подобный случай встретится на практике, стремится, по их мнению, к нулю, поэтому они считают, что возникающие при этом баги можно не исправлять.
Представим, что программа, которая должна принимать входные значения от 0 до 999, неадекватно срабатывает при вводе 999. Если вы остановитесь на этом значении, программисты, скорее всего, проигнорируют это сообщение об ошибке: «Кому взбредет в голову вводить 999? Это же крайний случай. В реальности никто так делать не будет!»
Попробуйте ввести другие значения. Вводите, к примеру, числа поменьше до тех пор, пока не установите, на каком промежутке программа работает нормально. Если она не справляется со значениями больше 99 (то есть с достаточно заметным промежутком от 100 до 999), такой отчет программистам будет трудно проигнорировать. Если же в отчете об ошибке говорится только о крайнем случае, это тоже значимо — только сообщите об этом явно.
Как и с последующим тестированием, время, которое вы можете потратить на такие ошибки, ограничено. Если вы понимаете, что работа над проблемой затянулась, переходите к поиску других багов. Если ваши коллеги-программисты воспринимают тесты на предельных значениях всерьез, им будет достаточно одного такого теста.
Джеймс Бах — основатель и главный консультант компании Satisfice, Inc., занимающейся тестированием и оценкой качества программного обеспечения.
Брет Петтикорд работает независимым консультантом. Часто выступает на конференциях и ведет семинары по автоматизации тестирования.
Более подробно с книгой можно ознакомиться на сайте издательства:
По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Для Хаброжителей скидка 25% по купону — Тестирование
ссылка на оригинал статьи https://habr.com/ru/articles/847374/
Добавить комментарий