Запланировали задачу в MS Project, а исполнители не в курсе, т.к. смотрят свои таски в JIRA? Вручную заводить в таски долго, а любое перепланирование вызывает проблемы?

Если вы сталкивались с этим, мой опыт может показаться полезным.

Вводные

Привет, меня зовут Алексей. Сейчас я заместитель руководителя ЦК Проектирования и Архитектуры одной из информационных систем Россельхозбанка. Но рассказать я хочу про свой предыдущий опыт.

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

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

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

Вдобавок ко всему, исполнители не были разбиты на группы и вести учет всех ресурсов приходилось в одном project-файле (ms project server  у нас не было). В огромном файле с 6000-6500 строк.

Основной системой для учета задач в нашей организации ранее была внедрена Atlassian Jira. Первоначально связку JIRA+MSProject внедрил мой предшественник, за что я ему очень благодарен.

Количество уже запланированных задач в моменте могло достигать 300-350 штук. Ежемесячно поступало на планирование ещё 20-30 задач. Задачи, планируемые по методологии Waterfall, фактически генерировали еще по 10-15 подзадач. Создавать этот объем в JIRA вручную очень трудоемко. Не создавать задачи в JIRA – тоже плохая идея. Гарантировано донести до исполнителей какие задачи в какой срок нужно сделать – практические нереально, учитывая количество сотрудников.

Изобретая велосипед

Первоначальное решение по интеграции MSProject <-> JIRA было реализовано в виде набора макросов, которые вызывали внешний шлюз к JIRA. Исходных кодов у нас не было, поэтому шлюз был черным ящиком, который мы не могли изменять. Шлюз взаимодействовал с JIRA через SOAP и после очередного обновления JIRA благополучно перестал работать.

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

Почему «велосипед» - так потому что ранее все работало, пусть и по другому протоколу. Да и вероятно существуют другие готовые решения, которые я не нашел.

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

Плюсы реализации на VBA:

  1. Открытый и достаточно простой код, который оперативно можно исправить

  2. Отсутствие необходимости установки дополнительных сред разработки.

  3. Пересборка dll шлюза требовала регистрацию ее в системе. Учитывая, что админских прав на рабочей станции у нас нет, исполнение запроса на обновление dll-библиотеки шлюза могло занять неделю. Простой в интеграции MSProject <-> JIRA был для нас недопустим.

  4. Отсутствие необходимости дополнительного ПО, достаточно стандартного набора библиотек.

Минусы реализации на VBA:

  1. Более низкая скорость работы в сравнении с шлюзом, написанным на C# (было принято не критичным, даже учитывая объем задач)

  2. Открытый код может повлечь локальные правки, которые в дальнейшем будет сложнее сопровождать (в связи с количеством пользователей решения – не критично)

  3. Нельзя заложить гарантированные ограничения в код, т.к. код открыт (в связи с количеством пользователей решения – не критично)

  4. Ограничения языка VBA (решается костылями)

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

Реализация

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

Минимально необходимый макрос для создания задачи в JIRA

Sub PostToJIRA
    Dim xmlHttpRequest As New MSXML2.XMLHTTP60
    Dim sJSON As String '<---------- здесь должен быть JSON с параметрами создаваемой задачи
    Dim sConnectionString As String '<---------- здесь должна быть строка подключения к вашей JIRA
    Dim sUserandPassword as String '<--------- здесь должна быть логин и пароль, формат User:Password в Base64 

                With xmlHttpRequest
                  URL sConnectionString + "rest/api/2/issue/"
                   .Open "POST", URL, True
                   .setRequestHeader "Authorization", "Basic " & sUserandPassword
                   .setRequestHeader "Content-Type", "application/json"
                   .setRequestHeader "Accept", "application/json"
                   .setRequestHeader "Origin", sConnectionString
                   .send (sJSON)
                End With
                
                With xmlHttpRequest
                    While Not .readyState = 4                               '<---------- ждем завершения обработки запроса,  если не ждать то при попытке обратиться к .responseText свалимся в ошибку
                    Pause (1)
                    Wend
                    sStatus = .Status & " | " & .statusText & " | " & .responseText
                    sRestAntwort = .responseText
                End With
            

                sStatusCode = xmlHttpRequest.Status
                If sStatusCode <> "201" Then
                    MsgBox (sStatus)
                    eErr = sStatus
                End If
		Set xmlHttpRequest = Nothing
End Sub

Естественно получение переменных необходимо вынести в отдельные функции. В частности, в нашей реализации строка sConnectionString определяется из конфигурационного файла, как и необходимые атрибуты для Json. А еще правильнее делать не процедуру PostToJira, а функцию, которая будет возвращать ответ от JIRA для дальнейшей обработки.

При создании задачи в JIRA необходимо учитывать следующее:

  1. У пользователя должны быть права на создание задачи в указанном проекте

  2. Все обязательные поля, для данной задачи, должны быть переданы в JSON запросе

  3. Все передаваемые поля должны быть на экранной форме создания запроса в JIRA через браузер

  4. Исполнитель, на которого назначается задача должен обладать правами «быть назначенным на задачу» (самый простой способ проверить – попробуйте назначить исполнителя через браузер)

Пример минимально необходимого JSON для создания задачи:

