Если вы работаете в IT-компании, то, скорее всего, ваши процессы построены вокруг известного продукта Atlassian — Jira. На рынке есть множество таск-трекеров для решения тех же задач, в том числе open-source-решения (Trac, Redmine, Bugzilla), но, пожалуй, именно Jira имеет сегодня самое широкое распространение.

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

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

Дополнительные возможности Jira


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

REST API


В общем случае вызов команды API — это HTTP-запрос к URL API с указанием метода (GET, PUT, POST and DELETE), команды и тела запроса. Тело запроса, а также ответ API —  в JSON-формате. Пример запроса, который вернёт JSON-представление тикета:

GET /rest/api/latest/issue/{ticket_number}

С помощью API вы можете, используя скрипты на любом языке программирования:

  • создавать тикеты;
  • модифицировать любые свойства тикетов (встроенные и кастомные);
  • писать комментарии;
  • с помощью JQL (встроенный язык запросов) получать любые списки тикетов;
  • и многое другое.

Подробная документация об API представлена по ссылке.

Мы написали собственный высокоуровневый Jira API-клиент на PHP, который реализует все необходимые нам команды. Вот пример команд для работы с комментариями:

public function addComment($issue_key, $comment)
{
   return $this->_post("issue/{$issue_key}/comment", ['body' => $comment]);
}
 
public function updateComment($issue_key, $comment_id, $new_text)
{
   return $this->_put("issue/{$issue_key}/comment/{$comment_id}", ['body' => $new_text]);
}
 
public function deleteComment($issue_key, $comment_id)
{
   return $this->_delete("issue/{$issue_key}/comment/{$comment_id}");
}

Webhooks


С помощью webhook можно настроить вызов внешней callback-функции на вашем хосте на различные события в Jira. При этом можно настроить сколько угодно таких правил таким образом, что различные URL будут «дёргаться» для разных событий и для тикетов, которые соответствуют указанному в webhook фильтру. Интерфейс настройки webhooks доступен администратору Jira.

В результате можно создавать правила вроде этого:

Name: “SRV — New Feature created/updated”
URL: www.myremoteapp.com/webhookreceiver
Scope: Project = SRV AND type in (‘New Feature’)
Events: Issue Updated, Issue Created

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

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

Подробная документация о webhooks представлена по ссылке.

ScriptRunner


Это плагин к Jira, очень мощный инструмент, который позволяет кастомизировать в Jira очень многое (в том числе он способен заменить собой webhooks). Для пользования этим плагином требуется знание Groovy. Основное преимущество инструмента для нас состоит в том, что можно встраивать во флоу кастомную логику в режиме онлайн. Код вашего скрипта будет исполняться сразу в среде Jira в ответ на определённое действие. Например, можно сделать в интерфейсе тикета свою кнопку, клик по которой будет создавать связанные с текущей задачей тикеты или запускать юнит-тесты для данной задачи. И если вдруг что-то пойдёт не так, вы как пользователь сразу об этом узнаете.

Желающие могут ознакомиться с документацией.

Флоу: что скрыто под капотом


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

Open/Backlog


Итак, сначала тикет попадает в беклог новых тикетов со статусом Open. Далее лид компонента, увидев новый тикет на своём дашборде, принимает решение: назначить тикет прямо сейчас разработчику либо отправить его в беклог известных тикетов (статус Backlog), чтобы назначить его позже, когда появится свободный разработчик и более приоритетные тикеты будут закрыты. Это может показаться странным, так как кажется логичным делать наоборот: создавать тикеты в статусе Backlog, а потом переводить в статус Open. Но у нас прижилась именно эта схема. Она позволяет легко настроить фильтры, чтобы сократить время принятия решения по новым тикетам. Пример JQL-фильтра, который показывает новые задачи лиду:

Project = SRV AND assignee is EMPTY AND status in (Open)

In Progress


