Документальный ролик о тесном взаимодействии пользователей программ и разработчиками. Когда пользователь испытывает боль за сбой программы у него есть возможность поделиться этой болью с программистом.
Нечестно, что только программист разделяет боль за некачественное решение. Отдел качества должен быть на передовой взаимодействия с заказчиком. После непродолжительной беседы по чату с Виталием Стаховым, мы решили, что и это не совсем верно. Поэтому предложена схема: клиент разделяет боль с тестером, тестер с программистом. Но стал вопрос, а с кем разделяет боль программист? И поняли, что с аналитиком. А аналитик? С пользователем! Круг замкнулся!
Хитрее всех в данной ситуации находится одна фигура. Эта фигура часто орёт на собраниях, что у него "огромная ответственность перед всеми", и поэтому кстати он получает больше всех денег. Но почему то он выпал из раздачи. Кто это? Конечно же менеджер.
После рассуждений мы поняли. Боль должна разделятся по объёму ответственности. А абсолютная ответственность как выяснилось у менеджера. Поэтому схема упростилась: клиенты, программисты, тестеры, аналитики пинают менеджера.
И это правильно!
пятница, 29 мая 2009 г.
Share the pain : система мотивирования
на 12:57 0 коммент.
Ярлыки: мотивация, человеческий фактор, Management
среда, 27 мая 2009 г.
Ретроспектива решает конфликты
В предыдущем посте я говорил, что инструмент ретроспективы может быть заимствован и развит до немыслимых высот. Если вы хорошо владеете этим инструментом, ваша зрелость растёт гигантскими шагами.
Пару слов о конфликте. Конфликт - это когда точки зрения не совпадают и мы начинаем подключать эмоции, а по сути никуда не двигаемся. Если посмотрите мои посты про эмоции - то знайте - это вы подключили своё подсознательное. Теперь вы стали сильнее и мудрее, когда включили эмоции. Единственное нужно уметь управлять подсознательным (эмоциями). Это умение управлять эмоциональным интеллектом. Подсознательное через эмоции подсказывает - работаем неэффективно. Теперь понятно, что работаем неэффективно, то есть обсуждения зашли в тупик. И это можно оценить по уровню эмоций.
Следующий шаг - остановится и задуматься, выйти из ситуации и посмотреть на это со стороны. А чтобы не париться про психологию конфликта и тактик поиска решений, просто сделайте ретроспективу на то, как вы обсуждали только-что. Оказывается открывается множество перспектив :)
Упрощёная схема:
1. Конфликтная ситуация.
2. Остановится
3. Понять свои эмоции.
4. Найти причину (см. технику)
5. Провести ретроспективу на то КАК вы обсуждаете, а не ЧТО вы обсуждали.
Секретная техника действует! Люди меняются и культура разработки растёт!
Приятной ретроспективы!
на 22:52 0 коммент.
Ярлыки: человеческий фактор
понедельник, 25 мая 2009 г.
Эволюция культуры команды - ретроспектива
Как я отличаю аджайл команду от не-аджайл? По наличию одной лишь практики - "Ретроспектива". Мне не достаточно сказать - у нас есть она. Я должен увидеть как происходит это таинство. У меня в загашнике есть ряд критериев по которым определяю качество "ретроспективы". Может быть когда-нибудь напишу :)
Сегодня хотел чуток о другом. Я просто несказанно рад, что Дмитрий у себя на блоге описал эту штучку (ссылка). И этот пост воодушевил закончить находящийся в черновике пост про ретроспективу. Асхат подхватил эстафету про ретро. Рекомендую зайти - ссылка.
Продолжать чтение моего поста нужно после чтения поста Дмитрия.
Я привык использовать облегчённый вариант ретроспективы. Я за упрощение во всем её многообразии. Мои ретроспективы просты по структуре
1. ХОРОШО
2. УЛУЧШИТЬ
3. ИДЕИ
Народ интересуется, почему же есть пункты "Хорошо", "Улучшить" и "Идеи", но нет "Плохо" ) Весь сыр бор вокруг пункта 2. Он показывать отличие в психологии проведения ретроспективы. Готовы ли на свершения (которые оформляются Action-планом, который я забыл упомянуть), или просто "вздыхатели" :)
Для русского менталитета пункт 2 должен быть "ПЛОХО". Для европейского - "УЛУЧШИТЬ".
Разница грандиозна. Во-первых, описать "ПЛОХО" нужно 1 мозго-силу. Констатируем факт и мы в шоколаде. Для описания "УЛУЧШИТЬ" нужно 2 мозго-силы. Первая для описания "плохой" ситуации, а вторая мозго-сила для предложения пути как исправить. Вот и получается пункт "УЛУЧШИТЬ" это посложнее, чем "ПЛОХО.
Во-вторых, "ПЛОХО" характеризует натуру, которая больше любит жаловаться, а не решать проблемы. "УЛУЧШАЮТ" в эффективных коллективах, когда идентифицируют неэффективное поведение, ситуацию и ставят задачи по улучшению. Игра слов. Но все же обращу внимания: жалуются - решают, проблемы - задачи. Можете подумать на досуге к какому поведению приводят две эти стратегии, если ими руководствоваться по жизни.
В общем народ можно разбить на две большие группы по этому критерию. Первая - кто ищет оправдания (для них в ретро нужен пункт ПЛОХО) и другая группа, кто ищет возможности (для этих нужен пункт УЛУЧШИТЬ).
А если получается много "УЛУЧШИТЬ" и улучшения достигаются. Это развивает команду. Команда за счёт "УЛУЧШЕНИЙ" изменяется, изменяется её культура.
И последнее, проведение ретроспективы это формализованная обратная связь на событие. В аджайл принято давать фидбэк раз в итерацию. Можно пойти дальше и это приносит грандиозный успех. Попробуйте проводить ретроспективу после:
- любого митинга
- во время конфликта
- после обсуждений
- после любой презентации
- после тренинга, и даже после каждого дня тренинга
- после встречи с заказчиком
- когда вы сделали что-то значимое, как способ поделиться
и много других
на 13:09 2 коммент.
Ярлыки: управление знаниями, Management
четверг, 21 мая 2009 г.
Секреты построения команды (Team Building)
Использование практик Agile позволяет эффективно управлять созданием продукта. Но создание команды и динамика построения команды в Agile освещены не очень хорошо. В предлагаемом подкасте я рассказываю о практиках, которые ориентированы на развитие командных отношений и повышение эффективности работы. Весь подход состоит из четырёх этапов:
1. Развитие эмоционального интеллекта
2. Коллективное принятие решений
3. Интеграция личных и командных целей
4. Общее видение
Все секреты одним файлом:
на 16:12 0 коммент.
суббота, 16 мая 2009 г.
Null Object и синтаксический сахар C#
public interface Null
{
}
internal class NullWord : Word, Null
{
}
if(word is Null)
Без комментариев. Красотища! :)
Использованы паттерны: NullObject и Marker Interface
Подробнее: http://agile.rpod.ru/109024.html
на 17:58 1 коммент.
100% Coverage Driven Design (CDD) - борьба с тухлым кодом
Всем известно, что для качественного ПО покрытие должно быть более 70%. Я не знаю, кто это придумал и причем тут качество, но мне не понятно какая польза от этой цифры. Ещё смешнее слышать, как менеджеры привязывают покрытие к качеству. Если рассуждать в плоскости менеджеров, что и на мелководье и рак рыба, то этого качества конечно же для успокоения самолюбия менеджера достаточно. Но истинные войны света должны понимать, что на этом качество не останавливается... Качество кода - это целая культура разработки, в которую вовлечены клиенты, разработчики, тестировщики и много других людей. Но об этом я уже писал неоднократно, а сегодня остановлюсь на новом подходе. Подходе дающим ещё один мощный инструмент разработчику (ни менеджеру, ни тестировщику) для написания качественного кода.
Я же хочу раскрыть другую замечательную вещь, которая повысит качество кода во много раз. Один нюанс - вам придётся делать 100% покрытие :)
Эту идея пришла во время парного программирования с Кириллом Медведевым в рамках одной из стади-групп.
Эту разработку я называл "100% Coverage Driven Design" (или сокращённо CDD). Суть этого подхода есть сложение TDD, общего подхода написания тестов (ключевая фраза здесь - TestLast) и инструмента покрытия кодом.
Напомню цикл TDD:
1. Пишем тест (формализуем ожидания от будущего кода)
2. Реализуем код
3. Рефакторим
В "100% Coverage Driven Design" цикл такой:
1. Тест
2. Код
3. Рефакторим
4. Добиваемся 100% покрытия
Какие бонусы даёт такой подход
1. Все бонусы TDD
2. Вы всегда контролируете, что ваш код используется и нету лишнего, мертвого, того кода, который будет тухнуть из-за дня в день. Покрытие будет следить, как только что-то лишнее появляется и не используется - сразу выкидываем.
Возникает вопрос. А что делать с тестами, которые устаревают. Ведь их с помощью покрытия нельзя выявить, а тем более сказать что код, который покрывается устаревшими тестами уже начинает потухать. А решение простое - смирение. Если тест устарел, то первым делом он начинает из зеленого превращаться в красное. И вы тут же решаете, что с ним делать. В красное он может превратиться по множеству причин. Но если одна из причин - устаревший и ненужный тест. Мы его удаляем. Запускаем Code Сoverage и проверяем, где произошли смещения от точки 100% покрытия.
Покажу на маленьком примере. С помощью TDD цикла создали библиотечку. Проверили её покрытие и выяснилось не 100%. Начинаем разбираться и видим, что появился тухлый код. Сначала комментирую тухляк, а потом лопатой все убираю.
Успешно справившись с продуктами собственной жизнедеятельности (удалив тухлятину), я сталкиваюсь с автогенерённым тухляком:
Мне приходиться напрячь мозги и понять, что components объект никогда и не используется! Такое открытие позволяет мне удалить столь запутанную тухлятину тоже.
Результат не заставляет ждать. Идеально чистый код! Я с уверенностью продолжаю дальнейшую разработку.
Теперь немного GUI-шного, про разработку через TestLast и как техника рефакторинга приводит ухудшению Code Coverage.
1. Конечно же, когда добавляется новый функционал, то используем TestFirst:
public void MainForm()
{
SetUpClass.PrepareTestFile();
var form = new MainForm();
var mocks = new MockRepository();
var dialog = (OpenFileDialog)mocks.CreateMock(typeof(OpenFileDialog));
Expect.Call(dialog.FileName).Return("filename.ew");
Expect.Call(dialog.ShowDialog()).Return(DialogResult.OK);
mocks.ReplayAll();
form.openFileDialog = dialog;
form.MenuItem_Open(null, null);
mocks.VerifyAll();
Assert.AreEqual(2, form.dicGridControl.Count);
}
2. Реализуем функцию
public void MenuItem_Open(object sender, EventArgs e)
{
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
Dic dic = new Dic();
dic.Load(openFileDialog.FileName);
dicGridControl.Bind(dic.ToList());
}
}
Покрытие: 100%
3. Проводим рефакторинг Replace Nested Conditional with Guard Clauses (кстати, мой самый любимый)
public void MenuItem_Open(object sender, EventArgs e)
{
if (openFileDialog.ShowDialog() != DialogResult.OK)
return;
Dic dic = new Dic();
dic.Load(openFileDialog.FileName);
dicGridControl.Bind(dic.ToList());
}
Покрытие: 97%.
Проведение рефакторинга привело к снижению покрытия. Мы столкнулись с усложнением кода с точки зрения поддержки покрытия. Но в тоже время облегчили с точки зрения понимания, сделав линейность выполнения основного блока. То есть основной блок в первом примере разбился на два: проверка условия выполнения и основной код.
В общем снизили покрытие. Что делать. Я останусь верным принципам рефакторинга и оставлю проверку входного условия. Но я должен дотянуть покрытие до 100%. Тут на помощь приходит старая практика Test Last. Если раньше, эта техника была вызвана сообращениями разработки тестов для уже разработанного кода, сейчас эта техника изменит своё предназначение. Используя эту технику я подтяну покрытие до 100%.
После мелких рефакторингов я добавил второй тест, используя технику TestLast:
[Test]
public void MainFormCancel()
{
Expect.Call(dialog.ShowDialog()).Return(DialogResult.Cancel);
mocks.ReplayAll();
form.MenuItem_Open(null, null);
mocks.VerifyAll();
Assert.AreEqual(0, form.dicGridControl.Count);
}
Результат: покрытие 100%
В данном случае проведение рефакторинга не очень оправдано - так как и с ним и без него код выглядит очень простым и его можно сразу понять. Я преследовал цель показать , как рефакторинг может привести к снижению покрытия кода, даже если он прошёл без изменения функциональности.
Другой нюанс, если я пойду дальше и подстрахуюсь от проблем с файловой системой:
public void MenuItem_Open(object sender, EventArgs e)
{
if (openFileDialog.ShowDialog() != DialogResult.OK)
return;
try
{
Dic dic = new Dic();
dic.Load(openFileDialog.FileName);
dicGridControl.Bind(dic.ToList());
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
Этот кусочек кода пишется даже без теста легко. Я нарушил правило TDD и добавил строчку кода без теста. И кара настигла меня моментально - покрытие упало, плюс протестировать статический метод MessageBox.Show - это целая проблема (ни моки, ни что либо другое здесь не поможет - в морг). А представьте сколько проблем мы делаем, когда разрабатываем более менее серьезное приложение?
Что хотелось бы иметь в инструментах покрытия:
1. Механизм разметки - какие функции все же не стоит покрывать. Например, автогенерацию или какие-то ничего незначащие хитрые кейсы.
2. Историю покрытия, чтобы наблюдать диффы. Это понадобилось бы для работы над легаси-системами. В таких системах, если мы начинаем разрабатывать по TDD большая часть кода будем мешать нашему анализу. А анализ диффов позволил бы использовать этот подход даже там.
Вывод: Данную методику изобрёл буквально вчера. За вчера её опробовал, очумел от эффективности и продолжаю праведно работать по ней. Методика 100% покрытия стала для меня точно так же как запускать юнит тесты. Стала родной и без неё уже свет не мил. Теперь не то чтобы у меня тесты есть согласно TDD, но и код очищается от мертвого кода очень удобно и легко. Теперь я не только уверен в функционировании (этому мне помогает TDD), но и что код чистый (этому помогает 100% покрытие). В общем я доволен как маленький ребёнок от такой простои и в тоже время мощной игрушки. Сейчас нарабатываю опыт от применения, о чем буду делиться и буду ждать последователей, кто готов проверить предложенный метод.
на 15:52 4 коммент.
Ярлыки: Качество кода, Code Coverage, TDD