Русский
Русский
English
Статистика
Реклама

Jira

Строим безопасную разработку в ритейлере. Опыт одного большого проекта

17.09.2020 10:15:44 | Автор: admin
Некоторое время назад мы закончили строить процесс безопасной разработки на базе нашего анализатора кода приложений в одной из крупнейших российских ритейловых компаний. Не скроем, этот опыт был трудным, долгим и дал мощнейший рывок для развития как самого инструмента, так и компетенций нашей команды разработки по реализации таких проектов. Хотим поделиться с вами этим опытом в серии статей о том, как это происходило на практике, на какие грабли мы наступали, как выходили из положения, что это дало заказчику и нам на выходе. В общем, расскажем о самом мясе внедрения. Сегодня речь пойдет о безопасной разработке порталов и мобильных приложений ритейлера.


Для начала в целом про проект. Мы выстроили процесс безопасной разработки в крупной торговой компании, в которой ИТ-подразделение имеет огромный штат сотрудников и разделено на множество направлений, минимально коррелирующих между собой. Условно эти направления можно разделить на 3 основные группы. Первая, очень большая группа, это кассовое ПО, которое написано преимущественно на языке Java (90% проектов). Вторая, самая обширная с точки зрения объема кода группа систем это SAP-приложения. И наконец, третий блок представлял собой сборную солянку из порталов и мобильных приложений: разного рода внешние сайты для клиентов компании, мобильные приложения к этим сайтам, а также внутренние ресурсы мобильные приложения и веб-порталы для персонала ритейлера.

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

Этот подход мы сформулировали максимально просто: сканируется наиболее актуальный для всех разработчиков код. Если говорить в терминах Gitflow, а все группы проектов, за исключением SAP, вели ветки разработки в Gitflow, сканируется основная ветка разработки по расписанию.

Но, как всегда, из любого правила бывают исключения: общий подход не везде мог быть применен as is по ряду причин. Во-первых, наш инструмент (анализатор кода) имеет несколько ограничений, обусловленных тем, что мы хотим иметь возможность при необходимости делать наиболее глубокий анализ некоторых языков программирования. Так, в случае с Java анализ по байткоду гораздо более глубокий, чем по исходному коду. Соответственно, для сканирования Java-проектов требовалась предварительная сборка байткода и лишь затем его отправка на анализ. В случае с C++, Objective C и приложениями для iOS анализатор встраивался в процесс на этапе сборки. Также мы должны были учесть различные индивидуальные требования со стороны разработчиков всех проектов. Ниже расскажем, как мы выстроили процесс для порталов и мобильных приложений.

Порталы и мобильные приложения


Вроде бы все эти приложения объединены в одну логическую группу, но на самом деле в них была жуткая каша. Одних порталов было больше 120-ти (!). Компания очень большая, со множеством бизнес, административных и технических подразделений, и периодически каждое из них решает, что ему нужен свой портал и мобильное приложение. Этот портал и приложение создаются, ими какое-то время пользуются, а потом благополучно забрасывают. В результате на начальном этапе нам пришлось провести для заказчика инвентаризацию, поскольку даже разработчики этих приложений не имели единого списка кодовых баз. Например, для управления репозиториями в этой группе разработчики использовали два GitLab, администраторами которых являлись разные люди. Кроме того, среди порталов и мобильных приложений существенная часть проектов была реализована с помощью внешней разработки. Поэтому, когда подходило время релиза, зачастую подрядчики передавали компании исходные коды новой версии чуть ли не на флешке. В итоге компания имела зоопарк различных приложений и полный беспорядок в их коде. Нам пришлось составить список всех проектов, найти всех ответственных за них техвладельцев, тимлидов, а затем согласовать с основным заказчиком департаментом ИБ, какие из них мы будем анализировать.

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

Приоритетной задачей для этой группы ПО ИБ-служба сформулировала внедрение анализа кода на уязвимости, а разработчики выстроить удобный для них процесс проверок, интегрированный в циклы разработки.

Интеграция по стандартной схеме


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


Настройка интеграции с GitLab

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

Разработчики группы порталов и мобильных приложений хотели организовать безопасную разработку как полуавтоматизированный процесс, чтобы код сканировался на уязвимости без какого-либо участия с их стороны. Чтобы офицер безопасности верифицировал результаты анализа на уязвимости и ставил разработчикам задачи в Jira, если считал уязвимости критичными, или же отправлял их разработчикам для получения разъяснений. Разработчики решали бы, нужно ли срочно исправлять уязвимость или нет. И если нужно, планировали бы, в какой релиз смогут включить исправления.

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


Настройка интеграции с Jira

В редких случаях тим-лиды сами смотрели результаты сканирования и заводили задачи в Jira вручную.


Создание задачи в Jira

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

В итоге процесс безопасной разработки после внедрения Solar appScreener стал выглядеть так: порталы ежедневно проверяются на наличие изменений в коде основной ветки разработки. Если основная, наиболее актуальная ветка не обновлялась в течение суток, то ничего не происходит. Если же она обновилась, то запускается отправка этой ветки на анализ в соответствующий проект для этого репозитория. Репозиторию в GitLab соответствовал определенный проект в анализаторе кода, и именно в нем сканировалась основная ветка. После этого офицер безопасности просматривал результаты анализа, верифицировал их и заводил задачи на исправления в Jira.


Результаты анализа и созданные в Jira задачи на исправление уязвимостей

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

Нестандартное в стандартном


В этом, на первый взгляд, не таком уж и сложном процессе имелось два серьезных ограничения. Во-первых, для анализа Android-приложений (то есть написанных на Java) нам нужна была сборка. А во-вторых, для iOS нужны были машины с MacOS, на которых устанавливался бы наш агент и имелась бы среда, которая позволяла бы собирать приложения. С Android-приложениями мы разобрались довольно просто: написали свои части в уже имеющиеся у разработчиков скрипты, которые запускались так же по расписанию. Наши части скриптов предварительно запускали сборку проекта в наиболее широкой конфигурации, которая направлялась в Solar appScreener на анализ. Для проверки же iOS-приложений мы устанавливали на Mac-машину наш MacOS-агент, который производил сборку кода и так же через GitLab CI отправлял код в анализатор на сканирование. Далее, как и в случае с другими видами ПО, офицер безопасности просматривал результаты анализа, верифицировал их и заводил задачи на исправления в Jira.

К порталам и мобильным приложениям мы также относили любые проекты, написанные на Java, их мы собирали и анализировали по аналогичной схеме.

В тех проектах, где не было CI/CD, что было обязательным для нас условием, мы просто говорили: Ребята, хотите анализировать собирайте в ручном режиме и загружайте в сканер сами. Если у вас нет Java или JVM-подобных языков Scala, Kotlin и прочих, то можете просто загружать код в репозиторий по ссылке, и все будет хорошо.

Сложности проекта


Как видно из вышесказанного, в этом стеке приложений основной проблемой было отсутствие во многих проектах CI/CD. Разработчики часто делали сборки вручную. Мы начали интеграцию нашего анализатора с порталов Sharepoint на языке C#. Сейчас C# более-менее перешел на Linux-системы, хотя и не совсем полноценные. А когда проект был в самом разгаре, этот язык еще работал на Windows, и нам приходилось ставить агент на Windows для GitLab. Это было настоящим испытанием, поскольку наши специалисты привыкли использовать Linux-команды. Необходимы были особенные решения, например, в каких-то случаях нужно было указывать полный путь до exe-файла, в каких-то нет, что-то надо было заэкранировать и т.п. И уже после реализации интеграции c Sharepoint команда проекта мобильного приложения на PHP сказала, что у них тоже нет раннера и они хотят использовать C#-овский. Пришлось повторять операции и для них.

Резюме


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

  • внедряемое нами решение достаточно взрослое, чтобы проявлять нужную гибкость для построения процессов DevSecOps в кардинально разных средах внедрения. Гибкость достигается за счёт большого набора встроенных и кастомных интеграций, без которых трудозатраты на внедрение возросли бы в разы или сделали бы его невозможным;
  • настройка нужной автоматизации и последующий разбор результатов не требуют необъятного количества трудозатрат даже при огромном скоупе работ. Согласование и построение внедряемых процессов и полная их автоматизация возможны усилиями небольшой экспертной группы из 3-4 человек;
  • внедрение средств автоматической проверки кода и практик DevSecOps позволяет выявить недостатки текущих процессов DevOps и становится поводом для их настройки, улучшения, унификации и регламентирования. В конечном счёте получается win-win ситуация для всех участников процесса от рядовых разработчиков до топ-менеджеров отделов инженерии и ИБ.

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

А был ли у вас свой опыт реализации подобных проектов? Будем рады, если вы поделитесь с нами своими кейсами внедрения практик безопасной разработки в комментариях!

Автор: Иван Старосельский, руководитель отдела эксплуатации и автоматизации информационных систем
Подробнее..

Строим безопасную разработку в ритейлере. Опыт интеграции с кассовым ПО GK

26.11.2020 10:08:34 | Автор: admin
Что самое сложное в проектной работе? Пожалуй, свести к общему знаменателю ожидания от процесса и результата у заказчика и исполнителя. Когда мы начинали внедрять безопасную разработку в группе GK-приложений (кассового ПО) крупного ритейлера, то на входе имели вагон времени и задачи снижения уязвимостей в коде. А вот что и как нам пришлось решать на практике, мы вам расскажем под катом.
Кстати, это уже третий пост, в котором мы делимся своим опытом выстраивания процесса безопасной разработки для крупного ритейлера. Если пропустили, можете прочитать первые две части: о безопасной разработке порталов и мобильных приложений и о безопасной разработке в группе приложений SAP.



О проекте


С этого скоупа мы начинали, когда пришли к заказчику. Согласно стартовому плану проекта, у нас были довольно вольготные сроки его реализации. Мы очень радовались, наивно думая, что сможем вести несколько проектов одновременно. В итоге мы почти все время уделяли именно кассовому ПО, потому что все оказалось гораздо сложнее. В целом, это стало самым сложным направлением интеграции, поскольку здесь требовалась наиболее серьезная автоматизация процесса.

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

GK


GK это по сути фреймворк, на основе которого можно создавать свою кастомизацию кассового ПО. Заказчик несколько лет назад выкупил у GK некоторую часть исходного кода этого софта для создания собственной версии, соответственно, это направление представляло собой очень большую группу разработки. Большая часть ПО написана на языке Java (90% проектов). Встречались и некоторые проекты, написанные на C++ с использованием довольно древних библиотек, поскольку аппаратное обеспечение было заточено под этот стек технологий. Для Windows под Windows Server 2008 и под набор библиотек для Visual Studio, для которых данная версия ОС была последней совместимой.

В группе имелись свои жесткие процессы разработки, свои релизные циклы. Процесс ветвления был похож на Gitflow с основной веткой разработки и feature-ветками под разнообразные задачи. Однако feature-ветки могли быть в статусе разработки месяцами (часто готовые к merge, но заброшенные) и вливались прямо перед релизом, в который они по плану должны были войти.

Помимо внедрения в CI/CD мы еще внедрялись и в Jira, для чего нам пришлось создать отдельную сущность для классификации задач уязвимость. Этот вид задачи позволял заводить уязвимости внутри Jira в соответствии с процессом разработки и работы с таск-трекером.

Направление GK имело длинный процесс разработки, когда создается feature на какой-либо функционал, а потом эта feature-ветка может жить очень долго отдельно от основной ветки разработки. Ее могут верифицировать, но не могут влить в master или development почти вплоть до самого релиза ввиду технических сложностей регрессионного тестирования и т.п.

Решение для интеграции


Когда мы пришли в группу GK внедрять Solar appScreener, мы были удивлены огромным количеством кода в проектах этого направления и предложили стандартный вариант сканирования основной ветки разработки. Разработчики сказали, что они тоже хотят получать информацию об уязвимостях и тоже хотят пользоваться анализатором, но не так, как офицеры безопасности. Им нужна была автоматизация проверки на уязвимости: единая точка входа в виде GitLab, где можно видеть все изменения. Чтобы на сканирование автоматически запускался код не только основной ветки разработки, но и всех побочных веток. При этом нужен был автоматизированный запуск из Jira и по просьбе заказчика полуавтоматизированный из Jenkins и GitLab.

В итоге мы решили, что самым простым способом анализа ветки (в особенности для долгих feature-веток) будет запуск сканирования таким образом, чтобы задача в Jira при ее полном завершении (финальном push-е) переводилась в статус in review. После чего она попадала к специалисту, который может принять изменения и дать добро на старт сканирования кода на уязвимости. Иначе анализ кода по каждому push-у разработчика в репозитории создал бы адскую нагрузку и на людей, и на технику. Разработчики комитили код в репозитории не реже раза в пять минут, и при этом проекты порой содержали по 3,5 млн строк кода, одно сканирование которого, соответственно, длилось 6-8 часов. Такое никакими ресурсами не покроешь.

Стек технологий


Теперь немного о том, какой набор технологий использовался в проекте. GitLab в качестве системы контроля версий, Jenkins в качестве CI/CD-системы, Nexus в качестве хранилища артефактов и Jira в качестве системы отслеживания задач. При этом сами разработчики взаимодействовали только с Jira и с GitLab, тогда как с Jenkins инженеры, а с Solar appScreener безопасники. Вся информация об уязвимостях в коде присутствовала в GitLab и Jira.

Поэтому пришлось организовать процесс сканирования следующим образом: в Jira задача переводилась в in review через Jenkins, так как была необходима сборка. Имелся целый стек из Jenkins-плагинов и скриптов, которые получали веб-хук из Jira. То есть помимо вида задачи уязвимость нам пришлось создавать в Jira еще и веб-хуки, которые при изменении проекта в GK отправлялись в Jenkins и требовали дополнительных шагов по настройке и серьёзной доработке двусторонней интеграции. Процесс был таким: когда в GK обновлялась какая-либо задача, Jira проверяла, соответствует ли эта задача тем, которые должны отправляться в Jenkins, а именно является ли это задачей разработки. И только после этого веб-хук уходил в Jenkins, который парсил веб-хук и на основе тела запроса понимал, какому репозиторию в GitLab и какой группе работ (job-ов) нужно запускаться.

Разработчики GK выставили ряд требований при заведении задач в Jira, и мы старались их использовать по полной, чтобы получить максимальное количество информации. Благодаря этому мы смогли правильно матчить репозитории в GitLab и ветку, которую мы должны были стянуть из конкретного репозитория для ее запуска на анализ. В требованиях мы жестко прописали, что ветка в GitLab обязательно должна содержать в названии номер задачи в Jira. В принципе, это best practice, который используется повсеместно в самой задаче должны быть метки, маркирующие, к какой части приложения/системы относится проблема.

На основе веб-хука, в котором содержалось название проекта, метки, поля с компонентами, а также ключ самой задачи и т.п., происходило автоматическое определение необходимости запуска всех задач. Часть проектов получала ответ всех значений удовлетворительно и после этого отправлялась на сканирование. А именно: поступал запрос в GitLab, проверялось наличие в нем данной ветки разработки, и при подтверждении система запускала сканирование новой части кода этой ветки в Solar appScreener.

Учитываем пожелания



Кадр из мультфильма Вовка в тридевятом царстве

Поскольку уязвимостей в GK-проектах было десятки тысяч, разработчики не хотели видеть их все. Меж тем в коде содержались порой критичные уязвимости: вставленные в код пароли, отраженные межсайтовые скриптинги, SQL-инъекции и т.п.

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

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

Как и для остальных проектов компании, мы выстроили для GK соответствие проекта в GitLab проекту в Solar appScreener, а дополнительно провели корреляцию с веткой разработки. Чтобы разработчикам и офицерам ИБ было проще искать, мы создали файл с реестром названия группы репозиториев, конкретного проекта из этой группы и ветки в Solar appScreener.

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

Интеграция с GitLab


Сначала мы сканировали основную ветку разработки для каждого репозитория, от которой шла ветка с изменениями. Поскольку разработчики хотели видеть комментарии с изменениями сразу в GitLab, мы договорились, что если ветка переведена в статус in review, это значит, что уже есть соответствующий merge request на ее вливание. Система проверяла, что merge request был действительно открыт, и если это подтверждалось, то Solar appScreener анализировал основную ветку разработки. Затем он сканировал ветку с изменениями, строил diff, выгружал его, получал только новые уязвимости, брал из них критичные (наш инструмент позволяет настраивать уровни критичности) и преобразовывал их описание в формат текстовых сообщений со ссылкой на данное вхождение в конкретном проекте в Solar appScreener (см.скриншот ниже). Эти сообщения отправлялись в GitLab в виде дискуссии от имени технической учетной записи. В merge request вместе с измененным кодом можно было увидеть непосредственно строку срабатывания. Её сопровождал адресованный конкретному разработчику комментарий в GitLab типа вот здесь содержится уязвимость, пожалуйста, поправьте или закройте ее.



Таким образом, между этими двумя сканированиями мы выявляли изменения, которые привнес разработчик. Если количество уязвимостей увеличивалось, это обязательно отражалось в комментариях отчёта. Такая схема была очень удобна для всех участников, потому что в GitLab сразу же появлялись неразрешенные дискуссии, а это значит, что merge request влить нельзя. И ответственный за approve merge requestа видел, что разработчик допустил уязвимости, и их нужно закрыть.

Интеграция с Active Directory


Чтобы просматривать уязвимости через Solar appScreener, разработчикам нужны были права. Поэтому помимо всей интеграции с системами разработки и со всеми тремя скоупами мы еще интегрировались и с сервисами Active Directory. Для нас некоторую сложность представляло то, что у заказчика был чудовищно большой AD с миллионом вложенных групп, что потребовало множества оптимизаций. То есть помимо внедрения CI/CD нам приходилось в процессе решать много сопутствующих задач настройки, адаптации и оптимизации (см. скриншот ниже).



Что касается интеграции с Active Directory, разработчики GK не хотели настраивать параметры доступа в ряд проектов Solar appScreener непосредственно в AD, потому что они не были владельцами этого ресурса. В компании процесс выдачи прав доступа выглядел следующим образом: если разработке нужно было внести нового человека в группу, приходилось писать заявку в техподдержку. Там определяли, кому именно отправлять данный запрос, кто отвечает за выдачу подобных прав, действительно ли можно выдать этому человеку права, авторизованы они или нет и т.п.

Это трудоемкий процесс, которым разработчики не управляли, в отличие от GitLab.Поэтому они попросили организовать интеграцию с AD следующим образом. Они разрешают видеть уязвимости не только техвладельцам системы и офицерам безопасности, как это было сделано для других направлений, но и сделать матчинг прав в GitLab. То есть если человек имеет права разработчика и выше (maintainer, владелец репозитория), то он может просматривать соответствующие проекты в Solar appScreener, которые относятся к этому репозиторию. Когда в Solar appScreener создавался новый проект, система запрашивала имена всех, кто состоит в GitLab в данном репозитории с уровнем доступа выше разработчика. Список выгружался, поступало обращение в анализатор кода, который в свою очередь отправлял запрос в AD с добавлением списка отобранных людей. Все, кто состоял в данном репозитории в GitLab, получали автоматические права через свои AD-учетки на доступ к проекту в Solar appScreener. В конце всей цепочки генерился pdf-файл с отчетом по уязвимостям из анализатора кода. В отчете содержался diff, который рассылался списку пользователей проектов GK на электронную почту.