Технические нюансы работы с Git
Надо отметить, что у нас работа над каждой задачей ведётся в отдельной Git-ветке. Насчёт этого у нас есть соглашение, что имя ветки в начале должно содержать номер тикета. Например, SRV-123_new_super_feature. Также комментари к каждому коммиту в ветку должны содержать номер тикета в формате [SRV-123]: {comment}. Такой формат необходим нам, например, для корректного удаления «плохой» задачи из билда. Как это делается, подробно описано в статье.

Эти требования контролируются Git-хуками. Например, вот содержимое prepare-commit-msg, который подготавливает комментарий к коммиту, получая номер тикета из имени текущей ветки:

#!/bin/bash
b=`git symbolic-ref HEAD| sed -e 's|^refs/heads/||' | sed -e 's|_.*||'`
c=`cat $1`
if [ -n "$b" ] && [[ "$c" != "[$b]:"* ]]
then
   echo "[$b]: $c" > $1
fi

Если коммит с «неправильным» комментарием попытаться запушить, такой пуш будет отклонён. Также отклонена будет попытка запушить ветку без номера тикета в начале.

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

У нас принято выставлять задаче due date в момент, когда она переводится в статус In Progress. Если же разработчик этого не сделал, ему придёт напоминание в корпоративный мессенджер HipChat. Специальный скрипт раз в два часа:

  • выбирает с помощью REST API Jira тикеты в статусе in progress с пустым полем due date (project = SRV AND status = ‘In Progress’ AND duedate is EMPTY);
  • выбирает незавершённые тикеты с due date старше текущей даты (project = SRV AND status = ‘In Progress’  AND duedate is not EMPTY AND duedate < now());
  • для каждого тикета узнаёт разработчика, читая соответствующее поле в тикете, а также лида разработчика;
  • группирует тикеты по разработчикам и лидам и отправляет напоминания в HipChat, используя его API.

Сделав все необходимые коммиты, разработчик пушит ветку в общую репу. В этом случае срабатывает Git-хук post-receive, который делает много всего интересного:

  • имя Git-ветки, а также комментарии к коммитам проверяются на соответствие нашим правилам;
  • проверяется, что тикет, с которым ассоциируется ветка, не закрыт (в закрытые тикеты пушить новый код нельзя);
  • проверяется синтаксис изменённых PHP-файлов (PHP -l file_name.php);
  • проверяется форматирование;
  • если тикет, в который пушится ветка, находится в статусе Open, то он автоматически переводится в статус In Progress;
  • тикет привязывается к ветке, делается соответствующая запись в кастомном поле тикета Commits с помощью Jira API. Выглядит это так:


(branchdiff — это ссылка на diff ветки с головой, от которой взяла своё начало текущая ветка, в нашем инструменте ревью кода Codeisok);

  • создаётся комментарий в тикете со всеми коммитами в данном пуше.

    (Aida — это условное название нашего комплекса автоматизации для работы с Jira, Git и не только. Именно от этого имени появляются автоматические комментарии в тикете. Подробнее об Aida мы писали в статье).
    Клик по хешу коммита открывает diff с предыдущей ревизией ветки (как это примерно выглядит, покажу ниже);
  • проверяется, есть ли в ветке файлы, для которых может потребоваться перевод на поддерживаемые языки (например, шаблоны web-страниц), и если такие есть, то кастомному полю тикета Lexems проставляется значение New\Changed. Это гарантирует, что тикет не уедет на продакшен без законченного перевода;
  • в список девелоперов (кастомное поле тикета Developers) добавляется имя сотрудника, который пушит ветку.

On Review


Написав код и самостоятельно убедившись, что все требования к задаче выполнены, а тесты не сломаны, разработчик назначает тикет ревьюверу (статус On Review). Обычно разработчик сам решает, кто будет ревьювить его тикет. Скорее всего, это будет другой разработчик, который отлично разбирается в нужной части кода. Ревью происходит с помощью инструмента Codeisok, который открывается сразу с нужным diff по клику на ссылку branchdiff в поле тикета Commits или на ссылку в виде хеша коммита в комментариях.

Ревьювер видит примерно такую картину:


