В этом посте я продолжаю описание своего опыта внедрения TFS (Team Foundation Server), начатое здесь, здесь и здесь.
Некоторое время назад появилась необходимость составить отчетность о трудозатратах, которые мы осуществляем при разработке и тестировании задач, выполняемых в рамках работы над выпуском новых версий нашего продукта.
Деятельность наша продукто-ориентированная, а не проектно-ориентированная, поэтому не было необходимости учета и сравнения плановых и фактических трудозатрат - речь шла только о фактических трудозатратах.
На выходе необходимо было иметь отчет следующего вида:
Task name | Development hrs | Testing hrs | Management hrs |
---|---|---|---|
Task 1 | ... | ... | ... |
Task 2 | ... | ... | ... |
Task 3 | ... | ... | ... |
Лирическое отсупление
Перед внедрением учета трудозатрат я опросил несколько коллег, работающих в различных небольших компаниях на предмет того, как у них организован учет трудозатрат. Ответы были следующие: - Учет трудозатрат не ведется. - Учет трудозатрат ведется суммарно по двум направлениям - разработка и исправление багов. Трудозатраты по отдельным задачам и трудозатраты на тестирование не учитываются. - Учет трудозатрат ведется по компонентам разрабатываемого продукта. Трудозатраты по отдельным задачам на учитываются. Практически никто из опрошенных: - не ведет учет плановых трудозатрат - не сравнивает фактические и плановые трудозатраты - не связывает баги с задачами (некоторые вообще для задач использует один инструмент, для ошибок - другой) - не суммирует время, потраченное на исправление ошибок, к задаче, к которой относятся данные ошибки (у многих вообще нет разницы между задачами и ошибками). |
Для того, чтобы организовать учет времени по выполняемым задачам мне пришлось добавить в task два поля - DevelopmentHours и TestingHours.
Эти поля были предназначены для учета фактических трудозатрат на разработку и тестирование и при создании задач автоматически устанавливались равными нулю.
Требовалось сделать так, чтобы при переходе task'а из состояния Active в Completed разработчики должны были указать задать значение поля DevelopmentHours.
Аналогично при переходе из состояния Completed в Closed или обратно в Active тестировщики должны были указать значение TestingHours.
При чем, просто добавить правило REQUIRED было бы недостаточно, потому что задача могла многократно переходить из одного состояния в другое в процессе тестирования и исправления и каждый необходимо было указывать новое значение DevelopmentHours или TestingHours, а правило REQUIRED не могло бы этого обеспечить - оно бы стало только лишь гарантировать присутствие значение как такового, даже предыдущего, а не нового.
Для решения задачи пришлось использовать правило NOTSAMEAS, которое сравнивает значение поля со значением другого поля и если они совпадают, то не позволяет сохранять задачу. В качестве второго поля должно было бы выступать предыдущее значение DevelopmentHours или TestingHours в зависимости от ситуации. Поскольку в задаче сами по себе предыдущие значения не хранятся, пришлось добавить еще два поля, которые пользователю не видны и которые используются для хранения предыдущих значений - DevelopmentHours2 и TestingHours2.
Эти поля автоматически заполняются с использованием правила COPY значениями полей DevelopmentHours и TestingHours при сохранении задачи.
Таким образом, когда у разработчика возникает необходимость изменить статус задачи с Active на Completed у него значения полей DevelopmentHours и DevelopmentHours2 совпадают и он не может сохранить задачу, пока не изменит поле DevelopmentHours. При сохранении задачи новое значение DevelopmentHours копируется в DevelopmentHours2 и они снова становятся одинаковыми, чтобы в следующий раз вновь обеспечить необходмость изменения поля DevelopmentHours.
Выглядит это так:
Для TestingHours и TestingHours2 все работает абсолютно аналогично, но только при переходе из состояния Completed в Closed или обратно в Active.
Таким образом разработчики должны каждый раз указывать новое значение поля DevelopmentHours, а тестировщики - TestingHours.
При переходе из состояние Active в Closed никаких проверок я добавлять не стал - т.е. задачу можно просто закрыть и все, если она, например, была отменена.
Учет времени по ошибкам я организовывать не стал, поскольку это, как мне кажется, стало бы отнимать слишком много времени само по себе.
Однако, для того, чтобы более точно учитывать время по задачам, я договорился с тестировщиками, что они, при проверке задач, будут всегда стараться в первую очередь зафейлить задачу, нежели создавать новый баг.
Кроме того, я договорился с архитектором, что он, при завершении архитектурного анализа будет также выставлять свое в время в поле DevelopmentHours.
Еще, было рекомендовано всем не пытаться оценить точное время, а ставить время приблизительное, при этом стараясь его несколько завышать для учета выпадающих расходов - консультаций с другими разработчиками и т.п.
Отчетность.
Для организации отчетность в TFS используется технология Reporting Services.
Открыть Диспетчер отчетов можно через портал проекта, а можно прямо из Visual Studio:
Для создания отчета пришлось использовать Visual Studio 2008 - в Visual Studio 2010 подходящего типа проекта почему-то не оказалось.
Для создания отчета необходимо создать проект типа Report Server Project, в котором создать .rdl-файл, являющийся описанием требуемого отчета.
В качестве источника данных была указана хранимая процедура, которая возвращала список work item'ов с типом task, так как только для них был организован учет трудозатрат.
При написании запроса к базе TFS было установлено следующее:
1. Все work item'ы хранятся в таблице WorkItemsAre. Тип при этом хранится в поле [Work item Type]. Т.е. если вы хотите выбрать все задачи, то можно написать такой запрос:
select *
from WorkItemsAre
where [Work item Type] = 'task'
2. Все поля (в том числе и добавляемые дополнительно) хранятся в таблице Fields. Дополнительно создаваемые поля имеют в данной таблице FldID начиная с 10 000.
При этом имя поля из таблицы WorkItemsAre составляется так - Fld + FldID поля из таблицы Fields.
Для примера, :
Поле DevelopmentHours в таблице Fields имеет FldID = 10133.
Соответственно его значение хранится в таблице WorkItemsAre в поле Fld10133.
Таким образом сначала определяем имя поля из таблицы Fields, а потом делаем составной запрос к таблице WorkItemsAre.
Т.е. примерно так:
declare @FieldName varchar (255), @q nvarchar (4000)
select @FieldName = 'Fld' + CONVERT (varchar (255), FldID)
from Fields
where ReferenceName = 'ROI.DevelopmentHours'
set @q = 'select ' + @FieldName + '
from WorkItemsAre
where [Work item Type] = ''task'''
exec sp_executesql @q
Таким образом можно определить и выбрать практически все интересующие поля.
Тип полей при этом совпадает с типом поля, заданном в TFS.
Используя хранимые процедуры можно написать практически любой запрос на получение данных из таблицы work item'ов, что и было сделано.
P.S.
Другие мои посты на тему TFS:
1. Миграция в TFS (Team Foundation Server)
2. Кто ошибку создает - тот ее и проверяет?
3. Нумерация версий продукта в TFS (Team Foundation Server)
4. Учет трудозатрат и отчетность в TFS (Team Foundation Server)
5. Как создать work item в TFS (Team Foundation Server) из письма в Outlook
6. Как поместить свой control на форму Work Item в TFS (Team Foundation Server)
7. Как настроить номер итерации по умолчанию в TFS (Team Foundation Server)
Комментариев нет:
Отправить комментарий