Резюме


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

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

Если у вас есть собственный опыт реализации практик безопасной разработки, пожалуйста, поделитесь им в комментариях!

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

Автор: Иван Старосельский, руководитель отдела эксплуатации и автоматизации информационных систем
Подробнее..

Строим безопасную разработку в ритейлере. Итоги одного большого проекта

22.12.2020 10:22:28 | Автор: admin
Эта статья завершающая в цикле материалов о нашем опыте выстраивания процесса безопасной разработки для крупного ритейлера. Если пропустили, можете прочитать первые части: о безопасной разработке порталов и мобильных приложений, о безопасной разработке в группе приложений SAP и о встраивании в процесс разработки кассового ПО. Настало время собрать шишки, которые мы набили подвести итоги.

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




Lessons to Be Learned


1. Учитываем регламенты и бюрократию


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

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

Нам нужно было внедриться в большое количество репозиториев мобильных приложений, но не во всех из них был настроен CI, и поэтому не везде можно было посмотреть, как собирается код. Поэтому мы сначала получали доступ к исходному коду (к сожалению, только на чтение). Доступа к инфраструктуре сборки и тестирования у нас не было, поэтому мы пытались собрать его у себя локально, писали внутренние инструкции для воспроизводимости и страховки от бас-фактора, пытались автоматизировать сборку и запуск анализа, постоянно консультировались с разработчиками ритейлера. Наконец, когда мы локально прогнали все анализы исходного (или собранного кода) в Solar appScreener, все финализировали и пришли к заказчику с готовым планом, выяснилось непредвиденное. Некоторые репозитории изменились (соответственно, наши подходы устарели), а часть тимлидов просто отказалась давать доступ к коду, потребовав инструкции по интеграции, чтобы внедрить все самостоятельно.

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

2. Текучка существенный тормоз процесса


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

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

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

3. Погружение в специфику избавит от множества проблем


На этапе внедрения мы нередко сталкивались с недочетами в планировании. Поскольку менеджмент ритейлера попросил подготовить генеральный план до утверждения проекта, а после утверждения мы были вынуждены идти четко по намеченному курсу, возникали сложности. На старте мы ожидали, что внутри компании все будет устроено плюс-минус единообразно (не считая SAP), но это оказалось совсем не так. Отличались инфраструктура и способы ее развертывания, регламенты по разработке, уставы, ограничения в приобретении продуктов и т.д. Мы прекрасно понимали, что столкнемся с различными технологиями в разработке, но надеялись на единые подходы к процессам и единые концепции, и вот в этом мы ошиблись.

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


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

Изменения в продукте по результатам проекта


1. Интеграция с AD


До этого проекта интеграция Solar appScreener с Active Directory не была оптимизирована под высокие нагрузки. Она начинала тормозить при подключении к каталогам с тысячами пользователей, с ней было не очень удобно работать. В процессе развития проекта систему доработали так, что никаких нареканий к ней уже не возникало. Теперь мы сможем интегрироваться с любой подобной системой, и проблем с производительностью у нас не будет.

2. Jira


Мы также серьезно улучшили все нюансы, связанные с Jira. До проекта мы полагались на дефолтную реализацию Jira, но у данной ритейловой компании Jira была очень серьезно переписана: добавлены различные поля, изменена дефолтная механика создания задач, все изначальные шаблоны. Поэтому мы внедрили в Solar appScreener инструмент, который позволяет подстраиваться под любой вид интеграции, потому что имеет возможность редактировать тело создаваемой задачи, которая посылается в Jira по API из Solar appScreener. Это очень гибкий инструмент.

Например, когда мы настраивали интеграцию с SAP, то столкнулись с тем, что наша старая интеграция с Jira выгружает какие-то дефолтные поля задачи, ты пытаешься создать задачу, и это не получается. Думаешь, что происходит?. Открываешь Jira, а там все не так, Jira по API выдает абсолютно не те дефолтные поля, не того типа данных, которые на самом деле должны содержаться. Но поскольку на эту реализацию у заказчика были завязаны процессы, то проблемы надо было решать на стороне Solar appScreener.

В результате в SAP нужно было заранее определить поля estimation time to do this task. Estimation time приходит как string, заходишь и видишь в нем два поля. А если открыть XML, то обнаруживается, что в этих полях данные должны быть описаны определенным образом. То есть это уже, по сути, словарь со множеством значений, где нужно сразу прописать время, например, one day в формате именно 1d. Ты это исправляешь, пытаешься запустить интеграцию и опять что-то не работает. Смотришь и понимаешь: какое-то поле, которое выгрузилось как обязательное, действительно числится как обязательное. Но при этом в самом интерфейсе его заполнять не нужно. Пару раз вот так потыкавшись, ты в итоге реализуешь интеграцию, но если бы у нас не было возможности гибкой настройки любого вида полей, то мы бы не смогли настроить интеграцию с такой кастомной версией Jira.



3. Изменение архитектуры приложения


Параллельно с этим проектом мы серьезно модернизировали архитектуру нашего приложения. Это потребовало существенных трудозатрат, так как необходимо было перейти от парадигмы цельного монолита, нагрузка от работы которого полностью ложилась на сервер, на классическую модель backend-frontend. Из-за чего пришлось применять другие подходы во всей разработке, проектировании, создании своего API и изменении стека технологий. В итоге это решение существенно упростило создание автоматизации так как именно наш новый API стал её основным инструментом и точкой входа.

Для себя мы выяснили, что есть очень много запросов на переход с MariaDB/MySQL, функционала которой было достаточно для работы приложения, на PostreSQL. Особенно со стороны крупного бизнеса, для которого эта база данных является одной из наиболее распространенных благодаря широкому функционалу и хорошей поддержке. Так, заказчик в определенный момент отказался от поддержки MariaDB, и их подразделение баз данных перешло на работу исключительно с PostgreSQL. Поэтому нам пришлось внедрять поддержку этой базы данных.

Резюме


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

Проект выявил узкие места, и мы осознали, как с ними бороться в будущем. Наша команда поняла для себя, как должна выглядеть архитектура Solar appScreener через год, чтобы продукт улучшался, расширялись его варианты поставки. Многое для себя выяснили с точки зрения улучшения пользовательского опыта работы с продуктом. В некоторых местах не хватало поиска по пользователям. Нужно было дать возможность добавить пользователя в локальную группу из LDAP и других протоколов сразу в нескольких, связанных с панелью администрирования местах (в настройках конкретного проекта, в настройках пользователя и т.п.).

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

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

Автор: Иван Старосельский, руководитель отдела эксплуатации и автоматизации информационных систем
Подробнее..

Как мы обрабатываем жалобы пользователей с помощью JIRA (REST API)

09.07.2020 08:06:27 | Автор: admin


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


Все жалобы пользователей должны где-то храниться, быть приоритезированы, удобно отслеживаться, и, более того, должны быть вовремя обработаны. Но не всегда есть возможность выделить достаточно ресурсов на разработку и поддержание подобной системы, ведь всегда найдется задача в бэклоге с более высоким приоритетом. Ниже я расскажу, как мы достаточно эффективно и быстро решили эту задачу в Uxcel используя JIRA REST API.


Для чего нам Report a problem?


Добавим немного контекста для чего мы предоставляем функционал жалоб и что нам нужно?
Uxcel веб-сервис для обучения UI/UX в игровой форме. Обучающим элементом у нас является Практика в большинстве случаев это 2 изображения, где одно верное, а другое нет. Что позволяет натренировать глаз находить недочеты даже в визуально идентичных элементах. Каждая практика помимо изображений имеет подсказку (hint наводку на верный ответ) и описание (description) с теорией, касающейся данной задачи.



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



Чтобы не изобретать велосипед со своими бордами, тикетами и backlog-ом, а также чтобы хранить все задачи команд в одной системе и даже в общих спринтах, было решено для этих целей использовать JIRA + REST API.


Организация тикетов в JIRA


Для каждой практики у которой есть хотя бы 1 жалоба создается BUG в JIRA в выделенном эпике Practices Reports. А сами жалобы хранятся в виде комментариев к соответствующим багам-практикам. В дополнение к этому, для разных видов практик добавляется Label (в нашем случае такие как: Course, Gym, UEye). Общая логика представлена на схеме ниже:



Таким образом, контент-команда выбирает наиболее приоритетные практики (в виде багов) для исправления в каждом спринте.


А теперь давайте взглянем на технические подробности реализации.


Интеграция с JIRA REST API


Первым делом нужно создать API token в JIRA, чтобы получить доступ к JIRA API. Для использования на продакшене рекомендую создать отдельного пользователя от имени которого и будут создаваться тикеты, иначе придется отбиваться от постоянных уведомлений, в то время как для отдельного пользователя их проще сразу все отключить.


Получение API токена:




  • Задаем имя токена -> нажимаем Create


Готово. Сохраняем куда-нибудь созданный токен, терять его нельзя.


Теперь можно выполнять API запросы к JIRA. В каждый запрос передается заголовок, содержащий емейл (пользователя для которого был создан токен) и сам токен их передаем посредством реализации HTTP basic authentication.


Пример кода (весь код на TypeScript для NodeJS):