{"fields":{"project":{"key": "Наш проект"},"summary": "Название задачи","description":"","issuetype":{"id":"Тип задачи в проекте"},"duedate":"2021-05-11",,"assignee":{"name":"ЛогинИсполнителя"}}}

С созданием задач разобрались. Теперь логичное желание каким-то образом изменить задачу в JIRA. Для этого нам нужно в момент создания задачи в JIRA, сохранить в Project идентификатор созданной задачи. Хорошо, что в случае успешного выполнения запроса в xmlHttpRequest.responseText будет передан ответный JSON. Разобрать JSON поможет JSONConverter, который можно взять здесь.

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

Private Function PutToJira(iJiraTask As String, iJSON As String) As String
    Dim xmlHttpRequest As New MSXML2.XMLHTTP60
    Dim tstr As String           

                With xmlHttpRequest
                    URL = GetConnectionString() + "rest/api/2/issue/" + iJiraTask
                   .Open "PUT", URL, True
                   .setRequestHeader "Authorization", "Basic " & GetUserAndPassword()
                   .setRequestHeader "Content-Type", "application/json"
                   .setRequestHeader "Accept", "application/json"
                   .setRequestHeader "Origin", GetConnectionString()
                   .send (iJSON)
                End With
                
                With xmlHttpRequest
                    While Not .readyState = 4                               '<---------- wait
                    Pause (1)
                    Wend
                    sStatus = .Status & " | " & .statusText & " | " & .responseText
                    sRestAntwort = .responseText
                End With

                sStatusCode = xmlHttpRequest.Status
                If sStatusCode <> "1223" Then MsgBox (sStatus)
		Set xmlHttpRequest = Nothing
		PutToJira = sRestAntwort
End Function

Пример JSON для изменения задачи:

{"fields":{"summary": "Название","description":"Описание",,"duedate":"срок исполнения","assignee":{"name":"Логин исполнителя"}}}

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

Пример функции для получения информации по задаче из JIRA:

Private Function GetFromJira(iJiraTasks As String) As String
		Dim xmlHttpRequest As Object
		Dim sRestAntwort As String 

                Set xmlHttpRequest = CreateObject("MSXML2.XMLHTTP")
                With xmlHttpRequest
                    URL = GetConnectionString() + "rest/api/2/search?jql=" + iJiraTasks + "&maxResults=500&order by ID"
                    .Open "GET", URL, False
                    .setRequestHeader "Authorization", "Basic " & GetUserAndPassword()
                    .setRequestHeader "Content-Type", "application/json"
                    .setRequestHeader "Accept", "application/json"
                    .send
                    sRestAntwort = .responseText
                    sStatus = .Status & " | " & .statusText & " "
                    sStatusCode = .Status
                End With

                If sStatusCode <> 200 Then MsgBox (sStatus)

  		Set xmlHttpRequest = Nothing

  		GetFromJira = sRestAntwort
End Function

В параметр iJiraTask можно передать строку для поиска в jql. Например, запрос “(ID=JIRATASK-1)” вернет выборку, содержащую одну задачу, но если передать условия для поиска – вернутся все задачи удовлетворяющие условиям. Так же можно обратиться напрямую к одной задаче заменив строку «rest/api/2/search?jql=" + iJiraTasks + "&maxResults=500&order by ID"» на «rest/api/2/issue/" + iJiraTask» и в переменной iJiraTask указав ID задачи.

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

								sRestAntwort = GetFromJira("(id = " + JiraID + ")")
                Set parsed = ParseJson(sRestAntwort)
                resA = parsed("issues")(1)("fields")("customfield_14902")
                If IsNull(resA) Then resA = "0"                

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

Применительно к используемой нами реализации было сделано следующее:

  1. Реализовано создание новых задач, с набором дополнительных атрибутов:

    • Дата начала

    • Дата окончания

    • Тип выполняемых работ

    • Информационная система (в какой-то момент у нас в отделе было несколько дорабатываемых информационных систем)

    • Количество запланированных Ч/Ч на задачу

    • Создаются связи с вышестоящей задачей

  2. Реализовано изменение задач в JIRA по запросу из MS Project

  3. Обновление статуса задачи, процента выполнения по задаче в MS Project по запросу в JIRA

  4. Макрос массового обновления всех не завершенных задач в MS Project по запросу в JIRA

В результате процесс работы с задачами приобрел следующий вид:

  1. Поступает запрос на планирование задачи

  2. В MS Project создается план задачи. Пример плана:

  3. После утверждения плана задачи выгружаются в JIRA.

  4. Исполнитель берет задачу в работу, и меняет статус, процент выполнения задачи.

  5. Статус и процент выполнения синхронизируется в MS Project на основании информации из  JIRA.

  6. Если задача не может быть выполнена в срок, либо требуется перепланирование задачи – исполнитель заполняет специальное поле в задаче в JIRA, на основании которого принимается решение о перепланировании.

  7. При необходимости задача перепланируется в MS Project и изменения выгружаются в JIRA.

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

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

P.S. Сейчас я уже в меньшей степени занимаюсь планированием. Когда-то давно мне казалось, что процесс планирования и управления задачами достаточно простая история (практика показала, что это далеко не так). Но при росте количества задач и исполнителей, все сильно усложняется.

Как у вас реализован подход к постановке задач исполнителям?

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