Закончив ревью, ревьювер нажимает кнопку Finish, и, помимо всего прочего, в этот момент происходит следующее:

  • с помощью API JIra создаётся комментарий в тикете с замечаниями ревьювера в контексте кода. Выглядит это примерно так:


  • если замечания к коду были и ревьювер решил переоткрыть тикет, то разработчику придёт уведомление об этом в HipChat (это делается с помощью правила webhook, которое срабатывает на переоткрытие);
  • заполняется поле тикета Reviewers.

Resolved


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



Также в любой момент можно вручную инициировать повторный прогон тестов, кликнув по специальной кнопке Run unit tests в меню тикета. После успешного прогона в тикете появится новый комментарий, аналогичный предыдущему.


По сути, эта кнопка — один из дополнительных статусов задачи в workflow Jira, перевод в который инициирует срабатывание скрипта на Groovy для плагина ScriptRunner. Скрипт вызывает внешний URL, который инициирует прогон тестов, и если URL ответил успехом, то тикет возвращается в предыдущий статус (в нашем случае Resolved).

In Shot / In Shot — OK


Задача сначала тестируется в devel-окружении. Если всё хорошо, создаётся шот (например, кликом по ссылке Create shot в поле Commits) — директория на выделенном сервере, в которую копируются изменения из тикета, смёрженные с текущим master. Сервер работает с продакшен-данными: базы и сервисы те же, что обслуживают реальных пользователей. Таким образом, тестировщик может открыть web-сайт или подключиться к шоту с помощью мобильного клиента и «изолированно» проверить фичу в продакшен-окружении. «Изолированно» значит, что никакой другой код/функционал, кроме нового из ветки и текущего master, не исполняется. Поэтому этот этап тестирования является, пожалуй, основным, так как позволяет QA-инженеру максимально достоверно найти проблему непосредственно в тестируемой задаче.

Доступ к ресурсам шота осуществляется по специальным URL, которые генерируются в скрипте создания шота и с помощью API Jira помещаются в шапку тикета. В результате мы видим ссылки на сайт, админку, логи и прочие инструменты, которые исполняются в шот-окружении:



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

Если тестирование в шоте прошло успешно, то тикет переводится в статус In Shot — OK.

In Build / In Build — OK


Мы выкладываем код два раза в день — утром и вечером. Для этого создаётся специальная build-ветка, которая в итоге будет слита с master и выложена «в бой».

В момент сборки build-ветки специальный скрипт с помощью JQL-запроса получает список тикетов в статусе In Shot — OK и пытается замёржить их в ветку билда при выполнении всех перечисленных ниже условий:

  • перевод для тикета закончен или переводить ничего не нужно (Lexems in (‘No’, ‘Done’));
  • разработчик присутствует на рабочем месте (система автоматического слияния проверяет по внутренней базе, не находится ли разработчик в отпуске или на больничном, и если да, то тикет может быть замёржен только вручную релиз-инженерами или другим ответственным разработчиком, который указан в специальном поле Vice Developer; лид отсутствующего разработчика в этом случае получает уведомление о том, что тикет не может быть автоматически добавлен в билд);
  • у тикета не установлен флажок Up in Build в значение by Developer (это специальное кастомное поле тикета, которое даёт возможность разработчику самому определять, когда тикет попадёт в билд);
  • ветка тикета не зависит от другой ветки, которая ещё не попала в master или текущий билд. Мы всячески стараемся избегать подобной ситуации, но иногда такое происходит, когда разработчик создаёт свою ветку не от master, а от ветки другого тикета, либо когда вмёрживает к себе чужую ветку. Это можно сделать в том числе и случайно, поэтому мы решили, что дополнительная защита не помешает.

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

Если же всё хорошо и ветка тикета замёржилась в билд, тикет автоматически переводится в статус In Build, а в кастомное поле тикета Build_Name пишется название билда.


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

На следующем этапе QA-инженеры дополнительно проверяют, корректно ли работает код задачи совместно с другими задачами в билде. Если всё хорошо, тикету вручную выставляется статус In Build — OK.

On Production / On Production — OK / Closed


Далее на билде прогоняется весь наш набор тестов (Unit, интеграционные, Selenium- и т. д.). Если всё хорошо, билд мёржится в master, а код выкладывается на продакшен. Тикет переводится в статус On Production.

Далее разработчик (или заказчик) убеждается, что на продакшене фича работает корректно, и выставляет тикету статус On Production — OK.

Спустя две недели тикеты в статусе On Production — OK автоматически переводятся в статус Closed, если кто-то ранее не сделал это вручную.

Также стоит упомянуть дополнительные статусы, в которых может находится тикет:

  • Requirements — когда не получается оперативно получить от заказчика необходимые уточнения по задаче, а без них дальнейшая работа по тикету невозможна, тикет переводится в этот статус и назначается тому, кто должен дать разъяснения;
  • Suspended — если работа по тикету приостановлена, например, если разработчик заблокирован задачами смежной команды или был вынужден переключиться на более срочную задачу;
  • Reopened — задача может быть переоткрыта на разработчика после ревью, после тестирования, после неудачной попытки слияния ветки с master.

В результате упрощённая схема нашего workflow выглядит так:


Тикет — центр коммуникаций по задаче


В результате прохождения тикета по флоу его шапка приобретает примерно такой вид:



Что здесь ещё интересного, что мы настроили под себя и о чём я ещё не упомянул?

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

    Project = SRV AND type = Bug AND status = Open AND component in componentsLeadByUser(d.semenihin)

  • Review — нужно ли ревью кода. По умолчанию нужно. Если значение поля установлено в No, тикет сразу попадёт в статус Resolved.

    QA — нужна ли проверка тестировщиком. По умолчанию нужна. Если значение поля установлено в No, тикет сразу попадёт в статус In Shot — OK.

    Sprint — в нашем случае актуально только для задач с типом New Feature, план для которых мы составляем заранее на неделю.
  • Due date — определение разработчиком даты, когда тикет будет на продакшене. Выставляется перед началом работы над задачей.
  • Situation — по сути, краткий лог с кратким описанием текущего статуса по задаче. Например, «20/08 Жду переводов», «21/08 Требуется уточнение от заказчика по проблеме Х». Это помогает видеть краткую сводку по задаче в списке других задач.
  • Msg4QA — информация для QA-инженеров, которой делится разработчик, чтобы упростить процесс тестирования

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

Помимо «человеческих» текстов, как я уже упоминал выше, в комментарии много всего пишется автоматически с помощью API:

  • коммиты;
  • результаты ревью;
  • результаты прогона тестов.

Иногда автоматические комментарии могут мешать, например, продакт-менеджерам. Поэтому мы сделали простенький JS-скрипт, который добавляет кнопку в интерфейс Jira и позволяет сворачивать все автоматические комментарии, оставляя только «человеческие». В итоге свёрнутые автоматические комментарии выглядят компактно.



JS-код скрипта, который мы встроили в шаблон тикета
window.addEventListener('load', () => {

    const $ = window.jQuery;

    const botsAttrMatch = [
        'aida',
        'itops.api'
    ].map(bot => `[rel="${bot}"]`).join(',');

    if (!$) {
        return;
    }

    const AIDA_COLLAPSE_KEY = 'aida-collapsed';
    const COMMENT_SELECTOR = '.issue-data-block.activity-comment.twixi-block';

    const JiraImprovements = {
        init() {
            this.addButtons();
            this.handleAidaCollapsing();
            this.handleCommentExpansion();

            // Handle toggle button and aida collapsing and put it on a loop
            // to handle unexpected JIRA behaviour
            const self = this;
            setInterval(function () {
                self.addButtons();
                self.handleAidaCollapsing();
            }, 2000);

            addCss(`
                #badoo-toggle-bots {
                    background: #fff2c9;
                    color: #594300;
                    border-radius: 0 3px 0 0;
                    margin-top: 3px;
                    display: inline-block;
                }
            `);
        },

        addButtons() {
            // Do we already have the button?
            if ($('#badoo-toggle-bots').length > 0) {
                return;
            }

            // const headerOps = $('ul#opsbar-opsbar-operations');
            const jiraHeader = $('#issue-tabs');

            // Only add it in ticket state
            if (jiraHeader.length > 0) {
                const li = $('<a id="badoo-toggle-bots" class="aui-button aui-button-primary aui-style" href="/">Collapse Bots</a>');

                li.on('click', this.toggleAidaCollapsing.bind(this));

                jiraHeader.append(li);
            }
        },

        toggleAidaCollapsing(e) {
            e.preventDefault();

            const isCollapsed = localStorage.getItem(AIDA_COLLAPSE_KEY) === 'true';

            localStorage.setItem(AIDA_COLLAPSE_KEY, !isCollapsed);
            this.handleAidaCollapsing();
        },

        handleAidaCollapsing() {
            const isCollapsed = localStorage.getItem(AIDA_COLLAPSE_KEY) === 'true';
            const aidaComments = $(COMMENT_SELECTOR).has(botsAttrMatch).not('.manual-toggle');

            if (isCollapsed) {
                aidaComments.removeClass('expanded').addClass('collapsed');
                $('#badoo-toggle-bots').text('Show Bots');
            }
            else {
                aidaComments.removeClass('collapsed').addClass('expanded');
                $('#badoo-toggle-bots').text('Collapse Bots');
            }
        },

        handleCommentExpansion() {
            $(document.body).delegate('a.collapsed-comments', 'click', function () {

                const self = this; // eslint-disable-line no-invalid-this
                let triesLeft = 100;

                const interval = setInterval(() => {
                    if (--triesLeft < 0 || self.offsetHeight === 0) {
                        clearInterval(interval);
                    }

                    // Element has been removed from DOM. i.e. new jira comments have been added
                    if (self.offsetHeight === 0) {
                        JiraImprovements.handleAidaCollapsing();
                    }
                }, 100);
            });

            $(document.body).delegate(COMMENT_SELECTOR, 'click', function () {
                $(this).addClass('manual-toggle');// eslint-disable-line no-invalid-this
            });
        }
    };

    JiraImprovements.init();

    function addCss(cssText) {
        const style = document.createElement('style');

        style.type = 'text/css';
        if (style.styleSheet) {
            style.styleSheet.cssText = cssText;
        }
        else {
            style.appendChild(document.createTextNode(cssText));
        }

        document.head.appendChild(style);
    }

});


Что ещё?


Ещё с помощью API и webhooks Jira мы делаем такие вещи:

  • отправляем уведомление в HipChat, если в комментарии был упомянут кто-то из сотрудников (очень способствует оперативному решению вопросов);
  • отправляем уведомления в HipChat при назначении тикета на ревью и когда тикет попадает на продакшен (как именно мы это реализовали, расскажу в следующей статье);
  • системные архитекторы с помощью специального интерфейса в пару кликов создают тикеты различным командам (клиентским и серверным) для реализации проекта (при этом тикеты корректно заполняются нужными полями и линкуются между собой; это помогает нам эффективно организовать синхронизацию работы команд);
  • мы автоматически отслеживаем появление новых версий клиентов; после этого специальный скрипт создаёт тикет серверной команде, чтобы мы внесли изменения в некоторые конфиги;
  • скрипт периодически снимает срезы по задачам в статусе In progress для статистики;
  • скрипт определяет задачи, которые надолго «зависают» в определённых статусах (например, On Review), и отправляет соответствующие уведомления ответственным сотрудникам;
  • если сотрудник в этот день отсутствует в офисе и об этом есть соответствующая запись во внутренней базе, то к его имени в Jira добавляется информация об этом (например, «d.semenihin (Day off)»). Очень полезная фича.

Итоги


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

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

Спасибо за внимание!

Комментарии (23)


  1. Magnum72
    03.10.2018 01:52

    У нас принято выставлять задаче due date в момент, когда она переводится в статус In Progress. Если же разработчик этого не сделал, ему придёт напоминание в корпоративный мессенджер HipChat. Специальный скрипт раз в два часа:


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


    1. alexkrash
      03.10.2018 07:59

      «Explicit better than implicit» :)
      Тут получается каламбур, но — у нас явно видно, что значение для чего-то (due date) не установлено. Т.к. это поле предназначено для заполнения вручную, то автоматическое вмешательство может вызвать некий диссонанс — «как это Due date уже прошел? я не помню, чтобы менял его».


    1. JSas
      03.10.2018 10:14

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


    1. OlegKrasikov
      03.10.2018 11:56

      Вы хотите ставить due date == текущему времени? Взял работу и сразу закончил?


  1. alexander_fokin
    03.10.2018 10:53

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

    Не бывает ли проблем на этом этапе? Решение конфликтов может быть проведено некорректно и привнести новые баги. А у вас к этому моменту уже все тесты пройдены…


    1. ShaggyRatte
      03.10.2018 11:55
      +1

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


  1. xopen
    03.10.2018 11:31

    Слишком много думаете о автоматизации и мало о процессе.
    Сходу:
    — Open это и есть беклог. Не нужен никакой отдельный беклог. Ассайнить тикеты никто не мешает.
    — Лидера уволить и научить разработчиков самим брать тикеты. Когда лидер болеет, работа стоит?
    — декомпозиция есть, а стадии нет? Ничего не создаём сложнее кнопки на экране? Спеки не создаём? Как вообще понять, что разработчик уже декомпозирует, а не тикет просто лежит в беклог? (Я знаю. Важный лидер за спинами ходит.)
    — Сделать Due Date просто обязательным полем и выкинуть скрипт.


    1. dsemenikhin Автор
      03.10.2018 12:12

      1. Backlog ввели чисто для удобства. Если задача находится в этом статусе, значит лид ее отсмотрел и принял решение прямо сейчас ее не назначать ни на кого. Это можно решать иначе, конечно. Лейблами, например.
      2. Я про это вроде как не писал ничего конкретного. В общем случае задачи назначает лид, но и разработчики сами разбирают тикеты вполне успешно. Тут нет жесткой схемы и каждый лид сам отстраивает этот процесс в своей команде.
      3. Тут соглашусь с вами. Пожалуй, есть что улучшить. Лид в курсе, да. Ну и мы стараемся делать так, чтобы количество задач висящих на разработчике в один момент времени было очень небольшим. В этом случае, довольно просто понимать чем занят сейчас разработчик, не отвлекая его.
      4. В нашем случае, спринт — не совсем спринт в классическом понимании :) Это инструмент недельного (у нас) планирования. Мы коммитимся перед продуктовой командой, что задачи взятые в спринт будут НАЧАТЫ на этой неделе, а значит и Due Date по ним будет определен. Подробно я писал об этом тут. Также Jira предоставляет удобные инструменты для работы со спринтами и в вашу схему они прекрасно ложатся.


      1. xopen
        03.10.2018 16:17

        Просто попытайтесь проникнуться идеей. Чем больше задач делегированно или автоматизированно — тем больше у руководителя времени вырасти из менеджера- сортировщика в лидера, который думает о развитии продукта и мотивации персонала. Всегда можно найти работника сортировщика, который будет это делать на «достаточно» хорошем уровне и будет рад, что он уже как бы мини-менеджер.
        «У нас принято выставлять задаче due date в момент» — положено-ешь, не положено — не ешь. Не знаешь дату — декомпозируй. Знаешь — пиши, работай.
        Там еще «разработчик присутствует на рабочем месте». Если мержится и работает — зачем вам разработчик? Не работает — выкинули и встретимся по приходу из отпуска.
        Что такое «On Production — Ok» ?? А если не ОК? Где стрелка отката назад? Подозреваю, что востановят прод из бекапа и он всегда будет снова ОК. Значит статус не нужен. Запустился, не упал за 10 мин — Closed. Упадет — новый тикет и root cause. Или ставьте Closed через 2 недели. Вы все равно НЕ ЗНАЕТЕ ок или не ок, пока две недели не пройдет. Зачем лишний статус?


        1. dsemenikhin Автор
          03.10.2018 19:18

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

          По «разработчик присутствует на рабочем месте». Во-первых, у нас принято проверять задачу в проде после того как она выехала. Посмотреть статку, эррор-логи, убедиться, что все работает нормально. Лучше всего это может сделать сам разработчик. Во-вторых, уходя в отпуск, девелопер может проставить в поле тикета ViceDeveloper имя другого разработчика, который в теме, и тогда тикет обычным образом замержится (кажется я забыл написать в статье об этом). В-третьих, лид получает уведомление в HipChat, если тикет его сотрудника скипнулся из-за отсутствия. В этом случае он может попросить релизеров замержить тикет в билд, если фича срочная и не ждет возвращения разработчика. Так что все довольно гибко.

          On Production — Ok — значит, что фича проверена на продакшене вот и все. Если не ок, то действуем по обстоятельствам: разбираемся, патчим, открываем новый тикет на исправление и т.п.


          1. xopen
            03.10.2018 20:13

            Статус лишний. «Closed» это и есть продакшн, который вроде ок.


  1. Sadwind
    03.10.2018 12:04

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

    Про Due Date тоже не понятно: зачем скрипт, если можно настроить обязательность заполнения поля при переводе на следующий этап? Чем скрипт удобнее?


    1. dsemenikhin Автор
      03.10.2018 12:19

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


      1. Sadwind
        04.10.2018 12:48

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


  1. unel
    03.10.2018 14:33
    +1

    Спасибо за статью! Всегда интересно узнать, как этот процесс устроен в других компаниях в таких подробностях)

    Возникло несколько вопросов:
    — на скрине с тикетом, я вижу одно поле, которое вроде не упоминалось в статье — «approvers», правильно ли я понимаю, что это список тех людей, что могут утвердить то, что таска соответствует описанию и её можно катить в прод? На каком этапе это происходит, есть ли для этого отдельный статус тикета и процесс?

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


    1. xopen
      03.10.2018 16:31

      последующие шаги?
      1. Unit test by Developer. (пока не работает — все отдыхают)
      2. Ревью кода предусматривает проверку логики. Если есть продукт-овнер, который это делает быстрее разработчиков — пускайте вперед. Если он один на всех и занят — пускайте разработчиков соседей. Или тим-лида. Чистая логика: если работает не так — какая мне разница красивый ли там код.
      3. Тестировщики максимально в конце. Желательно набор авто-тестов до того как людей дергать. Маленькая команда, тим лид глупый. Сделали мини ревью(формат только) — и пусть тестировщики разбираются работает или нет.

      Нет идеальных процессов. Процесс — либо дает предсказуемый средний результат. Либо закрывает именно ваши проблемы, дырки в скиллах и людях. Документация ниже плинтуса? Раздражает? Введите стадию «Document update» и тд. Делаете код ревью в гите и не бывает такого, что ревью не сделано — можно вообще выкинуть стадию «On review» в Jira.


      1. unel
        04.10.2018 12:49

        Ревью кода предусматривает проверку логики

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


      1. unel
        04.10.2018 12:49

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

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


    1. dsemenikhin Автор
      03.10.2018 19:27

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

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


  1. acmnu
    04.10.2018 11:38

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

    А что потом? Как они отслеживают процесс? И я правильно понял, что это специальный интерфейс сбоку от Jira?


    1. dsemenikhin Автор
      04.10.2018 11:43

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


      1. acmnu
        04.10.2018 16:25
        +1

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


        1. ShaggyRatte
          04.10.2018 17:03

          А на жире не смогли такое сделать?

          Это сложнее. Jira не предоставляет удобного способа создания каких-либо webview. Большинство встроенных операций представляют из себя стандартные экраны (screen), в которых можно настроить только список полей. Для создания чего-то кастомного, нужно смотреть в сторону плагинов: или писать полностью свои или использовать какие-то готовые. Например, в script runner есть возможность добавлять собственные web элементы в интерфейс, в том числе, можно вызывать dialogs при нажатии на кнопку.


          Но последнее, конечно, сложнее, чем сделать простую форму на отдельной странице :)