private generateAuthHeader(): string {    // конвертируем строку email:apiToken в Base64    const basicAuthValue = Buffer.from(`${this.jiraEmail}:${this.jiraApiToken}`).toString('base64');     return `Basic ${basicAuthValue}`;}

Примечание: для хранения ключей и паролей мы используем AWS Secrets Manager. Прямо в коде такие данные хранить не безопасно. Больше информации тут.

Создание бага через API


Осталось совсем немного подготовки. Для того чтобы создать баг, нам нужно знать его Issue ID в JIRA. Один из способов его узнать вызвать GET запрос на получение информации обо всех типах:


GET https://{id}.atlassian.net/rest/api/3/issuetype 

Поскольку это разовая операция, то чтобы не писать код можно воспользоваться Postman:



Во вкладке Authorization выбираем Type: Basic Auth, вводим email и api token.


В ответе нас интересует эта часть:


{    "self": "https://{id}.atlassian.net/rest/api/3/issuetype/10004",    "id": "10001",    "description": "A problem or error.",    "iconUrl": "https://${id}.atlassian.net/secure/viewavatar?size=medium&avatarId=10303&avatarType=issuetype",    "name": "Bug",    "untranslatedName": "Bug",    "subtask": false,    "avatarId": 10303}

После того как узнали Issue Id типа BUG (10001) нам нужно узнать Project Id, к которому баг будет принадлежать. Похожим образом можем получить список всех проектов и найти id нужного.


Для этого делаем GET запрос на


GET https://{id}.atlassian.net/rest/api/3/project/search

И последний подготовительный шаг: как я выше упоминал, мы храним баги в отдельном эпике (Jira Epic). Его id знать не обязательно, достаточно скопировать его Key (расположен перед названием эпика, либо в адресной строке, например UX-1).


Все готово к созданию первого бага через API.


Я использовал npm пакет Got для создания HTTP запросов для NodeJS.

await got.post({    url: `${this.jiraApiHost}/issue`, // jiraApiHost = https://{id}.atlassian.net/rest/api/3    headers: {        Authorization: authorization, // созданный Basic Auth Header в методе generateAuthHeader        'Content-Type': 'application/json'    },    responseType: 'json',    json: {        update: {},        fields: {            issuetype: { id: this.jiraBugTypeId }, // полученный id типа BUG (пример - 10001)            project: { id: this.jiraPracticeReportProjectId }, // id проекта (пример - 10005)            parent: { key: this.jiraPracticeReportEpicKey }, // ключ Epic (пример - UX-1)            summary: practiceTicketName, // имя практики формата -  [practiceId] practiceName (#reports)            labels: [practice.label]        }    }});

API Reference


Баг создан. Далее рассмотрим остальные методы необходимые для настройки полного цикла обработки жалоб и ведения их в JIRA, такие как: Поиск, Обновление статуса, Обновление информации, Добавление комментария к багу.


Поиск бага через API


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


Пример кода:


// формируем JQL запрос, ищем по типу BUG в эпике где хранятся жалобы по id практики (которое есть в названии каждого бага)const jql = `issuetype = Bug AND project = CNT AND parent = ${this.jiraEpicKey} AND text ~ "${practiceId}" order by created DESC`; const response = await got.get({    url: `${this.jiraApiHost}/search?jql=${jql}`,    headers: {        Authorization: authorization    },    responseType: 'json'});const practiceJiraTicket = response.body['issues'] && response.body['issues'][0];

API Reference


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


Обновление статуса бага через API


Чтобы обновить статус, воспользуемся Transitions. Но для этого нужно узнать Status ID для TODO / OPENED статуса (статус зависит от настроек JIRA).


Возвращаемся к Postman:


GET https://{id}.atlassian.net/rest/api/3/project/{projectIdOrKey}/statuses

По id проекта получаем все статусы, находим статус, который указывает на открытое состояние тикета и сохраняем его id.


Запрос на перевод бага в открытый статус:


await got.post({    url: `${this.jiraApiHost}/issue/${practiceJiraTicket.key}/transitions`, // где practiceJiraTicket - найденный объект бага    headers: {        Authorization: authorization,        'Content-Type': 'application/json'    },    responseType: 'json',    json: {        transition: {            id: this.jiraToDoStatusId // id статуса полученного выше (пример - 10006)        }    }});

API Reference


Следующий шаг после перевода найденного бага в открытое состояние обновление названия (а если нужно, то и описания либо приоритета).


Обновление названия бага через API


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


Код вызова API для обновления бага:


await got.put({    url: `${this.jiraApiHost}/issue/${practiceJiraTicket.key}`,    headers: {        Authorization: authorization,        'Content-Type': 'application/json'    },    responseType: 'json',    json: {        update: {            summary: [{ set: newPracticeTicketName }]        }    }});

API Reference


Далее добавим детали самой жалобы в виде комментария к уже подготовленному багу.


Добавление комментария через API


Каждая жалоба пользователя хранится в виде комментария к багу-практике.


Код создания комментария:


await got.post({    url: `${this.jiraApiHost}/issue/${practiceJiraTicket.key}/comment`,    headers: {        Authorization: authorization,        'Content-Type': 'application/json'    },    responseType: 'json',    json: comment // подробности о формировании объекта ниже});

API Reference


Объект comment формируется в виде Atlassian Document Format.
На сайте так же есть Builder, который значительно упрощает генерацию объекта: просто форматируем текст под свои нужды в редакторе при этом параллельно создается итоговый JSON объект.


Готово! Теперь можно принимать, хранить, обрабатывать, закидывать в спринты и удобно искать жалобы пользователей используя JIRA.


Как у нас выглядят жалобы в виде комментариев:



Итоговый вид нашего списка багов в JIRA (название содержит id, #N число жалоб, % верных ответов):



Дальше все зависит от вашей фантазии и требований. Например, можно:


  • реализовать асинхронную обработку жалоб, чтобы пользователь не ждал пока пройдет вся цепочка запросов к JIRA (у нас реализовано средствами AWS SNS)
  • добавить поле priority для багов и менять приоритет в зависимости от числа жалоб для более удобной фильтрации в борде
  • дополнительно информировать модераторов в Slack при появлении новой жалобы со ссылкой на созданный баг (slack/webhook пакет очень прост в интеграции)
  • настроить JIRA Webhooks, чтобы при закрытии бага автоматически рассылать уведомления всем пользователям, которые жаловались на практику с благодарностью за участие в улучшении продукта
  • автоматически назначать баг на автора контента, на который поступила жалоба.

Всем спасибо за внимание! Надеюсь, статья была для вас полезной :)
С радостью отвечу на ваши вопросы!

Подробнее..

Перевод Оптимизация рабочего процесса при помощи fzf

05.04.2021 12:20:40 | Автор: admin

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


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

Базовая функциональность fzf очень проста: он читает строки из стандартного потока ввода и даёт пользователю интерфейс, чтобы можно было выбрать одну или несколько строк и вписать их в стандартный поток вывода. Вики-страницы этого инструмента содержат массу примеров эффективного применения fzf. Это прекрасный ресурс, я взял несколько функций оттуда в свой репертуар и пользуюсь этими функциями почти каждый день, но в своей работе вы можете обнаружить очень специфические процессы, которых нет в вики, тогда как автоматизировать их было бы полезно.

Чтобы показать, как я подхожу к процессам подобного рода, я расскажу о 4 задачах, с которыми обычно сталкиваюсь. Затем напишу функцию оболочки с fzf, которая сделает работу удобнее. Кроме того, я расположу эти функции в порядке возрастания сложности:

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

Последние версии функций, включая варианты для fish, вы найдёте на Github.

Активация виртуальных сред python

Переменные моих виртуальных сред python содержится в файле ~/.venv. Вот, что я обычно делаю, чтобы активировать одну из сред:

  • начинаю ввод source ~/.venv/;

  • чтобы запустить автозавершение, нажимаю <tab>;

  • выбираю среду по желанию;

  • добавляю bin/activate и нажимаю <enter>.

Процесс можно улучшить чем-то вроде virtualenvwrapper, но есть и хороший пример с fzf: это простейшее решение, которое может занять всего одну строку.

function activate-venv() {  source "$HOME/.venv/$(ls ~/.venv/ | fzf)/bin/activate"}

activate-venv-simple.bash(download)

Активировать эту функцию можно с помощью команды:

source activate-venv-simple.bash

(добавьте этот код в свой .bashrc, чтобы он выполнялся постоянно), а затем используйте его, как показано ниже.

В окне выбора fzf показывает несколько виртуальных сред; среда активируется, когда строка выбрана.

Меньшая проблема то, что, если выйти из fzf нажатием ctrl-d, скрипт упадет с такой ошибкой:

bash: /home/crepels/.venv//bin/activate: No such file or directory

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

function activate-venv() {  local selected_env  selected_env=$(ls ~/.venv/ | fzf)  if [ -n "$selected_env" ]; then    source "$HOME/.venv/$selected_env/bin/activate"  fi}

Удаление веток git

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

  • я начинаю ввод git branch -D;

  • нажимаю табуляцию, чтобы вызвать автозавершение;

  • выбираю ветку, которую, как мне кажется, можно удалить.

Иногда я не уверен в том, какую ветку действительно можно удалить. Сначала мне нужно запустить команду git log в этой ветке, чтобы увидеть, что она содержит, и затем удалить её, как показано выше. Затем процесс повторяется до тех пор, пока я не удалю все залежавшиеся ветки.

Этот рабочий процесс хороший пример того, как сильно fzf упрощает работу. В этот раз мы воспользуемся опцией fzf --multi, которая позволяет по нажатию табуляции выбрать несколько записей.

function delete-branches() {  local branches_to_delete  branches_to_delete=$(git branch | fzf --multi)  if [ -n "$branches_to_delete" ]; then     git branch --delete --force $branches_to_delete  fi}

После выполнения source delete-branches-simple.bash мы можем использовать этот код следующим образом.

 Удаление веток при помощи fzf Удаление веток при помощи fzf

Код в основном работает, но реализовать эту функциональность можно по-разному. Первый вариант git branch показывает все ветки, включая ту, в которой мы находимся, она отмечена звёздочкой (*). Поскольку нельзя удалить ветку, в которой мы находимся, то и показывать её смысла нет, так что мы можем опустить эту ветку, предоставив вывод git branch команде grep --invert-match

Ещё один способ: мы можем пропустить переменным $branches_to_delete без кавычек в git branch -D. Сделать это нужно потому, что git каждая ветка нужна как отдельный аргумент. Если вы пользуетесь линтером вроде shallcheck, эта строка ему не понравится, поскольку переменные без кавычек могут вызвать глоббинг и разделение слов. В нашем случае срабатывание будет ложным: ветка не может содержать символов глоббинга; тем не менее я думаю, что избегать переменных без кавычек, где это возможно, хорошая практика, и один из способов сделать это пропустить вывод fzf через xargs прямо в git branch -D, а не хранить этот вывод в переменной. Если в xargs добавить опцию --no-run-if-empty, git будет вызываться только в том случае, если была выбрана хотя бы одна ветка.

Наконец, я упоминал, что, чтобы увидеть выбранную ветку, полезно посмотреть на вывод git log. Сделать это можно при помощи опции --preview: значением этой опции может быть какая-нибудь команда, которая будет выполняться всякий раз, когда в fzf будет выбрана новая строка, и вывод будет показан в окне предварительного просмотра. Фигурные скобки в этой команде работают как плейсхолдер, то есть заменяются на текущую выбранную строку.

function delete-branches() {  git branch |    grep --invert-match '\*' |    cut -c 3- |    fzf --multi --preview="git log {} --" |    xargs --no-run-if-empty git branch --delete --force}

Также обратите внимание на то, что вывод git branch пропускается через cut -с -3, которая из каждой строки удаляет 2 пробела. Если посмотреть на вывод git branch, видно, что каждая ветка, за исключением текущей, имеет префикс в 2 пробела. Если их не удалить, команда в --preview будет такой: git log ' branch-name', что приведёт к жалобам git на лишние начальные пробелы. В качестве альтернативы используйте команду git log {..}, которая тоже удалит пробелы из выбранной строки.

Вот пример: мы удаляем те же три ветки, что и выше, но при этом получаем больше информации.

Поток fzf для удаления ветвей в окне предварительного просмотра. Показаны ветки и вывод git log. Ударение ветвей с помощью fzf улучшенная версия.

Локально заходим в пул-реквест

Когда делается код-ревью, полезно бывает переключиться в ветку кода, который вы просматриваете . Интерфейс командной строки от гитхаба упрощает эту задачу: можно просто выполнить в репозитории команду пр pr-checkout. Так вы окажетесь в ветке соответствующего пул-реквеста и уже локально. Но как узнать номер пул-реквеста? Вот что я обычно делал:

  • открывал пул-реквест в браузере;

  • читал номер в URL;

  • переключался на окно терминала и вводил gh pr checkout, а затем номер.

Этот подход работает, когда мы имеем дело с пул-реквестом в 1 или 2 цифры, но, даже когда цифры всего 3, иногда я переключаюсь на браузер, чтобы убедиться, что запомнил номер правильно.

В моём прошлом посте я уже рассказывал, как при помощи gh автоматически опрашивал api Github, чтобы узнать номер пул-реквеста. Вы можете воспользоваться запросом к api, который я показываю ниже:

gh api 'repos/:owner/:repo/pulls'

Этот запрос возвращает массив JSON-объектов по одному объекту на каждый пул-реквест. Нам нужно конвертировать этот массив в подходящий fzf формат по строке на пул-реквест. Если говорить о данных, которые нам нужны, первое это номер пул-реквеста, который мы хотим пропустить через gh checkout. Также нам нужен способ идентифицировать интересный нам пул-реквест, в этом смысле лучший кандидат его заголовок. Чтобы извлечь эту информацию из JSON, мы можем воспользоваться интерполяцией строки в jq.

gh api 'repos/:owner/:repo/pulls' |    jq --raw-output '.[] | "#\(.number) - \(.title)"'

Вот опция сырого вывода --raw-output, которая определяет строку JSON; без неё каждая строка данных будет окружена кавычками. К примеру, если я выполню команду pr checkout https://github.com/junegunn/fzf, она выведет эти строки:

#2368 - ansi: speed up parsing by roughly 7.5x#2349 - Vim plugin fix for Cygwin 3.1.7 and above#2348 - [completion] Default behaviour to use fd if present else use find.#2302 - Leading double-quote for exact match + case sensitive search#2197 - Action accept-1 to accept a single match#2183 - Fix quality issues#2172 - Draft: Introduce --print-selected-count#2131 - #2130 allow sudo -E env fzf completion#2112 - Add arglist support to fzf.vim#2107 - Add instructions on command for installing fzf with Guix and/or Guix System#2077 - Use fzf-redraw-prompt in history widget#2004 - Milis Linux support#1964 - Use tmux shell-command#1900 - Prompt generally signals that the shell is ready#1867 - add {r}aw flag to disable quoting in templates#1802 - [zsh completion] Expand aliases recursively#1705 - Option to select line index of input feed and to output cursor line index#1667 - $(...) calls should be quoted: \"$(...)\"#1664 - Add information about installing using Vundle#1616 - Use the vim-specific shell instead of the environment variable#1581 - add pre / post completion 'hooks'#1439 - Suppress the zsh autocomplete line number output#1299 - zsh completion: Add support for per-command completion triggers.#1245 - Respect switchbuf option#1177 - [zsh] let key bindings be customized through zstyle#1154 - Improve kill completion.#1115 - _fzf_complete_ssh: support Include in ssh configs#559 - [vim] use a window-local variable to find the previous window#489 - Bash: Key bindings fixes

Пропустив их через fzf, мы сможем выбрать какие-то из этих строк и записать их стандартный поток вывода. Нам интересен только номер запятой, так что извлечём его при помощи команды set регулярного выражения с захватом группы. 1-я работающая версия выглядит так:

function pr-checkout() {  local pr_number  pr_number=$(    gh api 'repos/:owner/:repo/pulls' |    jq --raw-output '.[] | "#\(.number) \(.title)"' |    fzf |    sed 's/^#\([0-9]\+\).*/\1/'  )  if [ -n "$pr_number" ]; then    gh pr checkout "$pr_number"  fi}

Попробуем его на репозитории fzf.

Поток fzf в окне выбора показывает заголовки пул-реквестов. Выбирая строку, мы попадаем на соответствующий пул-реквест.

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

В этой функции мы удаляем ветки выше и заполняем окно предварительного просмотра с помощью вызова git log в выбранной ветви. Первой идеей может быть попытка попробовать то, что я уже показывал, то есть сделать запрос к api, чтобы получить информацию о выбранном реквесте. Но если мы выбираем разные ветви, то задержка запроса к api может начать нас раздражать, затрудняя работу. К счастью, запросы api нам больше не понадобятся: все нужные данные у нас уже есть: мы получили их, когда сделали первый запрос. Что нам нужно это дописать шаблон строки jq, чтобы извлечь всю нужную информацию и затем воспользоваться функцией fzf, которая позволяет спрятать информацию входящих строк в окне выбора и показать её в окне предпросмотра.

fzf рассматривает каждую строку как массив полей. По умолчанию поля разделяются последовательностями пробелов (табуляциями и пробелами), но мы можем управлять разделителем с помощью опции --delimiter. Например, если мы зададим --delimiter=',' и передадим строку first,second,third в fzf, то поля будут first,, second и third. Само по себе это бесполезно. Но с помощью опции --with-nth мы можем управлять полями в окне выбора. Например, fzf --with-nth=1,2 будет отображать только первое и второе поля каждой строки. Кроме того, мы видели выше, что можно написать {} в качестве плейсхолдера в команде предварительного просмотра и fzf заменит его текущей выбранной строкой. Но {} это простейшая форма плейсхолдера. Можно указать индексы полей в фигурных скобках, и fzf заменит плейсхолдер этими полями.

Вот пример, где мы используем как --with-nth, так и --preview, а <tab> играет роль разделителя.

echo -e 'first line\tfirst preview\nsecond line\tsecond preview' |    fzf --delimiter='\t' --with-nth=1 --preview='echo {2}'

fzf разбивает каждую строку по символу табуляции; опция --with-nth=1 указывает fzf показать первую часть в окне выбора; {2} в команде предварительного просмотра будет заменена второй частью, и так как она передаётся в echo, то просто отобразится.

Пример работы с полями в fzfПример работы с полями в fzf

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

function pr-checkout() {  local jq_template pr_number  jq_template='"'\'#\(.number) - \(.title)'\'\t'\'Author: \(.user.login)\n'\'Created: \(.created_at)\n'\'Updated: \(.updated_at)\n\n'\'\(.body)'\'"'  pr_number=$(    gh api 'repos/:owner/:repo/pulls' |    jq ".[] | $jq_template" |    sed -e 's/"\(.*\)"/\1/' -e 's/\\t/\t/' |    fzf \      --with-nth=1 \      --delimiter='\t' \      --preview='echo -e {2}' \      --preview-window=top:wrap |    sed 's/^#\([0-9]\+\).*/\1/'  )  if [ -n "$pr_number" ]; then    gh pr checkout "$pr_number"  fi}

Мы немного изменили эту простую функцию. Извлекли шаблон строки jq в переменную, а затем дополнили её информацией об авторе, времени создания пул-реквеста, времени его последнего обновления, а также его описанием . Всю эту информацию мы получили в объекте JSON. Ответьте на этот запрос к api гитхаба: gh api 'repos/:owner/:repo/pulls'.

Обратите внимание, что мы отделили новую информацию номер и заголовок символом табуляции \t. Символ табуляции используется также в качестве разделителя в fzf, затем мы показываем номер пул-реквеста и заголовок в окне выбора (при помощи --with-nth=1), а оставшуюся информацию показываем в окне предварительного просмотра (при помощи --preview='echo -e {2}').

Обратите внимание также, что на этот раз в jq мы не используем опцию --raw-output. Причина немного неочевидна. Строки, которые мы создаём с помощью jq, содержат экранированные символы новой строки. Если мы передадим опцию --raw-output в jq, она будет интерпретировать все экранированные символы, и, в частности, вместо \n отобразится именно новая строка. Вот пример, сравните выходные данные этой команды:

echo '{}' | jq --raw-output '"first\nsecond"'

и команды

echo '{}' | jq '"first\nsecond"'

первая выведет

firstsecond

А вторая вот такую строку:

"first\nsecond"

Первая версия проблематична. Помните, что fzf работает со строками, делает список строк, позволяя пользователю выбрать одну или несколько строк и вывести их. Это означает, что без опции сырого вывода каждый пул-реквест в fzf будет показан как множество строк. И это определённо не то, чего мы хотим. Поэтому позволим jq вывести escape-версию, чтобы гарантировать, что каждый пул-реквест это одна строка.

Однако такой подход вводит новые проблемы, первая мы по-прежнему хотим настоящие символы новой строки, а не символы \n. Эта проблема решается командой echo -e, которая включает интерпретацию escape-символов. Вторая проблема в том, что без опции сырого вывода jq в начале и в конце строки показывает символы кавычек и распечатывает наш разделитель, то есть табуляцию, как символ в escape. Эту проблему мы решим удалением кавычек в ручном режиме и заменой первого escape-символа \t на настоящую табуляцию. Именно это делается в sed после jq.

Наконец, обратите внимание, что мы определили опцию --preview-window=top:wrap, чтобы fzf оборачивал строки в окне предпросмотра и отображал их верхней части экрана, а не справа.

И вот как это выглядит в действии:

Создание веток для фич из проблем (issues) в JIRA

Мы видели выше, как использовать fzf для удаления ветвей git. Теперь давайте посмотрим на противоположную задачу создание новых ветвей. На работе для отслеживания проблем мы используем JIRA. Каждая ветвь функции обычно соответствует какой-то проблеме JIRA. Чтобы поддерживать эту взаимосвязь, я использую схему именования ветвей git, о которой расскажу ниже. Предположим, что проект JIRA называется BLOG, и сейчас я работаю над проблемой BLOG-1232 с названием Добавить в сценарий запуска флаг вывода подробностей. Я называю свою ветку BLOG-1232/add-a-verbose-flag-to-the-startup-script; описание обычно даёт достаточно информации, чтобы определить функцию, которой соответствует ветвь, а часть BLOG-1232 позволяет мне перейти к тикету JIRA, когда я ищу подробности о проблеме.

Вполне понятно, как выглядит рабочий процесс создания этих веток:

  • вы открываете issue из JIRA в браузере;

  • копируете номер проблемы или запоминаете его;

  • переключаетесь на терминал, начинаете вводить git checkout -b BLOG-1232/;

  • переключаетесь на браузер и смотрите на название;

  • переключаетесь на терминал и добавляете похожее на название в JIRA описание в kebab-cased.

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

И это ещё один рабочий процесс, который можно полностью автоматизировать. С проблемами в Jira можно работать так же, как мы работали с пул-реквестами, через API JIRA. Функция, которую мы напишем, подобна pr-checkout, но будет иметь несколько заметных отличий от неё.

Во-первых, от жира нет удобного инструмента, подобного gh, чтобы общаться с её api. Во-вторых, сервер (по крайней мере сервер, с которым работаю я) не разрешает создавать токены доступа, что заставляет меня при доступе к api использовать простые имя пользователя и пароль. Мне не хочется сохранить мой пароль в скрипте оболочки, а точнее, не хочется делать это в незашифрованном файле, поэтому, чтобы пароль хранился безопаснее, воспользуемся secret-tool. Наконец, создание имени ветки требует большего, чем простое извлечение текста; воспользуемся комбинаций cut, sed, и awk.

Давайте сначала посмотрим на скрипт, а потом попробуем понять, как он работает.

function create-branch() {  # The function expectes that username and password are stored using secret-tool.  # To store these, use  # secret-tool store --label="JIRA username" jira username  # secret-tool store --label="JIRA password" jira password  local jq_template query username password branch_name  jq_template='"'\'\(.key). \(.fields.summary)'\'\t'\'Reporter: \(.fields.reporter.displayName)\n'\'Created: \(.fields.created)\n'\'Updated: \(.fields.updated)\n\n'\'\(.fields.description)'\'"'  query='project=BLOG AND status="In Progress" AND assignee=currentUser()'  username=$(secret-tool lookup jira username)  password=$(secret-tool lookup jira password)  branch_name=$(    curl \      --data-urlencode "jql=$query" \      --get \      --user "$username:$password" \      --silent \      --compressed \      'https://jira.example.com/rest/api/2/search' |    jq ".issues[] | $jq_template" |    sed -e 's/"\(.*\)"/\1/' -e 's/\\t/\t/' |    fzf \      --with-nth=1 \      --delimiter='\t' \      --preview='echo -e {2}' \      --preview-window=top:wrap |    cut -f1 |    sed -e 's/\. /\t/' -e 's/[^a-zA-Z0-9\t]/-/g' |    awk '{printf "%s/%s", $1, tolower($2)}'  )  if [ -n "$branch_name" ]; then    git checkout -b "$branch_name"  fi}

В скрипте мы видим три части. Первая часть это команда curl, её переменные. Через них скрипт общается с API JIRA. Затем вывод api конвертируется строки формата, удобного для fzf; это часть скрипта такая же, как у pr-checkout. Наконец, вывод fzf конвертируется формат имени ветки.

Самые существенные изменения в сравнении с pr-checkout эта команда curl. Мы воспользовались конечной точкой поиска JIRA, которая в качестве параметра URL ожидает запрос на языке JQL. В моём случае меня интересуют все проблемы проекта BLOG, которые закреплены за мной, и те, что отмечены строкой In Progress. Строка запроса JQL содержит пробелы, знаки и скобки. Все они недопустимы в url, поэтому их нужно закодировать. Опция curl --data-urlencode автоматически закодирует эти символы. Поскольку в этой опции по умолчанию применяется запрос POST, чтобы переключиться на get, мы должны добавить опцию --get. Также воспользуемся опцией --user, чтобы сообщить curl, что нужно добавить заголовок базовой аутентификации. И последнее: добавим опцию --silent, чтобы опустить информацию о прогрессе выполнения и --compressed, чтобы сэкономить на пропускную способность.

Затем, чтобы конвертировать записи массива в JSON ответе в одну строку, воспользуемся той же техничкой, что и выше, разделив строку поиска в окне предпросмотра по символу табуляции и пропустив вывод через fzf, чтобы позволить пользователю выбрать запись. Вывод fzf будет строкой вроде BLOG-1232. Add a verbose flag to the startup script{...preview part}, чтобы удалить часть предварительного просмотра строки, воспользуемся командой cut. По умолчанию cut в качестве разделителя использует символ табуляции, а опция -f1 сообщает cut, что нужно вывести первое поле. Результат выполнения команды будет таким: BLOG-1232. Add-a-verbose-flag-to-the-startup-scrip. Затем команда sed заменит первую точку на символ табуляции, а все нечисловые и неалфавитные символы на -, сохранив при этом наши табуляции. И вот результат: BLOG-1232<tab>Add-a-verbose-flag-to-the-startup-script. Наконец, awk возьмёт строку, разделит её по табуляции, преобразует её вторую часть в нижний регистр и вернёт обе части символом косой черты в качестве разделителя.

 Создание новой ветки из проблем в JIRA Создание новой ветки из проблем в JIRA

Заключение

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

Представленные мной рабочие процессы могут никак не касаться вас. Но, надеюсь, вам поможет техника в целом: попробовать понаблюдать, как вы добавляете параметр к командам и как этот процесс можно автоматизировать. Параметры могут быть файлами или каким-то местом в системе, расположение которого не меняется, например, виртуальными средами. Или это могут быть параметры, которые пропускаются через другую команду (пример: ветви гита) или через API (номер пул-реквеста или заголовок из JIRA).

Узнайте, как прокачаться в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Проектные решения игра по твоим правилам

18.08.2020 10:04:18 | Автор: admin
Не секрет, что чем крупнее программный проект, тем больше его успех зависит от результатов работы аналитиков, в частности, от выбора правильной стратегии составления и согласования проектных решений. Однако как организовать работу этих творческих сотрудников? И как сделать так, чтобы результаты их деятельности были одинаково понятны как представителям заказчика, так и программистам? Как оценить возможные сроки выполнения и значимость этой работы для проекта? В этой статье я попытался сформулировать свои рецепты оптимизации управления аналитической работой на проектах по созданию программного обеспечения для государственных заказчиков. Приветствуется любая критика.

Источник

Рамки исследования


Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на проектирование программы.

Дж. Коплиен

Поскольку на текущий момент на рынке труда в IT фигурирует более двух десятков разновидностей вакансий аналитик, сразу оговорюсь, что я буду говорить об аналитической работе на госпроектах по созданию заказного программного обеспечения. Как показывает мой опыт, бизнес-аналитик, не разбирающийся в механизмах автоматизации бизнес-процессов, не может подготовить адекватную постановку задачи. Как не может быть адекватным системный аналитик, не понимающий бизнес-целей автоматизации. Поэтому, с моей точки зрения, аналитик, работающий на заказных программных проектах, должен совмещать в себе компетенции бизнес-аналитика, системного аналитика и UX-дизайнера. Кроме этого, как правило, ведущий аналитик на таком проекте должен выполнять функции Product Owner (если заказчик вам позволит). Именно об организации деятельности таких универсальных солдат пойдет речь далее.

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

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

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

Однако конкретность желаний заказчика не является гарантией того, что ему понравится конечный результат. В ходе моих проектов была выявлена следующая закономерность: все функциональные замечания заказчика, зафиксированные в ходе всех видов испытаний (не путать с выявленными ошибками!), касались требований, по которым превентивно не было согласовано с заказчиком проектное решение. В этом отношении показательна статистика, которую приводит Наталья Руколь, когда при анализе результатов одного из проектов выяснилось, что почти 70% выявляемых на стадии сдачи ошибок вызваны непониманием исходных требований со стороны разработчиков.

Казалось бы, после того, как уточнены требования к программному продукту, нужно сформировать пакет проектной документации в соответствии с ГОСТ РД 50-34.698, согласовать ее с заказчиком и потом разработать ПО в полном соответствии с утвержденным проектом. Зачастую именно о такой последовательности действий приходится слышать от вчерашних студентов-отличников (троечники, как правило, вообще не знают о существовании таких документов) и многих опытных топ-чиновников, которые никогда не несли персональной ответственности за конечный результат разработки программного обеспечения.

Как подсказывает мой опыт, формирование проектной документации это только финальная часть работы аналитика. В качестве аналогии можно привести научно-исследовательскую работу, в результате которой должен быть сформирован отчет в соответствии с ГОСТ 7.32 или написана диссертация. Однако эти документы являются всего лишь формой оформления полученных научных результатов. Проведение бесплодных экспериментов, статистическая обработка белого шума, поиски крупиц требуемой информации в тоннах псевдонаучной макулатуры все эти неотъемлемые составные части научной работы всегда остаются за кадром. Точно так же в случае с проектной документацией. С одной стороны, она является неотъемлемой частью программного продукта. С другой в ней оформлены только конечные результаты аналитической работы.


Источник

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

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

Проектные решения VS проектной документации?


Как всё прекрасно на бумаге,
Как легко следовать словам.
Как просто сделать так, что ты непогрешим.

Б. Гребенщиков

Несмотря на то, что определение понятия проектное решение дано в ГОСТ 34.003-90, в моем случае значение этого понятия было открыто в ходе мучительных и безрезультатных попыток согласования с представителями заказчика нескольких взаимосвязанных, но неоднозначных требований, когда клиенты просто игнорировали предлагаемые нами описания постановки задач (ОПЗ), сформированных в строгом соответствии с РД 50-34.698-90. После осознания того, что решение со стороны заказчика не будет принято вплоть до начала испытаний, был предпринят следующий манёвр: в адрес заказчика было отправлено наше проектное решение (т.е. решение, которое формально он был не обязан согласовывать).

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

Получившийся коктейль одновременно по форме был похож на документ, оформленный в соответствии с требованиями РД 50-34.698-90, однако по факту он не соответствовал ни одному из форматов, приведенных в этом ГОСТ. При этом, то, что было в нем написано, понимал обычный, неподготовленный представитель заказчика. Требования, уточненные в этом документе, были совершенно понятны как для заказчика так и для исполнителя. Были определены границы требований, необходимый объем планируемых работ и чем собственно эти работы должны были завершиться.

В сопроводительном письме присутствовала примерно такая фраза:

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

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

Что забавно, сначала в ответных письмах в случае, если заказчик не присылал необходимые уточнения, мы использовали фразу работы приостанавливаются. После нескольких таких писем один из представителей заказчика устроил форменный скандал в связи с тем, что мы согласно подписанному контракту не можем приостанавливать работы и отсутствие разъяснений в отношении требований не является основанием для прекращения разработки. Однако на формулировку о том, что работы не могут быть продолжены у него не нашлось возражений.

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

Описание слона не по ГОСТ


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

Фредерик Брукс

На мой взгляд, основным критерием хорошего описания постановки задачи (проектного решения) является не выполнение формальных требований ГОСТ, а однозначное описание условий успешного завершения работ по выполнению требований заказчика. С этой точки зрения, фактически неотъемлемой частью любого проектного решения является описание тестовых заданий по проверке требований.


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

  1. Перечень требований заказчика (которые будут реализованы в рамках проектного решения).
  2. Список определений и сокращений.
  3. Перечень нормативных документов, регламентирующих автоматизируемый процесс.
  4. Описание порядка применения программного обеспечения (use case), которое может включать:

    описание автоматизируемого процесса (как правило, в формате BPMN не забывайте отмечать, как выполняется то или иное действие: автоматически, автоматизировано или вообще без компьютера) и предполагаемого результата;
    перечень ролей и их полномочий;
    определение необходимости ведения истории изменения объектов учета (необходимость хранения и последующего анализа предыдущих значений атрибутов объекта) пренебрежение данным пунктом может увеличить время разработки в разы;
    определение необходимости протоколирования действий пользователей (определение таких действий, связь с историей изменения объекта).
  5. Описание доработки:

    описание новых классификаторов и требования по доработке имеющихся, определение порядка их сопровождения;
    описание пользовательского интерфейса (UI) и правил его отображения (в случае, если в рамках проектного решения определяются схемы процессов, все экранные формы должны быть связаны с действиями на этих схемах);
    описание печатных отчетов и правил (алгоритмов) их формирования.
  6. Электронный обмен данными:

    описание форматов и регламента взаимодействия через API;
    описание форматов и регламента (последовательности) загрузки внешних данных в ручном режиме (в виде файлов);
    описание форматов и регламента (последовательности) выгрузки данных в ручном режиме в виде файлов.

    В качестве примеров проектного решения по электронному обмену данными может здорово пригодиться пакет стандартов, разработанный некоммерческим партнерством Стандарты некоммерческого обмена информацией (партнерство распалось в 2011 г., в настоящее время эти стандарты продолжает сопровождать компания ). Также могут помочь нормативно-эксплуатационные документы, размещенные на техническом портале Системы межведомственного электронного взаимодействия (СМЭВ).
  7. Определение полномочий доступа:

    определение атомарных действий, по которым должно (может) производиться ограничение доступа, определение иерархии этих действий;
    определение перечня атрибутов объекта, по которым должно (может) производиться ограничение доступа.
  8. Сценарий (синопсис) проведения тестирования, который включает последовательность выполнения и названия отдельных тестовых заданий, а также ожидаемый результат выполнения этих тестовых заданий. При наличии времени на проектирование в этот раздел могут включаться описание тестовых заданий (по шагам) и краткое описание тестовых данных. Именно в этом разделе должны находить отражение пользовательские истории (собранные и запротоколированные во время проведения информационных обследований), начальные условия выполнения программы, условия (ограничений) успешного завершения, альтернативные варианты завершения процесса. Сценарий проведения тестирования в обязательном порядке должен быть узнаваем со стороны заказчика.

Повторюсь это не фиксированная структура для проектного решения, это формальный перечень вопросов (checklist), ответы на которые должны быть при необходимости отражены в том или ином виде в проектном решении. Как показывает практика, если разработка в отношении одного из описанных выше элементов не предполагается будет лучше, если вы укажете это в проектном решении явно. Или почти явно (не надо пугать заказчика). Главный критерий однозначная трактовка. Важно не переборщить, чтобы вместо решения заявленного требования в результате его согласования не родилось пять новых. Например, фраза Справочник типов объектов должен содержать только актуальные значения и фраза В справочнике типов не предусматривается хранение истории изменений означают одно и то же, но вторая фраза с высокой долей вероятности приведет к тому, что вам придется описывать и реализовывать механизмы версионности этого самого справочника. При формировании проектных решений важно понимать, что его назначение зафиксировать правила, по которым вы гарантированно сдадите связанные с этими решениями требования.

Лучше один раз увидеть


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

Виллард Британ

Многое (если не все) на проекте зависит от того, как представители заказчика представляют себе конечный результат. Поэтому уже на начальных этапах проектирование макетов пользовательского интерфейса имеет ключевое значение для успешности проекта. Уточняйте и конкретизируйте требования заказчика в понятных ему терминах внешнего описания программного продукта. Диалог с представителями заказчика, основанный на обсуждении макетов экранных форм, показал себя гораздо более эффективным, чем диалог по обсуждению форматов входных и выходных данных и алгоритмов их преобразования (основные разделы в ОПЗ, созданном в соответствии с ГОСТ).

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

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

    Источник: Стив Макконел. Сколько стоит программный проект. ISBN: 978-5-91180-090-1
  2. Грамотный UX-дизайн позволяет обеспечить формирование проектной и эксплуатационной документации еще до завершения кодирования. Сразу после согласования проектного решения, параллельно с разработкой, становится возможным формировать руководство пользователя (замена макетов интерфейса на скриншоты осуществляется во время выполнения задач тестирования).
  3. Фиксация макетов пользовательского интерфейса облегчает нахождение решения спорных вопросов при определении новизны требований. Если на согласованном макете UI не было поля, значит, его добавление это новое требование, выходящее за рамки согласованного проектного решения (следующий пример раскроет последствия добавления всего лишь одного поля на форму).
  4. Иногда, форма внезапно может оказать существенное влияние на содержание. Описанный далее случай произошел на четвертой неделе активного UX-проектирования и регулярного обсуждения с заказчиком макетов пользовательского интерфейса одной из подсистем АСУ. Заказчик охотно шел на общение, были уже предварительно согласованы схемы основных процессов и более 80% экранных форм. Мало того, чтобы ускорить разработку была уже создана база данных и по отдельным задачам в полную силу работали программисты. На одном из рабочих совещаний вдруг заместитель начальника управления (для которого собственно и создавалась подсистема) спросил: А где у вас тут поле даты?. Как выяснилось, он имел в виду, что программа должна иметь возможность отразить состояние дел (или сформировать отчет) на любую произвольную дату, и это при том, что ведение истории изменений ранее не обсуждалось. Все представители заказчика подразумевали, что это было совершенно очевидно и не требовало дополнительных пояснений. В результате небольшое замечание увеличило время разработки подсистемы почти в два раза. Надо отметить, что макеты форм практически не изменились, просто на некоторых добавилось поле По состоянию на дату Х.

Источник

Хотелось бы сказать несколько слов о принципах проектирования пользовательских интерфейсов для автоматизированных систем управления. Несмотря на лавинообразный рост использования мобильных устройств, для автоматизированных систем управления, применяемых в государственных учреждениях, настольные компьютеры и ноутбуки остаются вне конкуренции (так же, как и для решения задач программирования и системного администрирования). В настоящее время для прототипирования интерфейсов появилось множество разнообразных средств. Однако за разъяснением особенностей применения Figma или Axure в интересах мобильных устройств теряются 10% примитивных способов, которые позволяют проектировать 90% пользовательских интерфейсов АСУ.

Моя практика показала, что для значительного сокращения проблем при разработке ПО надо придерживаться нескольких простых правил при проектировании пользовательских интерфейсов.

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

Я не буду приводить здесь пример интерфейса IntelliJ IDEA или PhpStorm, однако попробую препарировать на составные части основные составляющие такого UI, с точки зрения аналитика автоматизированной системы управления.

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


Каждая из опций меню главной навигационной панели открывает доступ к формам-спискам объектов. Списки объектов (каталогов) и форм (карточек) отображения этих объектов формируют львиную долю пользовательского интерфейса. Унификация этих двух типов форм в рамках проекта и формирование на их основе навигационной структуры позволяют на порядок сократить количество запросов пользователей, связанных с недоработками пользовательской документации.

В рамках описания любой списковой формы при проектировании должны быть определены:

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

При проектировании списковых форм хорошо зарекомендовали себя следующие правила:

  1. Все элементы управления формой должны располагаться в верхней части в форме панели инструментов при этом вероятность того, что пользователь потеряет их, сводится практически к нулю. При этом практика показала целесообразность отказа от строки иерархического меню в пользу ленточного интерфейса (ribbon).
  2. Для всех списков, как правило, на ленте должны присутствовать четыре группы элементов управления:
  3. При формировании статистических отчетов (в т.ч. и для вывода на печать) желательно не создавать специализированные формы для предварительной настройки этих отчетов. Сама списковая форма с ее возможностями выборки, сортировки и отображения объектов должна обеспечивать предварительную настройку требуемых отчетов. Другими словами по возможности отчеты должны формироваться на основе выбранных критериев при формировании списков.

В рамках описания карточки объекта при проектировании должны быть определены:


  • макет карточки просмотра;
  • перечень действий, которые можно произвести с объектом учета (CRUD, изменение статуса, согласование и т.п.) и требуемые для этих действий полномочия доступа;
  • описание правил валидации атрибутов при добавлении/редактировании;
  • перечень возможных информационных сообщений;
  • способы просмотра истории изменений объекта.

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

  1. В случае, если в ходе разработки требуются изменения уже существующих интерфейсов, не стоит изобретать велосипед. Здесь лучше всего себя проявил Paint.NET (с помощью которого, кстати, подготовлены картинки к этой статье). Не имеет смысла заново перерисовывать формы, проще изменить готовый скриншот.
  2. Если вы разрабатываете новый интерфейс пользователя, а ваш заказчик бумажная крыса, в таких случаях лучше всего себя зарекомендовал MS Visio со стандартным набором элементов управления. Не раз видел, как заказчик, который наотрез отказывался посмотреть разработанный интерактивный прототип, увлеченно обсуждал предлагаемые проектные решения, выполненные с использованием MS Visio, и рисовал очень интересные каракули на макетах, распечатанных на бумаге в цвете, выполненных в стиле привычного ему Windows.
  3. Если вы разрабатываете новую подсистему, а ваш заказчик - продвинутый пользователь, то интерактивные прототипы вне конкуренции. При этом с наилучшей стороны показал себя подход, когда эти прототипы строятся на основании того же самого фреймворка, который используется для создания интерфейса пользователя. В случае одного из моих успешных проектов прототип программного обеспечения строился на основе инструментов DHTMLX. Вместо базы данных для имитации работоспособности использовались статичные XML-файлы, сформированные на основе примеров таблиц, которые предоставил заказчик. Представления (view), созданные аналитиками в ходе прототипирования, использовались как заготовки для работы программистов. За счет низкого порога вхождения по использованию данного фреймворка, трудозатраты аналитиков на создание прототипов пользовательского интерфейса были соизмеримы с трудозатратами, если бы те же макеты экранных форм создавались в MS Visio. Правда, при этом некоторые представители заказчика не понимали, что еще надо программировать после того, как им продемонстрировали рабочую программу.

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

Строительные леса и опалубка


Обычно люди очень много думают. Но беда в том, что они думают о проблемах, а не о решениях этих проблем.

Дэвид Аллен

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

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

Источник

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

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

  • Анализ документов отчет по результатам анализа нормативных документов заказчика или проектной документации.
  • Аналитический обзор отчет по результатам анализа путей решения возникшей проблемы (как правило, сравнительный анализ новых технологий или тенденций рынка).
  • Информационное обследование отчет по результатам проведенного исследования существующих бизнес-процессов заказчика (формирование модели as is как есть).
  • Системный анализ материалы, описывающие в терминах разработчиков способ реализации требований заказчика одного из вариантов использования программного обеспечения (use case). Этот же тип аналитической работы организуется в случае необходимости реинжиниринга legacy-кода.
  • Анализ данных отчет по результатам исследования качества данных, загруженных в систему (выявление ошибок и противоречий).
  • Учебные материалы материалы, подготовленные для проведения обучения сотрудников заказчика или членов проектной группы.

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

Шаблоны описаний задач типа анализ
Тип материала Типовое описание постановки задачи в JIRA (требуемые результаты аналитической работы)
1. Анализ документа 1.1. Выявить перечень изменений по отношению к предыдущей версии документа
1.2. Выявить термины, которые вводит документ
1.3. Выявить и описать нормативные и неформальные классификаторы предметной области, которые указаны в данном документе
1.4. Выявить разделы документов, которые регламентируют автоматизируемые процессы
1.5. Выявить неоднозначности и противоречия
1.6. Сформировать предложения по устранению выявленных недостатков
1.7. Сформировать экспертное заключение о документе
2. Аналитический обзор 2.1. Уточнить цели и задачи решения проблемы
2.2. Подготовить перечень существующих решений (вендоры, основные характеристики, достоинства, недостатки)
2.3. Провести сравнительный анализ существующих решений
2.4. Сформировать предложения по решению проблемы
3.Информационное обследование 3.1. Сформировать перечень разделов нормативных документов, регламентирующих связанные требования.
3.2. Выявить основных участников (потребителей) автоматизируемого процесса, определить их роли и полномочия
3.3. Выявить процессы документооборота и организации делопроизводства (составить общий маршрут прохождения документов с условиями прохождения)
3.4. Определить формы требуемых отчетов и условия их формирования (порядок получения исходных данных, периодичность, сроки представления)
3.5. Выявить потребности по миграции данных и интеграции с другим ПО
3.6. Подготовить описание вариантов использования программного обеспечения в рамках связанных требований (описать пользовательские истории)
3.7. Подготовить примерный перечень тестовых заданий (сценарий контрольных точек проверки требований заказчика)
4. Проектное решение 4.1. Сформировать описание автоматизируемого процесса
4.2. Сформировать перечень ролей и их полномочий.
4.3. Определить требования по ведению истории изменений
4.4. Определить требования по протоколированию действий пользователей
4.5. Сформировать перечень используемых классификаторов
4.6. Подготовить и описать требования к пользовательскому интерфейсу
4.7. Определить требования к регистрации и отображению атрибутов
4.8. Определить правила валидации атрибутов и формирования информационных сообщений в случае нарушения этих правил
4.9. Определить требования по формированию отчетов
4.10. Определить требования по информационному обмену
4.11. Сформировать сценарий проверки реализации проектного решения
4.12. Уточнение проектного решения с ответственными программистами
4.13. Уточнить и согласовать проектное решение с представителем заказчика
5. Системный анализ 5.1. Уточнить (сформировать) общую структуру иерархии классов системы
5.2. Уточнить (сформировать) логическую структуру базы данных
5.3. Уточнить (определить) правила ограничения целостности и индексации данных
5.4. Описать алгоритм обработки в терминах базы данных (протокола обмена)
5.5. Сформировать описание протокола обмена (интерфейса взаимодействия)
5.6. Сформировать описание правил ограничения доступа
6. Анализ данных 6.1. Выявить данные не соответствующих действующим правилам валидации, выявить причину наличия таких данных (как правило, это тяжелое наследие запуска ПО в эксплуатацию)
6.2. Выявить противоречия классификаторов (микс зеленого, теплого и тяжелого)
6.3. Выявить закономерности распределения данных (тут я, конечно, слукавил, поскольку только эта строчка тянет за собой отдельную специализацию аналитика data mining)
6.4. Сформировать предложения о путях устранения выявленных ошибок и противоречий
7. Учебные материалы 7.1. Подготовить перечень учебных источников и нормативных документов
7.2. Разработать рабочую учебную программу
7.3. Подготовить презентацию
7.4. Подготовить перечень основных понятий и их определений
7.5. Подготовить перечень контрольных вопросов (тестовое задание на определение уровня подготовки)
7.6. Подготовить видеозапись занятия

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

План для маэстро


Всё должно быть изложено так просто, как только возможно, но не проще.

Альберт Эйнштейн

Зачастую, когда речь заходит о планировании работ по анализу и программированию, возникает множество споров о том, как можно оценить сроки получения результатов в этом случае. Однако проведенный выше анализ этой творческой деятельности позволяет сделать предположение о том, что в рамках программного проекта это все-таки возможно. Первым шагом к этому становится разбиение работ по проектированию системы на части, которые можно проконтролировать с периодичностью не менее раза в неделю. Необходимо стремится к тому, чтобы трудозатраты аналитика на формирование одного проектного решения не превышали 5 рабочих дней (в терминах объема такое проектное решение должно состоять примерно из 20-30 страниц согласно ГОСТ Р ИСО/МЭК 15910-2002). Соответственно по тем же нормативам на рецензирование того же проектного решения у программиста должно уходить максимум 3 часа.

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

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

Как правило, для получения сроков выполнения задач на анализ, достаточно экспертной оценки самого исполнителя, но в случае возникновения споров можно применить прагматичный подход. Для повышения объективности оценки трудоемкости задач на анализ может быть использован online-калькулятор, который позволяет спланировать и оценить трудозатраты на проведение аналитической работы. С использованием данного инструмента можно сформировать перечень запланированных работ, уточнить их формулировки в зависимости от специфики проекта. Для каждой из планируемых работ учитывается минимальная, максимальная и наиболее вероятная оценка трудозатрат. В результате расчета формируется ожидаемая трудоемкость выполнения задачи и рассчитывается оптимальный резерв времени, который необходимо оставить для страховки. Сформированное описание постановки задачи на анализ можно скопировать прямо в поле описания задачи JIRA.

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

Дополнительные атрибуты задачи типа анализ
Наименование атрибута Описание
Общие сведения
Тип материалов Тип аналитических материалов:

  • анализ документов;
  • аналитический обзор;
  • материалы информационного обследования;
  • проектное решение;
  • системный анализ;
  • анализ данных;
  • учебные материалы.

Результат решения
Актуальная версия Номер актуальной версии аналитического материала вручную изменяется ответственным аналитиком каждый раз, когда происходит загрузка соответствующего аналитического материала в репозиторий документации. Номер состоит из двух частей, разделенных точкой: [A].[B].

  • [A] позволяет отслеживать изменения, которые вносятся в документ по замечаниям заказчика, при этом используются следующие цифры: 0 для внутреннего рассмотрения (рабочий вариант); 1 для первого документа, согласованного внутри компании, при передаче его на рассмотрение заказчику; 2+ - варианты версий при переделке по замечаниям заказчика.
  • [B] позволяют отслеживать изменения, которые вносятся в документ по замечаниям членов проектной команды.

Дата согласования Дата согласования материалов со стороны заказчика
Согласовали Представители заказчика, принявшие результат работы аналитика
Статистика
Текст Количество страниц текста
Схемы Количество схем (рисунков)
Макеты форм Количество макетов экранных форм

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

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

Желательно до встречи в первом приближении сформировать макеты пользовательского интерфейса, которые можно будет обсудить с заказчиком. При проведении информационного обследования необходимо обсудить с заказчиком основной бизнес-процесс, с его точки зрения (пользовательскую историю user story), альтернативные пути, в каком виде заказчик видит конечный результат.

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

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

  • нарушение базовых принципов классификации, например, когда в рамках одной группы смешиваются разные признаки (красное, зеленое, теплое);
  • построение отчетных документов на основе атрибутов, учет которых не предусмотрен;
  • неопределенность или недостаточность нормативных атрибутов для однозначной идентификации объектов учета;
  • отсутствие описания требуемых действий при типовых форс-мажорных обстоятельствах;
  • юридические коллизии наличие расхождений или противоречий в содержании отдельных нормативно-правовых актов, которые регулируют одинаковые или смежные процессы.

Решение этих нормативных конфликтов является одним из ключевых вопросов при встречах с представителями заказчика. Для того, чтобы зафиксировать это решение, в результате проведения информационного обследования в обязательном порядке должен быть сформирован протокол с указанием участников, места и времени проведения. Протокол представляется заказчику на уточнение (e-mail прикрепляется к соответствующей задаче). После этого задание на информационное обследование можно переводить в статус выполнено. В статус закрыто эта задача JIRA переводится после получения от заказчика подтверждения о согласовании протокола.

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

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

4.После согласования с заказчиком (письмо, подтверждающее этот факт, сохраняется в JIRA), задачу по подготовке проектного решения можно переводить в статус выполнено.

Продолжение следует


В настоящее время проектирование программного обеспечения для государственных заказчиков чаще всего организуется в соответствии с требованиями ГОСТ 34 серии. При этом, ратуя за точное соответствие итоговой проектной документации этому ГОСТ, зачастую большинство представителей заказчика забывают о том, что кроме документации, которая предоставляется на испытания разработанного ПО, со стороны заказчика в рамках согласования эскизного и технического проектов должны быть утверждены проектные решения. И даже в том случае, когда согласовываются эскизный и технические проекты, не редкость, когда в угоду нереальным срокам при полном соблюдении формы игнорируется содержание. Особенно это характерно для проектирования систем, напрямую не связанных с безопасностью жизнедеятельности. Так на одном из проектов один заместитель руководителя учил жизни, рассказывая о том, как он сформировал с помощью Википедии 500-страничный технический проект за одну ночь. Расхлебывать результаты таких проектных решений приходится, как правило, совсем другим людям.

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

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

Как мы пользуемся Jira Query Language на практике

13.12.2020 16:23:06 | Автор: admin
Всем привет!

Меня зовут Сергей Раков, я руководитель B2G-направления в компании Ростелеком ИТ. Я хочу рассказать про язык Jira Query Language (JQL): как им пользоваться на практике, основные приемы, с какими проблемами мы сталкивались и как их решали.

imageОригинал картинки взят у deviniti.com/atlassian

Таск-трекеров очень много, каждый подходит для решения одних задач и не очень помогает решать другие. Многими из них мы пользовались, но сейчас остановились на Jira она наш основной инструмент. Лично мне очень нравится ее язык JQL, который сильно упрощает работу и позволяет из коробки иметь мощный и гибкий инструмент для поиска тикетов.

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

Но возникает проблема, если нужно выйти за рамки базовых запросов. Например, если мы хотим найти задачи, которые были на конкретном исполнителе когда-либо, или найти все задачи, исключая один проект. Сделать хитрую выборку для проекта с одним статусом задач и исполнителем и еще одним исполнителем и другим статусом задач силами базового поиска уже сделать нельзя.

На помощь приходит продвинутый поиск. Синтаксис JQL очень похож на SQL. Но в JQL не нужно выбирать конкретные поля, которые будем селектить, указывать таблицы и базы данных, из которых будем выводить. Мы указываем только блок с условиями и работаем с сортировкой все остальное Jira автоматически делает сама.

Все, что нужно знать для работы с JQL это названия полей, по которым будем выбирать тикеты, операторы (=, !=, <, >, in, not in, was, is и т.д.), ключевые слова (AND, OR, NOT, EMPTY, ORDER BY и т.д.) и функции, которые из коробки доступны в продвинутом режиме (Now(), CurrentUser(), IssueHistory(), EndOfDay() и другие).

Поля


Jira при вводе в строку поиска сама выдает подсказки всех возможных значений, которые вы ищете: как по полям, так и по значениям этих полей. Для себя я недавно открыл интересное системное поле lastViewed. Jira хранит историю ваших просмотров тикетов.
image
Здесь представлены два варианта составления фильтров для просмотра последних задач. Первый мой вариант с lastViewed, где Jira выдаст просмотренные мной задачи за последние семь дней, отсортированные по убыванию. Этот фильтр настроен на моем дашборде в виде гаджета, и я к нему часто прибегаю. Потому что тикет закрылся, вкладку и номер не запомнил, быстро открыл, посмотрел, какой был последний тикет.

Есть стандартный фильтр Viewed Recently. Он использует функцию IssueHistory(), сортировка тоже производится по полю lastViewed. Результат одинаковый, но способ, даже в Jira, можно использовать разный. Стоит отметить, что поле LastViewed и IssueHistory() возвращают только вашу историю просмотра историю третьих лиц таким образом посмотреть не получится.

image
По большей части в Jira все операторы стандартные. Мне больше всего нравятся операторы WAS, WAS IN, WAS NOT IN, WAS NOT, CHANGED, потому что они работают с временем. В обычных базах данных такой возможности нет.

image

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

Правда, есть одна оговорка: Jira не хранит историю для текстовых полей: названий тикетов и их описаний. Там нельзя написать: Выведи мне тикеты, в которых поле Summary содержало слово Ростелеком.

Второй пример с оператором CHANGED. Мы хотим получить тикеты, в которых исполнитель был изменен после 1 января 2020 года. Можно использовать другие дополнительные слова, например, BEFORE или знаки >, <, кому как удобнее, и конкретную дату. В этом же примере можно еще сделать отрицание и увидеть, какие тикеты на каких пользователях зависли: assignee not changed AFTER 2020-01-01.

Ключевые слова


image
Основные ключевые слова OR, AND, NOT. Они работают так же, как и логические операторы. Используя OR, мы получим полный набор тикетов из двух проектов A и B. Если нужно сузить выборку, используем AND. Пример нам нужны тикеты из проекта A, по которым исполнителем был юзер B: project = A AND assignee = B. С отрицанием то же самое.

Функции


Согласно документации, в Jira 47 функций, но я никогда не использовал их все. Вот несколько, по моему мнению, основных:

image

now() популярная функция, которая позволяет найти тикеты у которых, например, истек планируемый срок реализации.

currentUser() возвращает текущего пользователя. Jira содержит преднастроенные фильтры, в которых используется эта функция. С currentUser() можно делать универсальные поисковые запросы. Я так делал универсальный дашборд для всей команды разработки: напихал гаджетов на дашборд и в каждом указал вместо конкретного юзера currentUser(). Этот дашборд будет уникальным для каждого залогиненного пользователя, хотя конфигурация будет одинаковая.

unreleasedVersions() это функция, возвращающая тикеты, которые находятся в невыпущенных версиях. Но она не возвращает тикеты, у которых версия не проставлена.

startOfDay() возвращает начало текущего дня. Есть функции для недели, месяца и года. Это же относится и к закрывающей функции endOfDay(). Они позволяют отвязаться от конкретных дат, им можно задавать аргументы: если написать startOfDay(-1), то вернется начало предыдущего дня. Если оставить все как есть, то отобразится начало дня текущего на выходе будет время. Эти функции помогают избежать хардкода, мы очень часто ими пользуемся.

С issueHistory() я уже приводил пример, эта функция возвращает список только ваших просмотров.

linkedIssues() функция, которая позволяет найти тикеты, которые прилинкованы к конкретному тикету.

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

assignee was currentUser()AND fixVersion was inunreleasedVersions()AND created > startOfYear()

Немного синтетический пример, но тем не менее. Это единый запрос, разделенный на три блока. После выполнения первой части запроса мы получим тикеты, на которых я когда-либо был исполнителем или являюсь им в данный момент. Очень важно, что WAS это не только был, но и есть.

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

Третье условие дата создания. Мы фильтруем только те тикеты, которые были созданы с момента начала текущего года.

Функции ScriptRunner


Это плагин, значительно расширяющий возможности Jira. Обычно его используют для автоматизации процессов, но также он добавляет очень много дополнительных функций к JQL. ScriptRunner был нашим самым первым плагином, который мы поставили сразу, как только переехали в Jira в конце 2018 года. Я очень активно просил поставить этот плагин, потому что без него не мог собрать данные по связям с эпиками. Мне, например, часто нужно было вернуть все тикеты эпиков по определенному запросу или все эпики для тикетов из подзапросов. ScriptRunner позволяет все это успешно проделывать.

Чтобы пользоваться функциями ScriptRunner, нужно в JQL добавить дополнительное слово issueFunction in или not in. Далее идет функция, например, epicsOf() она возвращает эпики тикетов, которые удовлетворяют условиям подзапроса. Подзапрос идет на второй строке в скобках, и мы его рассмотрим подробнее.

issueFunction in epicsOf("worklogDate >= startOfWeek(-1) AND worklogDate <= endOfWeek(-1)")AND project in ("Видео.B2G")

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

Сам запрос начинает выполняться со скобок, то есть с подзапроса worklogDate даты списания. Дальше идет уточнение >= startOfWeek(-1) начало недели. Но обратите внимание на цифру -1: она означает, что нам нужен не этот понедельник, а прошлый. А еще worklogDate <= endOfWeek(-1), то есть она меньше окончания прошлой недели. Этот запрос будет выдавать тикеты, не важно какие баги, таски, user story, на которые сотрудники списывали времяс понедельника по воскресенье прошлой недели.

Фишка в том, что функции startOfWeek() и endOfWeek() позволяют отвязаться от даты. Вне зависимости от того, в какой промежуток текущей недели я делаю этот запрос, он отдаст мне один и тот же скоуп эпиков. Как только закончится эта неделя, он вернет эпики по ней. Удивительно, но не все пользуются этой возможностью: недавно изучал открытые запросы, которые публично расшарены, и увидел там много хардкодных дат. И есть подозрение, что эти даты постоянно меняются. Да и что говорить, в начале сам так делал.

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

Следующий запрос эпики со списаниями в этом году, но без контрактов. Этот запрос появился из-за того, что мы используем Jira не только как таск трекер, но и для ведения финансового учета. Есть отдельный проект под контракты, которые мы ведем в виде тикетов, и используем как систему электронного документооборота: статусы постоянно меняются, мы линкуем контракты с эпиками, знаем, сколько у нас людей списалось в какой эпик, знаем, сколько это стоит, и затем по каждому контракту выставляем стоимость работ. Плюс через контракты переносятся трудозатраты в Redmine 2.0. То есть мы списываемся в Jira, а затем автоматические скрипты переносят наши затраты в в Redmine 2.0 по этим контрактам.

Когда эта автоматика заработала, ко мне начали прилетать запросы от коллег вида: есть эпики, трудозатраты которых нельзя перенести в Redmine, потому что там нет контрактов. Рассмотрим запрос подробнее.

issueFunction in epicsOf("worklogDate >= startOfYear()")AND issueFunction not in hasLinkType(Contract)AND project in ("Видео.B2G")


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

Contract в скобках это тип внутренней связи, соединяющей контракты с эпиками. hasLinkType() функция в ScriptRunner, возвращающая тикеты с этим типом связи. Но мне нужны тикеты, которые не содержат этот тип связи, и поэтому использую отрицание not in.

При выполнении первого условия у меня появился скоуп эпиков, актуальных в этом году. Далее отфильтровались эпики без контрактов, и в финале по конкретному проекту Видео.B2G. Таким образом я получил все эпики, с которыми можно работать.

И в конце хочу предложить пройти небольшой тест из трёх вопросов по теме этого поста. Займет 2 минуты. После прохождения увидите свою оценку. Ссылка на опрос: https://docs.google.com/forms/d/e/1FAIpQLSdGrUZZVB62W_1-nC42Aoaz0nO5jUFTK-qIzPDKLX58u5SzCg/viewform?usp=sf_link

Буду рад что-то уточнить или ответить на вопросы в комментариях, если они у вас есть.
Спасибо.
Подробнее..

Перевод Нет Jira нет проблемы

11.04.2021 12:12:58 | Автор: admin

Для тех везунчиков, которые пока не имели дела с Jira (если тут такие есть), сообщаю: Jira это инструмент для управления проектами, и на первый взгляд всё в этой системе выглядит весьма солидно и пристойно.

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


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

Но вот что примечательно: Jira преподносит себя как "рабочий инструмент номер один для гибких команд". Гибких? Хм-мм... Если для управления Jira нужен особый человек или даже целая аутсорсинговая компания, о какой гибкости можно говорить?

Давайте разберёмся, что вообще означает термин "гибкий" (Agile) и почему про него все сегодня говорят?

Последовательная разработка

Сегодня только и разговоров, что про методику Agile, как раньше про методику Waterfall. Впервые каскадная методика Waterfall была описана Уинстоном Ройсом в статье, опубликованной в 1970 году. Хотя термин Waterfall (каскад) не был употреблён в статье ни разу, описание метода напомнило многим каскадную схему:

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

Основная идея методики: любое планирование процессов разработки программного обеспечения должно осуществляться заранее, после чего должны выполняться последовательные шаги по созданию и поставке программного обеспечения. Данная концепция отлично вписывается в старые идеи научных методов управления, заложенные Фредериком Уинслоу Тейлором ещё в 1911 году. Если опустить детали, его идея состоит в следующем: организацию работ нельзя доверять исполнителям, нужна отдельная группа людей группа организаторов процесса, которая разработает последовательность действий, после чего безукоснительное выполнение таких действий поручается исполнителям.

Единственной проблемой при применении такого подхода к разработке программного обеспечения является его малая эффективность как в прошлом, так и сейчас эта методика постоянно даёт сбои.

Встреча в Сноубэрд

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

Это хорошо понимала группа разработчиков, собравшихся на горнолыжном курорте Сноубэрд в США в 2001 году. Они согласились с тем, что при изменении требований процесс разработки пойдет насмарку, а, так как препятствовать изменению требований невозможно, любая используемая методика управления процессом изначально обречена на провал. Так как же быть? Выход подсказал Александр Великий, разрубивший некогда Гордиев узел.

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

Изменение требований на поздних этапах является конкурентным преимуществом

-Мэри Поппендик

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

Основные положения манифеста:

  • Люди и взаимодействие важнее процессов и инструментов.

  • Работающий продукт важнее исчерпывающей документации.

  • Сотрудничество с заказчиком важнее согласования условий контракта.

  • Готовность к изменениям важнее следования первоначальному плану.

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

Что произошло?

Если первым (основным) принципом манифеста является "Люди и взаимодействие важнее процессов и инструментов", то почему все гибкие команды, в которых мне (или вам) приходилось работать, так высоко ценят процессы и инструменты? И тут я опять поминаю недобрым словом Jira. Не дай бог составить задачу вразрез с требованиями Jira, не дай бог добавить хоть одну строку кода без разрешения Jira...

Корень зла, согласно прагматическому замечанию Дэйва Томаса, кроется в том, что слово agile прилагательное, превратилось в Agile (собственное) существительное. Существительные продаются лучше, чем прилагательные, и даже возник "Промышленный комплекс Agile", приторговывающий маркой "Agile".

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

Если идея гибкости возникла в результате признания того факта, что мы не можем предвидеть, как именно могут измениться требования, то единого решения (процесса), которое подошло бы для всех возможных сред, не может быть просто по определению. "Agile-эксперты" навязывают нам определённый процесс, и такое состояние Мартин Фаулер называет неприкрытой пародией на "гибкость".

Как же так, вообще без процесса?

Но нужен же какой-то процесс, разве нет? Нужен, но какой? Да очень простой использовать всё, что работает! Но как узнать, будет ли он работать? Тут следует применить эвристический подход.

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

Инструменты

А что с инструментами? Да то же самое, что и с процессом используйте всё, что работает. Или, если говорить точнее, используйте любой инструмент, который лучше всего подходит для процесса. Но будьте осторожны. Поскольку ваш процесс, скорее всего, изменится, гибкость такого инструмента должна быть достаточно высока, чтобы подстроиться под такие изменения. Также не следует делать ставку на какой-либо конкретный инструмент, ведь рано или поздно придётся переключиться на другой инструмент, лучше подходящий для (изменённого) процесса.

Инструмент, подходящий под это описание и имеющийся в каждом офисе, уже имеется!

Вот этот инструмент лекционная доска, несколько стикеров / каталожных карточек и пара-тройка маркеров. И это всё, что нужно. Инструмент просто отличный, так как каждый хорошо знает, как им пользоваться, и он максимально гибок. Если потребуется цифровой инструмент (для удалённой работы), я бы остановился на более универсальном инструменте достаточно гибком, но обязательно специализированном. Причём вы должны быть уверены, что такой инструмент подходит для вашего процесса.

Что не так с Jira?

Если не вдаваться в детали, Jira не нравится мне тем, что она навязывает пользователю определённый процесс. Но этим дело не ограничивается. Я даже был свидетелем того, как команды разработчиков были вынуждены подстраивать свои процессы под Jira, что является грубым нарушением принципа "Люди и взаимодействие важнее процессов и инструментов".

Неприязнь к Jira у меня накопилась потому, что именно от общения с этим инструментом у меня больше всего разбаливается голова, однако не лучше обстоят дела с другими специализированными инструментами управления программным обеспечением. Если конкретный используемый вами инструмент не подходит (в каком-то смысле) к вашему процессу, как долго вы будете пытаться побороть инструмент, прежде чем плюнуть и настроить процесс под требования инструмента?

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

Между прочим, Atlassian (компания-разработчик Jira) постоянно ищет себе инженеров по различным направлениям, в числе прочих нужны Fullstack-разработчики и Java-разработчики. Если одна из ваших целей релоцироваться в компанию с мировым именем, то приходите учиться, прокачаем ваши скилы и поможем выгодно представить их в резюме.

Узнайте, как прокачаться в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

КакстроитьдиаграммуГанттапоJira-тикетам

04.06.2021 08:06:10 | Автор: admin

Время чтения: 5 минут

Статья для менеджеров, которым необходимо вести управление проектами и ставить сроки в изменчивом мире Agile. Поделюсь опытом использования двух приложений Jira Roadmap и Structure Gantt.

Пример Диаграммы Гантта Пример Диаграммы Гантта

Ганттдля(ленивых) экономящих свое время

Для построения диаграммыГантта существует множество программ: Ganttpro, Monday, Teamgantt,старый добрыйExcelи другие.

Нам с коллегами в Ozonони не подходили,потому чтоежедневная работа завязана наJira-тикеты.Чтобы пользоваться сторонними сервисами, приходилосьпереписывать всю информацию изJiraещёраз (название задачи, исполнитель, связи, статус).Этотребовало много времении терпениянамонотонную механическую работу.

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

  1. JiraRoadmap

  2. StructureGantt

JiraRoadmap

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

Jira RoadmapJira Roadmap

О приложенииStructureвOzonбыло известно давно. Однакоононебросалось в глаза,пока не обратили внимание на еговозможность строитьдиаграммуГантта.Рекламное видео отправило всех в менеджерский рай: информация из Jira-тикетовотражается, можно группировать задачи по статусу, связи подсвечиваются, не мешает команднымKanban-доскам.Минимум монотонной механической работы.

Structureсписоквсех задач с данными изJira-тикетов,распределённыхпо столбикам. Список можно группировать, фильтровать, выводить ту информацию,которая требуется.

StructureGanttк функционалуStructureдобавляется возможность видетьJira-тикетыи связи между задачами на временной ленте.

Structure GanttStructure Gantt

В конце 2020 годаруководители Ozon приобрелиStructureGanttдля удобного и наглядного ведения проектов. Однаков менеджерском раю оказаться сразу не получилась.Причины: сложная функциональностьи отсутствиенаглядногообучающего материала.

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

  • В чате Slack#jira-structureможнобылооперативно получить ответ на вопрос по работе приложение или поделиться своими находками.

  • Ходили друг к другу в настройкиStructure подсмотреть, как ребята в других командах справляются с похожимизадачами.

  • Созванивались и пытались коллективным разумом найтивыход из тупиковых ситуаций.

Слабые стороныStructureGantt

Сильные стороныStructureGantt

Сложно разобраться с инструментом

Богатаяфункциональность

Невозможно увидеть время переходаJira-тикетыиз одного статуса в другой

Вся информация автоматически дублируется междуJira-тикетамииStructureGantt

В мануалах нет примеров использованияна практике

На одном экране помещается большое количество данных

Примеры использованияStructureGantt

Два слова о специфике работы. Я менеджер команды разработки, отвечающей за загрузку товаров на сайтOzonMarketplace.Менеджер проекта,ProductOwnerи культорг в одном лице. Мне нужнокоординироватьпроекты внутри команды и между отделами, планировать спринты и распределять задачи между разработчиками, следить за поддержкой и контролировать выполнение задач к сроку.

У нас в командесемьбэкенд-разработчиков,двафронта,одинаналитик,одинQA итехлид. Держать информацию по всем задачам в головенереально, поэтому важно уметь еёбыстро находить.

Есть несколько режимовStructure Gantt, которые я меняю в зависимости отконтекста, чтобы минимизировать объём работы.

Планирование и мониторинг проектов

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

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

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

Описание статуса проектатолько структура без диаграммыГантта

Использую, когда нужнаконкретная информацияв срезе всехJira-тикетов. Например, необходимо быстро проверить, что даты начала и конца всех проектов совпадают с цифрами вотчёте. В таком случае я сворачиваюГанттив столбиках структуры быстро вижу необходимые цифры. Собиратьинформациюпо временной ленте было бы неудобно.

Планирование спринта

Группируютикетыпо исполнителю, чтобы видеть занятость конкретного разработчика в следующий спринти прогноз, когдаразработчик должен освободиться. Подобное представление задач на диаграммея не рекомендуюпоказывать разработчикам, есливы используетеKanban:я считаю, чтоинженерамследуетфокусироватьсяна задачахв работеи не отвлекаться на другие.ДиаграммаГантта всё- такиинструментдляспецифическихменеджерскихзадач.

Мои любимыефичиStructureGantt

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

Связи между задачами

История декомпозирована,Jira-тикетына задачи заведены. На следующем этапе при растягиванииколбасокповременной ленте я расставляю связи междутикетами. Делаю так,чтобычётковыделить,какая задача заблокирована иликакиезадачи должны быть закончены одновременно (классические зависимостив управлении проектами:finishtostart,finishtofinish).

Цвета

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

Переход между режимами

В примерах использованияStructureGanttя говорила, что переключаюсь между режимами в зависимости от занятия. Помогает мне в этомкнопка, удобно расположеннаяв центре экрана. Переключение не занимает много времени, поэтому я часто им пользуюсь.

Выбор за вами

Нам с коллегами Structure Gantt позволяет собирать всю нужную информацию из Jira в одном месте. Получается больше порядка и контроля над проектами.

При этом у Structure Gantt есть свои слабые стороны. Буду рада, если продакты ALM Works (создатели Structure) обратят внимание на них и сделают программу более простой и понятной в освоении.

Во время подготовки статьи я обнаружила, что функциональность Jira Roadmap заметно изменилась c лета прошлого года. Набор возможностей стал похож на то, что предлагает Structure Gantt.

Если выбираете приложение к Jira для ведения проектов и создания диаграмм Гантта, попробуйте оба варианта. Главное старайтесь оптимизировать затяжную механическуюработу.У насменеджеров есть много других важных задач, помимо рутины!:)

Ссылки

  1. Описание функционала на сайте Atlassian JiraRoadmap и StructureGantt

  2. Рекламное видео "What is Structure.Gantt?"

Подробнее..

ZERG что за зверь?

19.02.2021 14:12:20 | Автор: admin


Когда мы говорим о CI&CD, мы часто углубляемся в базовые инструменты автоматизации сборки, тестирования и доставки приложения фокусируемся на инструментах, но забываем осветить процессы, которые протекают во время отрезания и стабилизации релизов. Однако, не все готовые инструменты одинаково полезны, а какие-то кастомные процессы не укладываются в их покрытие. Приходится исследовать процессы и находить пути автоматизации для их оптимизации.

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

У нас есть ночные прогоны, когда гоняются полные наборы тестов. Но на самой заре освоения Zephyr, нашим тестировщикам во время регресса приходилось скачивать xcresult, или ещё ранее plist, или junit xml, а затем проставлять соответствия зелёных и красных тестов в зефире руками. Это довольно рутинная операция, да и занимает она много времени, чтобы руками пройти 500-600 тестов. Такие вещи хочется отдать на откуп бездушной машине. Так родился ZERG.


Рождение зерга


Zephyr Enterprise Report Generator небольшая утилита, которая изначально умела только искать соответствия в отчёте тестов и отправлять в Zephyr их актуальные статусы. Позже утилита получила новые функции, но сегодня мы остановимся на поиске и отправке отчётов.
В Zephyr нам предлагается оперировать версиями, циклами и проходами (execution) тест кейсов. Каждая версия содержит произвольное количество циклов, а каждый цикл содержит в себе проходы кейсов. Такие проходы содержат в себе информацию о задаче (zephyr прекрасно интегрируется с jira и тест кейс это, по сути, задачка в jira), авторе, о статусе кейса, а также о том, кто занимается этим кейсом и о других необходимых деталях.
Для автоматизации проблемы, которую мы обозначили выше, нам важно разобраться в проставлении статуса кейса.

Работа с кодом


Но как соотнести тест в коде и тест в зефире? Здесь мы выбрали довольно простой и прямолинейный подход: для каждого теста мы добавляем в секцию комментариев ссылки на задачи в jira.


В комментариях также могут размещаться дополнительные параметры, но об этом позже.
Так, один тест в коде может покрывать несколько задач. Но работает и обратная логика. Для одной задачи может быть написано несколько тестов в коде. Их статусы будут учитываться при составлении отчёта.
Нам надо пройти по исходникам, извлечь все тест-классы и тесты, слинковать задачи с методами и соотнести это с отчётом о прохождении тестов ( xcresult или junit ).
Работать с самим кодом можно разными путями:
просто читать файлы и через регулярные выражения извлекать информацию
использовать SourceKit

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



Нам надо получить тесты. Для этого опишем структуры:



Затем нам надо прочитать отчёт о прохождении тестов. ZERG был рождён ещё до переезда на xcresult, и поэтому умеет парсить plist и junit. Детали в этой статье нас всё ещё не интересуют, они будут приложены в коде. Поэтому отгородимся протоколам



Остается только слинковать тесты в коде с результатами тестов из отчетов.



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

Работаем с зефиром


Теперь, когда мы прочитали отчёты о тестировании, нам надо их перевести в контекст zephyr. Для этого надо получить список версий проекта, соотнести с версией приложения (чтобы это так работало, необходимо, чтобы версия в зефире совпадала с версией в Info.plist вашего приложения, например, 2.56), выкачать циклы и проходы. А дальше соотнести проходы с нашими уже имеющимися отчётами.
Для этого нам надо реализовать в ZephyrAPI следующие методы:



Cпецификацию можно увидеть здесь: getzephyr.docs.apiary.io, а реализацию клиента в нашем репозитории.
Общий алгоритм довольно простой:



На этапе сопоставления проходов с отчётами есть тонкий момент, который необходимо учитывать: в zephyr api обновление execution отправлять удобнее всего пачками, где передаётся общий статус и список идентификаторов проходов. Нам нужно развернуть наши отчёты относительно тикетов и учесть n-m соотношение. Для одного кейса в зефире может быть несколько тестов в коде. Один тест в коде может покрывать несколько кейсов. Если для одного кейса есть n тестов в коде и один из них красный, то для такого кейса общий статус красный, однако если один из таких тестов покрывает m кейсов и он зелёный, то остальные кейсы не должны стать красными.
Поэтому мы оперируем сетами и ищем пересечение красных и зелёных. Всё, что попадает в пересечение, мы отнимаем из зелёных результатов и отправляем отредактированные сведения в zephyr.



Здесь ещё нужно отметить, что внутри команды мы договорились, что zerg не будет менять статус прохода, если:
1. Текущий статус blocked или failed (раньше для failed мы меняли статус, но сейчас отказались от практики, потому что хотим, чтобы тестировщики обращали внимание на красные автотесты во время регресса).
2. Если текущий статус pass и его поставил человек, а не zerg.
3. Если тест помечен как флакающий.

Интересности Zephyr API


При запросе циклов нам приходит json, который с первого взгляда невозможно систематизировать для десериализации. Всё дело в том, что запрос на получение циклов для версии, хотя по смыслу и должен возвращать массив циклов, на самом деле возвращает один объект, где каждое поле уникально и называется идентификатором цикла, который лежит в значении. Чтобы такое обработать, мы применяем несложные хаки:



Статусы прохождения тестов приходят в одном из запросов рядом с объектом запроса. Но их можно вынести заранее в enum:



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



Вместо заключения


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

Kanboard бесплатный инструмент для отслеживания задач с поддержкой Kanban

17.03.2021 22:16:55 | Автор: admin

Kanboard - это бесплатный аналог более продвинутых коммерческих систем отслеживания задач, таких как Jira или Trello.

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

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

Установка

Kanboard написан на PHP и работает на разных платформах, а также поддерживает несколько вариантов БД. У нас использован Apache + PHP + PostgreSQL на сервере Ubuntu.

Готового облачного сервиса на базе Kanboard нет (на момент написания статьи), так что Вам потребуется собственный сервер (например, любой VPS).

Для установки нужно скопировать Kanboard в папку web server, создать БД и прописать коннект к базе в php-файлике конфигурации. (Все достаточно понятно описано на сайте продукта в разделе с документацией для каждой платформы: https://kanboard.org/).

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

Kanban

Конечно, самой главной функций Kanboard является возможность визуализировать задачи на Kanban-доске.

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

Визуализация задач на Kanban-доскеВизуализация задач на Kanban-доске

В Kanboard есть свернутый и развернутый варианты представления задач на доске. Свернутый вариант позволяет получить обзор большого количества задач на одном экране. Развернутый вид - представляет каждую задачу в виде более детальной карточки.

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

Также есть возможность настроить свой запрос для фильтра. Например, "status:open tag:BI" покажет все открытые задачи с меткой "BI".

Задачи перетаскиваются мышкой, но можно изменить расположение задачи и через меню.

Карточка задачи

Сама карточка задачи довольно аскетична и содержит минимум необходимых полей. Но, по нашей практике, этих полей оказалось достаточно. (При необходимости, есть плагин для добавления своих мета-полей.)

  • Метки

Поле "Метки" позволяет вести несколько значений. В отличии от Labels в Jira, этот список нужно заранее определить в настройках проекта. На мой взгляд, так даже лучше, т.к. не создает "помойку" из разных меток.

  • Поле заказчик

Пришлось прибегнуть к небольшой, но важной хитрости. Поля "Заказчик" в системе нет и разработчики почему-то не хотят его добавлять (судя по обсуждению на их github). Решение было найдено следующее: Устанавливаем плагин, который делает редактируемым поле Creator и дальше просто меняем название к коде PHP на "Заказчик". Полем Creator, как таковым, пришлось пожертвовать. Зато заказчику приходят все уведомления при изменении задачи.

Карточка задачиКарточка задачи

Создание проектов

Можно создать много проектов, причем при создании есть возможность скопировать настройки из уже имеющегося проекта.

Для проекта определяем менеджеров и участников. Т.е. доступ пользователей в этой системе регулируется на уровне проектов.

Проект имеет довольно много настроек:

  • Набор колонок и дорожек - В методе kanban задача движется слева направо по вертикальным колонкам. Вы можете сами определить название этих колонок в зависимости от Вашего процесса. Горизонтальные дорожки можно использовать, например, для расположения в верхней дорожке задачи высокого приоритета.

  • Категории и метки - возможность классифицировать задачи. Например Категории можно использовать для типизации задач, а метками обозначать системы или тематики, к которым они относятся.

  • Автоматические действия. - Можно настроить разную дополнительную логику системы. Например, автоматически проставить дату начала при перемещении задачи из колонки Backlog.

  • Пользовательские фильтры - возможность задать фильтр задач и сохранить его под определенным именем. (Язык фильтра, конечно сильно упрощен по сравнению с JQL в Jira).

Разные полезные функции

  • Импорт задач - Можно при запуске системы импортировать задачи из CSV файла.

  • Приложения - Можно прикладывать файлы или картинки к задачам.

  • Подзадачи - У задачи можно создавать подзадачи. Причем, система умеет показывать/скрывать подзадачи в общем списке задач в виде второго уровня иерархии.

  • Комментарии - есть возможность переписываться с другими пользователями по задаче в виде комментариев.

  • Мультиязычность - интерфейс системы переведен на разные языки, в т.ч. на русский.

  • Аналитика - Есть возможность просмотреть среднее время в каждой колонке, время цикла, burn-down и другие отчеты типовые отчеты. Но, на мой взгляд, аналитика (как и в Jira) тут сыроватая и проще будет взять данные запросом из БД и построить отчет самостоятельно.

  • Функция "пригласить пользователей" - Если Ваши участники еще не зарегистрированы в системе, то есть возможность пригласить пользователей, указав один или несколько мейлов и проект, в который вы хотите пригласить участников. Пользователь получит уведомление со ссылкой на регистрацию.

  • Есть понятие "закрытия" для задачи или проекта. Например, задача может висеть в колонке Done до конца спринта и дальше можно просмотреть и массово закрыть все, что в Done при планировании следующего спринта.

Эргономика и дизайн

Дизайн Kanboard многим показался не слишком эстетичным, хотя вопрос конечно субъективный. Имеющиеся в плагинах темы принципиально ситуацию с дизайном не улучшили.

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

При просмотре Kanban лучше выбрать "Компактный вид", т.к. в нем нет горизонтальной прокрутки.

Стабильность работы

Система работает стабильно, ошибок, падений и прочих неприятностей не обнаружили.

Быстродействие системы очень хорошее и это важно. Она не тупит при построении Kanban или редактировании задач (на Ubuntu почему-то заметно быстрее, чем на Windows Server).

Чего в ней нет

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

  • Список задач жестко зафиксирован и его вид не настраивается. Возможно только использование тех же фильтров, что и на Kanban-доске. Если нужен список в своем формате, то проблема решается только экспортом в CSV или подключением к БД.

Думаю, эта система подойдет многим, несмотря на явное стремление разработчиков к минимализму.

Свою задачу она вполне решает и позволяет работать, используя метод Kanban.

Подробнее..
Категории: Agile , Kanban , Jira

Ваш безлимит как увеличить пропускную способность автомерджа

21.06.2021 14:12:41 | Автор: admin

Отыщи всему начало, и ты многое поймёшь (Козьма Прутков).

Меня зовут Руслан, я релиз-инженер в Badoo и Bumble. Недавно я столкнулся с необходимостью оптимизировать механизм автомерджа в мобильных проектах. Задача оказалась интересной, поэтому я решил поделиться её решением с вами. В статье я расскажу, как у нас раньше было реализовано автоматическое слияние веток Git и как потом мы увеличили пропускную способность автомерджа и сохранили надёжность процессов на прежнем высоком уровне.

Свой автомердж

Многие программисты ежедневно запускают git merge, разрешают конфликты и проверяют свои действия тестами. Кто-то автоматизирует сборки, чтобы они запускались автоматически на отдельном сервере. Но решать, какие ветки сливать, всё равно приходится человеку. Кто-то идёт дальше и добавляет автоматическое слияние изменений, получая систему непрерывной интеграции (Continuous Integration, или CI).

Например, GitHub предлагает полуручной режим, при котором пользователь с правом делать записи в репозиторий может поставить флажок Allow auto-merge (Разрешить автомердж). При соблюдении условий, заданных в настройках, ветка будет соединена с целевой веткой. Bitbucket поддерживает большую степень автоматизации, накладывая при этом существенные ограничения на модель ветвления, имена веток и на количество мерджей.

Такой автоматизации может быть достаточно для небольших проектов. Но с увеличением количества разработчиков и веток, ограничения, накладываемые сервисами, могут существенно повлиять на производительность CI. Например, раньше у нас была система мерджа, при которой основная ветка всегда находилась в стабильном состоянии благодаря последовательной стратегии слияний. Обязательным условием слияния была успешная сборка при наличии всех коммитов основной ветки в ветке разработчика. Работает эта стратегия надёжно, но у неё есть предел, определяемый временем сборки. И этого предела оказалось недостаточно. При времени сборки в 30 минут на обработку 100 слияний в день потребовалось бы более двух суток. Чтобы исключить ограничения подобного рода и получить максимальную свободу выбора стратегий мерджа и моделей ветвления, мы создали собственный автомердж.

Итак, у нас есть свой автомердж, который мы адаптируем под нужды каждой команды. Давайте рассмотрим реализацию одной из наиболее интересных схем, которую используют наши команды Android и iOS.

Термины

Main. Так я буду ссылаться на основную ветку репозитория Git. И коротко, и безопасно. =)

Сборка. Под этим будем иметь в виду сборку в TeamCity, ассоциированную с веткой Git и тикетом в трекере Jira. В ней выполняются как минимум статический анализ, компиляция и тестирование. Удачная сборка на последней ревизии ветки в сочетании со статусом тикета To Merge это однo из необходимых условий автомерджа.

Пример модели ветвления

Испробовав разные модели ветвления в мобильных проектах, мы пришли к следующему упрощённому варианту:

На основе ветки main разработчик создаёт ветку с названием, включающим идентификатор тикета в трекере, например PRJ-k. По завершении работы над тикетом разработчик переводит его в статус Resolved. При помощи хуков, встроенных в трекер, мы запускаем для ветки тикета сборку. В определённый момент, когда изменения прошли ревью и необходимые проверки автотестами на разных уровнях, тикет получает статус To Merge, его забирает автоматика и отправляет в main.

Раз в неделю на основе main мы создаём ветку релиза release_x.y.z, запускаем на ней финальные сборки, при необходимости исправляем ошибки и наконец выкладываем результат сборки релиза в App Store или Google Play. Все фазы веток отражаются в статусах и дополнительных полях тикетов Jira. В общении с Jira помогает наш клиент REST API.

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

Первая версия: жадная стратегия

Сначала мы шли от простого и очевидного. Брали все тикеты, находящиеся в статусе To Merge, выбирали из них те, для которых есть успешные сборки, и отправляли их в main командой git merge, по одной.

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

Наличие в TeamCity актуальной успешной сборки мы проверяли при помощи метода REST API getAllBuilds примерно следующим образом (псевдокод):

haveFailed = False # Есть ли неудачные сборкиhaveActive = False # Есть ли активные сборки# Получаем сборки типа buildType для коммита commit ветки branchbuilds = teamCity.getAllBuilds(buildType, branch, commit)# Проверяем каждую сборкуfor build in builds:  # Проверяем каждую ревизию в сборке  for revision in build.revisions:    if revision.branch is branch and revision.commit is commit:      # Сборка актуальна      if build.isSuccessful:        # Сборка актуальна и успешна        return True      else if build.isRunning or build.isQueued        haveActive = True      else if build.isFailed:        haveFailed = Trueif haveFailed:  # Исключаем тикет из очереди, переоткрывая его  ticket = Jira.getTicket(branch.ticketKey)  ticket.reopen("Build Failed")  return Falseif not haveActiveBuilds:  # Нет ни активных, ни упавших, ни удачных сборок. Запускаем новую  TriggerBuild(buildType, branch)

Ревизии это коммиты, на основе которых TeamCity выполняет сборку. Они отображаются в виде 16-ричных последовательностей на вкладке Changes (Изменения) страницы сборки в веб-интерфейсе TeamCity. Благодаря ревизиям мы можем легко определить, требуется ли пересборка ветки тикета или тикет готов к слиянию.

Важно, что ревизию можно (а часто даже необходимо) указывать в запросе на добавление новой сборки в очередь в параметре lastChanges, потому что в противном случае TeamCity может выбрать устаревшую ревизию ветки при запуске сборки. Как будет показано ниже, указывать ревизию необходимо в тех случаях, если, например, логика вне TeamCity основана на поиске сборок на конкретных коммитах (наш случай).

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

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

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

Конфликты слияния

Если изменить одну и ту же строку кода в разных ветках и попытаться соединить их в main, то Git попросит разрешить конфликты слияния. Из двух вариантов нужно выбрать один и закоммитить изменения.

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

Если команда git merge завершилась с ошибкой и для всех файлов в списке git ls-files --unmerged заданы обработчики конфликтов, то для каждого такого файла мы выполняем парсинг содержимого по маркерам конфликтов <<<<<<<, ======= и >>>>>>>. Если конфликты вызваны только изменением версии приложения, то, например, выбираем последнюю версию между локальной и удалённой частями конфликта.

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

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

Логические конфликты

А может ли случиться так, что, несмотря на успешность сборок пары веток в отдельности, после слияния их с main сборка на основной ветке упадёт? Практика показывает, что может. Например, если сумма a и b в каждой из двух веток не превышает 5, то это не гарантирует того, что совокупные изменения a и b в этих ветках не приведут к большей сумме.

Попробуем воспроизвести это на примере Bash-скрипта test.sh:

#!/bin/bashget_a() {    printf '%d\n' 1}get_b() {    printf '%d\n' 2}check_limit() {    local -i value="$1"    local -i limit="$2"    if (( value > limit )); then        printf >&2 '%d > %d%s\n' "$value" "$limit"        exit 1    fi}limit=5a=$(get_a)b=$(get_b)sum=$(( a + b ))check_limit "$a" "$limit"check_limit "$b" "$limit"check_limit "$sum" "$limit"printf 'OK\n'

Закоммитим его и создадим пару веток: a и b.
Пусть в первой ветке функция get_a() вернёт 3, а во второй get_b() вернёт 4:

diff --git a/test.sh b/test.shindex f118d07..39d3b53 100644--- a/test.sh+++ b/test.sh@@ -1,7 +1,7 @@ #!/bin/bash get_a() {-    printf '%d\n' 1+    printf '%d\n' 3 } get_b() {git diff main bdiff --git a/test.sh b/test.shindex f118d07..0bd80bb 100644--- a/test.sh+++ b/test.sh@@ -5,7 +5,7 @@ get_a() { }  get_b() {-    printf '%d\n' 2+    printf '%d\n' 4 }  check_limit() {

В обоих случаях сумма не превышает 5 и наш тест проходит успешно:

git checkout a && bash test.shSwitched to branch 'a'OKgit checkout b && bash test.shSwitched to branch 'b'OK

Но после слияния main с ветками тесты перестают проходить, несмотря на отсутствие явных конфликтов:

git merge a bFast-forwarding to: aTrying simple merge with bSimple merge did not work, trying automatic merge.Auto-merging test.shMerge made by the 'octopus' strategy. test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)bash test.sh7 > 5

Было бы проще, если бы вместо get_a() и get_b() использовались присваивания: a=1; b=2, заметит внимательный читатель и будет прав. Да, так было бы проще. Но, вероятно, именно поэтому встроенный алгоритм автомерджа Git успешно обнаружил бы конфликтную ситуацию (что не позволило бы продемонстрировать проблему логического конфликта):

git merge a Updating 4d4f90e..8b55df0Fast-forward test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)git merge b Auto-merging test.shCONFLICT (content): Merge conflict in test.shRecorded preimage for 'test.sh'Automatic merge failed; fix conflicts and then commit the result.

Разумеется, на практике конфликты бывают менее явными. Например, разные ветки могут полагаться на API разных версий какой-нибудь библиотеки зависимости, притом что более новая версия не поддерживает обратной совместимости. Без глубоких знаний кодовой базы (читай: без разработчиков проекта) обойтись вряд ли получится. Но ведь CI как раз и нужен для решения таких проблем.

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

Превентивные меры

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

Нужно синхронизировать ветки так, чтобы их совокупный вклад в main не приводил к падению сборки релиза. Ясно, что все готовые к слиянию ветки нужно так или иначе объединить и прогнать тесты по результату объединения. Путей решения много, давайте посмотрим, каким был наш путь.

Вторая версия: последовательная стратегия

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

Git, по идее, как раз и является средством синхронизации. Но порядок попадания веток в main и, наоборот, main в ветки определяем мы сами. Чтобы определить точно, какие из веток вызывают проблемы в main, можно попробовать отправлять их туда по одной. Тогда можно выстроить их в очередь, а порядок организовать на основе времени попадания тикета в статус To Merge в стиле первый пришёл первым обслужен.

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

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

Но есть у этой схемы существенный недостаток: пропускная способность автомерджа линейно зависит от времени сборки. При среднем времени сборки iOS-приложения в 25 минут мы можем рассчитывать на прохождение максимум 57 тикетов в сутки. В случае же с Android-приложением требуется примерно 45 минут, что ограничивает автомердж 32 тикетами в сутки, а это даже меньше количества Android-разработчиков в нашей компании.

На практике время ожидания тикета в статусе To Merge составляло в среднем 2 часа 40 минут со всплесками, доходящими до 10 часов! Необходимость оптимизации стала очевидной. Нужно было увеличить скорость слияний, сохранив при этом стабильность последовательной стратегии.

Финальная версия: сочетание последовательной и жадной стратегий

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

Давайте вспомним идею жадной стратегии: мы сливали все ветки готовых тикетов в main. Основной проблемой было отсутствие синхронизации между ветками. Решив её, мы получим быстрый и надёжный автомердж!

Раз нужно оценить общий вклад всех тикетов в статусе To Merge в main, то почему бы не слить все ветки в некоторую промежуточную ветку Main Candidate (MC) и не запустить сборку на ней? Если сборка окажется успешной, то можно смело сливать MC в main. В противном случае придётся исключать часть тикетов из MC и запускать сборку заново.

Как понять, какие тикеты исключить? Допустим, у нас n тикетов. На практике причиной падения сборки чаще всего является один тикет. Где он находится, мы не знаем все позиции от 1 до n являются равноценными. Поэтому для поиска проблемного тикета мы делим n пополам.

Так как место тикета в очереди определяется временем его попадания в статус To Merge, имеет смысл брать ту половину, в которой расположены тикеты с большим временем ожидания.

Следуя этому алгоритму, для k проблемных тикетов в худшем случае нам придётся выполнить O(k*log2(n)) сборок, прежде чем мы обработаем все проблемные тикеты и получим удачную сборку на оставшихся.

Вероятность благоприятного исхода велика. А ещё в то время, пока сборки на ветке MC падают, мы можем продолжать работу при помощи последовательного алгоритма!

Итак, у нас есть две автономные модели автомерджа: последовательная (назовём её Sequential Merge, или SM) и жадная (назовём её Greedy Merge, или GM). Чтобы получить пользу от обеих, нужно дать им возможность работать параллельно. А параллельные процессы требуют синхронизации, которой можно добиться либо средствами межпроцессного взаимодействия, либо неблокирующей синхронизацией, либо сочетанием этих двух методов. Во всяком случае, мне другие методы неизвестны.

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

Остаётся предотвратить все возможные случаи состояний гонки. Их много, но для понимания сути приведу несколько самых важных:

  1. SM-SM и GM-GM: между командами одного типа.

  2. SM-GM: между SM и GM в рамках одного репозитория.

Первая проблема легко решается при помощи мьютекса по токену, включающему в себя имя команды и название репозитория. Пример: lock_${command}_${repository}.

Поясню, в чём заключается сложность второго случая. Если SM и GM будут действовать несогласованно, то может случиться так, что SM соединит main с первым тикетом из очереди, а GM этого тикета не заметит, то есть соберёт все остальные тикеты без учёта первого. Например, если SM переведёт тикет в статус In Master, а GM будет всегда выбирать тикеты по статусу To Merge, то GM может никогда не обработать тикета, соединённого SM. При этом тот самый первый тикет может конфликтовать как минимум с одним из других.

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

Таким образом, мы получили своего рода неблокирующую синхронизацию.

Немного о TeamCity

В процессе реализации GM нам предстояло обработать много нюансов, которыми я не хочу перегружать статью. Но один из них заслуживает внимания. В ходе разработки я столкнулся с проблемой зацикливания команды GM: процесс постоянно пересобирал ветку MC и создавал новую сборку в TeamCity. Проблема оказалась в том, что TeamCity не успел скачать обновления репозитория, в которых была ветка MC, созданная процессом GM несколько секунд назад. К слову, интервал обновления репозитория в TeamCity у нас составляет примерно 30 секунд.

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

Кто-то посчитает решение очевидным, но я нашёл его не сразу. Оказывается, прикрепить ревизию к сборке при её добавлении в очередь можно при помощи параметра lastChanges метода addBuildToQueue:

<lastChanges>  <change    locator="version:{{revision}},buildType:(id:{{build_type}})"/></lastChanges>

В этом примере {{revision}} заменяется на 16-ричную последовательность коммита, а {{build_type}} на идентификатор конфигурации сборки. Но этого недостаточно, так как TeamCity, не имея информации о новом коммите, может отказать нам в запросе.

Для того чтобы новый коммит дошёл до TeamCity, нужно либо подождать примерно столько, сколько указано в настройках конфигурации корня VCS, либо попросить TeamCity проверить наличие изменений в репозитории (Pending Changes) при помощи метода requestPendingChangesCheck, а затем подождать, пока TeamCity скачает изменения, содержащие наш коммит. Проверка такого рода выполняется посредством метода getChange, где в changeLocator нужно передать как минимум сам коммит в качестве параметра локатора version. Кстати, на момент написания статьи (и кода) на странице ChangeLocator в официальной документации описание параметра version отсутствовало. Быть может, поэтому я не сразу узнал о его существовании и о том, что это 40-символьный 16-ричный хеш коммита.

Псевдокод:

teamCity.requestPendingChanges(buildType)attempt = 1while attempt <= 20:  response = teamCity.getChange(commit, buildType)  if response.commit == commit:    return True # Дождались  sleep(10)return False

О предельно высокой скорости слияний

У жадной стратегии есть недостаток на поиск ветки с ошибкой может потребоваться много времени. Например, 6 сборок для 20 тикетов у нас может занять около трёх часов. Можно ли устранить этот недостаток?

Допустим, в очереди находится 10 тикетов, среди которых только 6-й приводит к падению сборки.

Согласно жадной стратегии, мы пробуем собрать сразу все 10 тикетов, что приводит к падению сборки. Далее собираем левую половину (с 1 по 5) успешно, так как тикет с ошибкой остался в правой половине.

Если бы мы сразу запустили сборку на левой половине очереди, то не потеряли бы времени. А если бы проблемным оказался не 6-й тикет, а 4-й, то было бы выгодно запустить сборку на четверти длины всей очереди, то есть на тикетах с 1 по 3, например.

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

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

Примерно такой же алгоритм реализован в премиум-функции GitLab под названием Merge Trains. Перевода этого названия на русский язык я не нашёл, поэтому назову его Поезда слияний. Поезд представляет собой очередь запросов на слияние с основной веткой (merge requests). Для каждого такого запроса выполняется слияние изменений ветки самого запроса с изменениями всех запросов, расположенных перед ним (то есть запросов, добавленных в поезд ранее). Например, для трёх запросов на слияние A, B и С GitLab создаёт следующие сборки:

  1. Изменения из А, соединённые с основной веткой.

  2. Изменения из A и B, соединённые с основной веткой.

  3. Изменения из A, B и C, соединённые с основной веткой.

Если сборка падает, то соответствующий запрос из очереди удаляется, а сборки всех предыдущих запросов перезапускаются (без учёта удалённого запроса).

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

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

Но если преград человеческой мысли нет, то пределы аппаратных ресурсов видны достаточно отчётливо:

  1. Каждой сборке нужен свой агент в TeamCity.

  2. В нашем случае у сборки мобильного приложения есть порядка 15-100 сборок-зависимостей, каждой из которых нужно выделить по агенту.

  3. Сборки автомерджа мобильных приложений в main составляют лишь малую часть от общего количества сборок в TeamCity.

Взвесив все плюсы и минусы, мы решили пока остановиться на алгоритме SM + GM. При текущей скорости роста очереди тикетов алгоритм показывает хорошие результаты. Если в будущем заметим возможные проблемы с пропускной способностью, то, вероятно, пойдём в сторону Merge Trains и добавим пару параллельных сборок GM:

  1. Вся очередь.

  2. Левая половина очереди.

  3. Левая четверть очереди.

Что в итоге получилось

В результате применения комбинированной стратегии автомерджа нам удалось добиться следующего:

  • уменьшение среднего размера очереди в 2-3 раза;

  • уменьшение среднего времени ожидания в 4-5 раз;

  • мердж порядка 50 веток в день в каждом из упомянутых проектов;

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

Примеры графиков слияний за несколько дней:

Количество тикетов в очереди до и после внедрения нового алгоритма:

Среднее количество тикетов в очереди (AVG) уменьшилось в 2,5 раза (3,95/1,55).

Время ожидания тикетов в минутах:

Среднее время ожидания (AVG) уменьшилось в 4,4 раза (155,5/35,07).

Подробнее..

Боль разработчика Никогда не давайте пользователям бесплатный тариф

15.03.2021 12:08:42 | Автор: admin


Если вы запускаете какой-то сервис в интернете, всегда есть соблазн предложить бесплатный тариф, чтобы завлечь публику.

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

И будет требовать от вас надёжного сервиса, новых функций и предъявлять претензии. Чем меньше платит пользователь тем больше шуму он поднимает в социальных сетях и тем больше поддержки требует. Отрицательные отзывы идут именно от бесплатных юзеров, а не от платных (это вполне логично, если подумать).

Британский разработчик Гвидо Зюйдхоф (Guido Zuidhof) настолько устал от таких пользователей, что запустил специальный сайт No Free Plan, на котором излил всю свою боль по этому поводу.

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

Цена бесплатного плана


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

Но в реальности у каждого бесплатного плана есть конкретная цена. Она измеряется в вашем времени и усилиях.

Мы уже упомянули, что люди на самых дешёвых тарифах самые назойливые. Как думаете, от кого придёт больше запросов в службу поддержки: от десяти крупных корпоративных клиентов с подпиской за $100 в месяц или от тысячи пользователей, каждый из которых сидит на тарифе за $1 (включая школьников, студентов)? Очевидно, что в первой группе более высококвалифицированные специалисты и профессиональные IT-департаменты, которые задают меньше глупых вопросов.

Хотя по деньгам это абсолютно одинаковая сумма, но во втором случае седина покроет ваши виски гораздо быстрее, уверен Гвидо Зюйдхоф.

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

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

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

В итоге бесплатные тарифы слишком дорого обходятся.

Ничего бесплатного не бывает


Понятно, откуда идёт заблуждение об эффективности бесплатных планов. Мы видим, что крупнейшие интернет-компании Google и Facebook не берут никакой платы за основной набор услуг. Хотя у Google есть много платных сервисов, но для широкой публики всё основное бесплатно. И на Google Drive, и на Gmail есть бесплатный лимит, который устраивает почти всех.

И стартап YouTube тоже никогда не брал платы за просмотр видеороликов.

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


Сервис слежки за сотрудниками Hubstaff почти обанкротился с таким бесплатным тарифом

Прежде чем предлагать бесплатный сервис налево и направо, наращивая пользовательскую базу в геометрической прогрессии, нужно продумать бизнес-модель. Это проблема не только SaaS, но и онлайновых СМИ, которые хотят сохранить бесплатную подписку. Например, несколько лет назад закрылся Gigaom популярный и качественный сайт с техническими новостями и аналитикой. Один из лучших представителей IT-журналистики не смог выжить по модели фримиум.

Какие альтернативы?


Пробный период


Отлично работает пробная подписка. Особенно как в варианте Netflix когда одновременно с бесплатным пробным периодом заключается договор на дальнейшее платное обслуживание, так что через 30 дней счёт выставляется автоматически. Теоретически, пользователь имеет право в любой момент отменить подписку, хотя на практике очень многие забывают это сделать или ленятся это не совсем честно, но законно во многих странах. Ну а большинство действительно довольны платным сервисом Netflix и привыкают к комфорту.

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

Пробный период эффективен даже без тёмных паттернов. Лимит можно выставить по времени (30 суток) или по объёму услуг (в гигабайтах трафика, минутах просмотра и т. д.).

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

Фильтрация пользователей


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

Вы выбираете действительно достойных, кто вам нравится.

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

Здесь нет никакого снобизма, разработчик сервиса имеет полное право на такую избирательность, какую захочет.

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

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

Единовременный платёж


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

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

Это не полноценная подписка на сервис, а некий промежуточный вариант между вечным пробным периодом и нормальной платной подпиской. По аналогии с фримиум (freemium) его можно назвать чипиум (cheapium).

Важно точно обговорить условия такой подписки. Очевидно, что в наше время никто не может гарантировать вечный сервис. Поэтому нужно установить минимальный срок работы сервиса (хотя бы 1-6 месяцев), а если тот закроется раньше, то деньги будут возвращены. Рекомендуется указать возможность закрытия аккаунта в случае неактивности (в течение полугода или больше), а также различные льготы подписчикам.

Автор концепции No Free Plan говорит, что на создание сайта его побудило чтение многочисленных дискуссий в сообществе Indie Hackers, где общаются основатели мелких онлайн-компаний и независимых бизнесов. Обычно это разработчики-одиночки, которые запускают платный сервис, SaaS, утилиту, игру или мобильное приложение или несколько таких сервисов, зарабатывая доход в качестве индивидуального предпринимателя.

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

Проблема опенсорсных мейнтейнеров


Эта проблема отлична известна в сообществе Open Source. Мейнтейнеры опенсорсных проектов работают бесплатно и быстро выгорают на этой работе, сталкиваясь с массой претензий от недовольных пользователей.

Не каждый выдерживает такое давление. Некоторые психуют и просто удаляют свои репозитории, как это сделал хабраюзер fafhrd91, автор веб-сервера Actix Web. После критики его профессиональных навыков автор отказался от дальнейшей поддержки проекта (репозиторий всё-таки восстановили и передали другому мейнтейнеру).

От работы больше никакой радости. Возможно, вы захотите уйти, но не сможете из-за чувства ответственности за свой код, сообщество и людей, которые используют ваше программное обеспечение, пишет мейнтейнер GNOME Calendar. К сожалению, работа мейнтейнером свободного ПО может плохо отразиться на вашем психологическом и эмоциональном здоровье.

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

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

Преимущества бесплатных тарифов


Конечно, его мнение крайне субъективное. Сам Гвидо запустил два простеньких инди-сервиса и на сегодняшний день не заработал ещё тысячи долларов. То есть у него пока не накопилось достаточно опыта, чтобы делать такие выводы и объективно оценить пользу бесплатных тарифов.

В то же время мы видим, что многие компании предлагают данный вариант. Бесплатные вечные тарифы есть у Trello, Jira, Slack, Asana, Dropbox. Миллионы профессионалов используют эти сервисы бесплатно, а потом рекомендуют их в компаниях, куда приходят работать и те покупают платную подписку. Ссылки на Dropbox разлетаются по интернету как вирусный маркетинг. Таким образом, здесь расходы на бесплатные тарифы многократно окупаются.

Вопрос только в том, это стандарт индустрии или исключение из правил?

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

Это модель будущих единорогов.

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

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

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



На правах рекламы


Наша компания предлагает аренду VPS для совершенно любых проектов. Создайте собственный тарифный план в пару кликов, максимальная конфигурация позволит разместить практически любой проект 128 ядер CPU, 512 ГБ RAM, 4000 ГБ NVMe!

Подробнее..

Агрессивный переход в Atlassian облако или это vendor lock-in?

25.10.2020 00:14:44 | Автор: admin

В настоящий момент модель Cloud First (где-то уже Smart) шагает семимильными шагами, особенно в период пандемии COVID-19. И ведь в основном, страны такие как США (Cloud Smart), ЕС, Канада, Великобритания, Австралия, Чили, Аргентина уже имеют стратегию, цели и планы. Например, пройдя по прикрепленным ссылкам создается впечатление, что вот оно, облако, и все - пора иметь только облако или гибрид.

Но меня всегда беспокоит такая ситуация как vendor lock-in.

По моему первому впечатлению, vendor lock-in произошел после анонса новости от 16 октября от со-основателя компании Atlassian Скотта Фаркуар (Scott Farquhar). В качестве волевого и одностороннего решения сообщаются следующие важные даты:

со 2 февраля 2021 года,

а со 2 февраля 2024 года:

  • прекратится поддержка Server edition продуктов.

Итак, это значит, что вендор насильно пытается всех перевести в облако или на худой конец в Data Center. Компания предоставляет 3 варианта установки продуктов:

  • Server

  • Data Center

  • Cloud

где под Server подразумевается следующая политика лицензирования, единоразовая покупка лицензии и по желанию продление лицензии для поддержки и обновления. Не подразумевается масштабирование из коробки.

А под Data Center подразумевается обязательная ежегодная подписка, и масштабирование из коробки, и возможность обновления минорных релизов без простоев.

Ну, под Cloud, это полное системное администрирование силами вендора, где инфраструктура развернута на мощностях AWS и возможность оплаты за каждого сотрудника. Дополнительно можно посмотреть различия в этой сравнительной таблице, предложенным вендором.

Итак, рассмотрим ряд сценариев, которые предстоят клиентам вендора в ближайшем будущем:

  1. Согласиться и платить больше до 2024 года, и в конечном переходе мигрировать на DC. Для справки, кодовая база DC и Server одна и та же.

  2. Мигрировать потихоньку на DC, и сообществом давать обратную связь вендору, и получать скидки при переходе на DC. (тут основные даты связаны 1 полугодием 2021 (01.07.2021). Наверное, легко прослеживается связь с отчетным периодом.)

  3. Переход на Cloud, если у вас действительно есть необходимость соответствию 152-ФЗ, то тут https://jira.atlassian.com/browse/CLOUD-11061 прошу дать обратную связь или как минимум проголосовать. (*полагаю однажды Atlassian развернет мощности на территории РФ у одного из облачных провайдеров)

  4. Искать альтернативы, например, переход на другие on-prem продукты (Redmine, Phabricator, Youtrack, Trac, Mantis, BugGenie, Gitlab, AzureDevOps)

  5. Искать альтернативы, например, переход на другие облачные продукты. (например: Github, Wrike, Asana, Smartsheet, Trello (Atlassian product)).

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

Поэтому, я считаю, что в принципе, довольно интересное будущее ждет людей, занимающихся обслуживанием, развитием Atlassian экосистемы (не облачных продуктов) в организациях, особенно участников сообщества Atlassian в Telegram. И буду рад прочитать вашу обратную связь, узнать про другие продукты (в области управления проектами), решения и мнения об этих инициативах.

Подробнее..
Категории: Conference , Cloud , Atlassian , Jira , On-premise , Jira datacenter

Перевод Кросс-браузерное тестирование в Selenium

11.06.2021 02:20:41 | Автор: admin

В этой статье мы рассмотрим кросс-браузерное тестирование. Это тип тестирования, который проверяет, работает ли приложение так, как ожидается, в нескольких браузерах, операционных системах и устройствах. Мы можем проводить кросс-браузерное тестирование с помощью автоматизации и без нее. Сценарии автоматизированного тестирования могут быть написаны или созданы с помощью таких программ, как TestProject и Selenium.

К концу этой статьи вы узнаете об определении кросс-браузерного тестирования, его преимуществах и работе с ним в Selenium и TestProject.

Примечание: Код из этой статьи находится на GitHub здесь.

Что такое кросс-браузерное тестирование?

Кросс-браузерное тестирование гарантирует, что наше тестируемое приложение (AUT) совместимо с каждым браузером, операционной системой и устройством. Цель заключается в сравнении ожидаемого поведения приложения в различных случаях. Бывают случаи, когда один и тот же тестовый сценарий проходит на одном или нескольких экземплярах, но не работает на другом экземпляре.

Возможно, сбой произошел из-за нашего тестового скрипта или приложения. Вы когда-нибудь пытались открыть веб-сайт с помощью Internet Explorer, но он не работал, а затем тот же сайт без проблем открывался в Chrome? Такие проблемы выявляются во время кросс-браузерного тестирования, поскольку данные из AUT отображаются по-разному в каждом браузере.

Преимущества кросс-браузерного тестирования

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

Я сосредоточусь на двух преимуществах кросс-браузерного тестирования:

  1. Время

  2. Тестовое покрытие

Время

Создание и выполнение индивидуального сценария тестирования (Test Script) для уникальных сценариев занимает много времени. Поэтому наши тестовые сценарии создаются с тестовыми данными для использования их комбинаций. Один и тот же сценарий тестирования может выполняться на Chrome и Windows для первой итерации, затем на Firefox и Mac для второй итерации, а затем на других сценариях для последующих итераций.

Это экономит время, поскольку мы создаем только один тестовый сценарий, а не несколько. Ниже приведены 2 фрагмента кода для загрузки и получения заголовка для страницы TestProject. Один пример - это кросс-браузерное тестирование, а другой пример содержит отдельные тестовые сценарии для трех браузеров (Chrome, Firefox и Edge).

package tutorials.testproject;import io.github.bonigarcia.wdm.WebDriverManager;import org.openqa.selenium.WebDriver;import org.openqa.selenium.chrome.ChromeDriver;import org.openqa.selenium.edge.EdgeDriver;import org.openqa.selenium.firefox.FirefoxDriver;import org.testng.annotations.Parameters;import org.testng.annotations.Test;public class CrossBrowserTesting {  WebDriver driver;  @Test  @Parameters ( {"BrowserType"} )  public void testExamplePageOnMultipleBrowsers (String browserType) {    if (browserType.equalsIgnoreCase("Chrome")) {      WebDriverManager.chromedriver().setup();      driver = new ChromeDriver();    }    else if (browserType.equalsIgnoreCase("Edge")) {      WebDriverManager.edgedriver().setup();      driver = new EdgeDriver();    }    else if (browserType.equalsIgnoreCase("Firefox")) {      WebDriverManager.firefoxdriver().setup();      driver = new FirefoxDriver();    }    driver.manage().window().maximize();    driver.get("https://example.testproject.io/web/index.html");    System.out.println(browserType + ": " + driver.getTitle());  }}
package tutorials.testproject;import io.github.bonigarcia.wdm.WebDriverManager;import org.openqa.selenium.WebDriver;import org.openqa.selenium.chrome.ChromeDriver;import org.openqa.selenium.edge.EdgeDriver;import org.openqa.selenium.firefox.FirefoxDriver;import org.testng.annotations.Test;public class IndividualBrowserTesting {  WebDriver driver;  @Test  public void testExamplePageOnMultipleBrowsersOnChrome () {    WebDriverManager.chromedriver().setup();    driver = new ChromeDriver();    driver.manage().window().maximize();    driver.get("https://example.testproject.io/web/index.html");    System.out.println("Chrome: " + driver.getTitle());  }  @Test  public void testExamplePageOnMultipleBrowsersOnFirefox () {    WebDriverManager.firefoxdriver().setup();    driver = new FirefoxDriver();    driver.manage().window().maximize();    driver.get("https://example.testproject.io/web/index.html");    System.out.println("Chrome: " + driver.getTitle());  }  @Test  public void testExamplePageOnMultipleBrowsersOnEdge () {    WebDriverManager.edgedriver().setup();    driver = new EdgeDriver();    driver.manage().window().maximize();    driver.get("https://example.testproject.io/web/index.html");    System.out.println("Chrome: " + driver.getTitle());  }}

Тестовое покрытие

Тестовое покрытие - это техника, которая определяет, что и в каком объеме покрывается в наших тестовых сценариях.

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

  • Что будет включено в наши сценарии тестирования, зависит от требований.

  • То, сколько охвачено в наших сценариях тестирования, зависит от браузеров и их различных версий.

Тестовое покрытие является эффективным мерилом для процесса тестирования. Однако 100% покрытие трудно обеспечить, и, скорее всего, функция ведет себя не так, как это обычно происходит в конкретной версии.

Как осуществить кросс-браузерное тестирование в Selenium?

Мы осуществляем кросс-браузерное тестирование в Selenium, используя его сетку (grid) или тестовые данные. Selenium Grid упрощает процесс, а тестовые данные используются в качестве исходных. С помощью Selenium Grid наши тестовые сценарии выполняются параллельно на нескольких удаленных устройствах. Команды отправляются клиентом удаленным экземплярам браузера.

Тестовые данные могут храниться в файле Excel, CSV, файле свойств, XML или базе данных. Мы также можем объединить TestNG с тестовыми данными для проведения тестирования на основе данных или кросс-браузерного тестирования. Для тестирования на основе данных аннотация DataProvider и атрибут dataProvider или атрибут dataProviderClass позволяют нашему тестовому сценарию получать неограниченное количество значений.

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

<suite name="Cross Browser Testing">    <test name = "Test On Chrome">        <parameter name = "BrowserType" value="Chrome"/>            <classes>                <class name = "tutorials.testproject.CrossBrowserTesting"/>            </classes>    </test>    <test name = "Test On Edge">        <parameter name = "BrowserType" value="Edge"/>        <classes>            <class name = "tutorials.testproject.CrossBrowserTesting"/>        </classes>    </test>    <test name = "Test On Firefox">        <parameter name = "BrowserType" value="Firefox"/>        <classes>            <class name = "tutorials.testproject.CrossBrowserTesting"/>        </classes>    </test></suite>
package tutorials.testproject;import io.github.bonigarcia.wdm.WebDriverManager;import org.openqa.selenium.WebDriver;import org.openqa.selenium.chrome.ChromeDriver;import org.openqa.selenium.edge.EdgeDriver;import org.openqa.selenium.firefox.FirefoxDriver;import org.testng.annotations.Parameters;import org.testng.annotations.Test;public class CrossBrowserTesting {  WebDriver driver;  @Test  @Parameters ( {"BrowserType"} )  public void testExamplePageOnMultipleBrowsers (String browserType) {    if (browserType.equalsIgnoreCase("Chrome")) {      WebDriverManager.chromedriver().setup();      driver = new ChromeDriver();    }    else if (browserType.equalsIgnoreCase("Edge")) {      WebDriverManager.edgedriver().setup();      driver = new EdgeDriver();    }    else if (browserType.equalsIgnoreCase("Firefox")) {      WebDriverManager.firefoxdriver().setup();      driver = new FirefoxDriver();    }    driver.manage().window().maximize();    driver.get("https://example.testproject.io/web/index.html");    System.out.println(browserType + ": " + driver.getTitle());  }}

В XML-файле тег параметра расположен на уровне теста. У нас есть возможность разместить тег на уровне тестового набора, на уровне теста или на обоих уровнях. Обратите внимание, что тег параметра имеет имя и значение с данными между двойными кавычками. Его имя, т.е. "BrowserType", передается тестовому сценарию через аннотацию @Parameters, а значение, т.е. "Chrome", передается в операторы if и else if.

Операторы if и else if устанавливают Chrome, Edge или Firefox. Каждый браузер получал команды от одного и того же тестового сценария после выполнения из XML-файла. Следующие результаты тестирования показывают, как успешно загружается страница TestProject, а консоль печатает уникальное имя браузера и заголовок страницы.

Кросс-браузерное тестирование в Selenium с помощью TestProject

OpenSDK / Закодированный тест

Существует 2 способа проведения кросс-браузерного тестирования с помощью TestProject. Мы можем использовать OpenSDK с открытым исходным кодом или AI-Powered Test Recorder. OpenSDK оборачивается в Selenium и поддерживает Java, C# или Python. Наши тестовые сценарии похожи на кросс-браузерное тестирование в Selenium с минимальными изменениями в коде и зависимостях. Мы должны включить зависимость TestProject для Maven или Gradle, импортировать драйверы браузера и передать токен.

<dependency>     <groupId>io.testproject</groupId>     <artifactId>java-sdk</artifactId>     <version>0.65.0-RELEASE</version> </dependency>
implementation 'io.testproject:java-sdk:0.65.0-RELEASE'
import io.testproject.sdk.drivers.web.ChromeDriver;import io.testproject.sdk.drivers.web.FirefoxDriver;import io.testproject.sdk.drivers.web.EdgeDriver;

AI-Powered Test Recorder

С помощью AI-Powered Test Recorder мы создаем новое веб-задание, затем выбираем несколько браузеров, таких как Chrome, Edge и Firefox. Тест в задании TestProject позволяет нам выбрать дополнительный источник данных CSV, если мы хотим выполнить тестирование на основе данных. Вот несколько скриншотов, показывающих шаги по выполнению кросс-браузерного тестирования и отчета.

Вот пошаговая демонстрация кросс-браузерного тестирования с помощью TestProject AI-Powered Test Recorder.

Выводы

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

Кросс-браузерное тестирование осуществляется с помощью Selenium и TestProject.

TestProject позволяет нам создавать собственные тестовые сценарии с использованием Java, C# или Python после добавления OpenSDK с открытым исходным кодом. OpenSDK является оберткой Selenium, поэтому он содержит команды Selenium плюс дополнительные команды из TestProject. Кроме того, мы можем использовать TestProject's AI-Powered Test Recorder для проведения кросс-браузерного тестирования. Это удобный процесс, который требует от нас только выбора браузера, который мы хотим использовать для кросс-браузерного тестирования.


Перевод статьи подготовлен в рамках курса "Java QA Engineer. Basic". Всех желающих приглашаем на двухдневный онлайн-интенсив Теория тестирования и практика в системах TestIT и Jira. На интенсиве мы узнаем, что такое тестирование и откуда оно появилось, кто такой тестировщик и что он делает. Изучим модели разработки ПО, жизненный цикл тестирования, чек листы и тест-кейсы, а также дефекты. На втором занятии познакомимся с одним из главных трекеров задач и дефектов Jira, а также попрактикуемся в TestIT отечественной разработке для решения задач по тестированию и обеспечению качества ПО.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru