7/22/2010 4:52:51 PM

Давно, очень давно собирался написать что-то на эту тему, но всё никак не формировалось. Не формируется и сейчас, поэтому просто мысли.

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

Очень часто, к сожалению, люди путают “просто” и “сложно”. То есть, когда они что-то делают “просто”, то получается в результате “сложно”.
Почему так получается? Да просто потому, что это самое “просто” изначально определено неверно в их головах.

Люди ведь как думают? Они думают, что “просто” – это когда не надо думать, не надо “париться”, бац – и сделал. Ну, вы понимаете, сделать “просто”, “по быстрому”. Потом спрашиваешь: отчего такая фигня получилась? А они в ответ: “ну, хотелось просто сделать”.
То есть, такой себе эгоистический достаточно подход получается: человек делал “просто”, и пока он делал, ему, возможно, и было “просто”, он не думал, он спустя рукова (если не мозг) работал, но вот всем остальным потом.. Им же ведь иметь дело с результатом. А результат в этом случае далеко не прост выходит. Он по большей части получается невнятный, запутанный, многосмысленный результат-то.

Правильное понятие о простоте, я думаю, должно складываться именно из результата.
Вот я прихожу, смотрю на код – а его так просто поддерживать и изменять, что ну никаких проблем с этим не возникает. Всё разложено по полочкам, разобрано по смыслам, не допускает двойных толкований. Легко читать, легко понять, что имеется в виду.
Вот это – просто. Я и коллеге скажу: “да там всё просто написано, сразу всё понятно”.
И это вовсе не означает, что человек, который писал этот код, не прилагал усилий. Это в 99% случаев означает совершенно обратное, кстати.

Я вижу результат, работать с которым мне просто. И я стараюсь, на основе него, делать свои какие-то результаты, с которыми и мне в дальнейшем, и другим людям тоже будет просто.

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

Поэтому.. Пожалуйста, когда в следующий кто-то предложит, или сами решите сделать что-то просто, вы уж не поленитесь Smile

7/13/2010 1:14:13 PM

Читая Мишины отзывы и ссылки, думал тут про тестеров.
Там кто-то говорит про "плохих" и "хороших" программистов и тестеров, кто-то объясняет, что программисты делают "тяп-ляп" потому, что "типа тестер всё равно проверит", а тестеры типа относятся к программерам как к "багоделам".

Это показалось мне странным, я думал-думал и пришёл к такому вот выводу: что-то тут не так :)

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

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

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

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

Тестер для программиста никогда не должен быть некой сущностью, которая проверяет домашнее задание непоседливого школьника, указывая на недостатки и недоработки. А школьник этот вертится на стуле и стремится поскорее “ответреться”. А если тут ещё ПиЭм неправильный, который типа контроллирует и типа требует результата – то и вообще атас (это я всё о том же).

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

Такой подход + отсутствие персонального владения кодом (я не помню, писал про таковое, или посчитал очевидным, но это – Изначальное Зло, если оно есть в команде – срочно искоренять, а тех, кто это устроил – линчевать) ведут к естественному и правильному взаимодействию тестеров и программистов, которое выражается… в отсутствие персонального взаимодействия Smile

То есть, я не имею в виду, что тестеры с программистами не общаются, вовсе нет. Общаются, и ещё как! Но это общение вида: я делаю фичу, или чиню баг, у меня есть вопрос, я пошёл к тестеру и попросил объяснить, как это должно работать, или как это воспроизвести, или что-то ещё.
Но это не взаимодействие типа “я напишу, а я проверь там” и “я проверил, ты там доделай”.

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

11/18/2009 9:52:42 PM

Интересно здесь. Не то, чтобы совсем, но неожиданно.

Майкрософт объявили направление: веб-приложения, которые (одинаково) доступны на лаптопах, десктопах и мобильных устройствах.
Основной платформой (по крайней мере для UI) объявлен Сильверлайт.

И вот тут начинается интересное, с анонса Silverlight 4.
Silverlight 4 содержит очень много замечательных вещей, начиная с drag-n-drop и заканчивая тем, что теперь он может работать вне пределов браузера, как нормальное приложение.
При этом его можно назначить trusted – и он может иметь доступ к железу, файловой системе, другим веб-сайтам и сервисам, да мало ли.
Например, внутри сильверлайта можно запускать всякие другие вещи. В качестве примера – adobe flash. Ребята запускали youtube на демо.

В общем, похоже, сильверлайт придётся осваивать.

P.S.
Сижу сейчас на секции, посвящённой будущему программирования. Докладчики – их пятеро – рассуждают.. о чём бы вы думали? О распараллеливании, о том, что в функциональных языках этих проблем нет и о том, как с этим быть :) Проблема серьёзно назрела.

11/17/2009 9:41:00 AM

Сегодня весь день слушал workshop по паттернам параллельного программирования.
Мероприятие состояло из трёх частей.

В первой части нам подробно рассказали зачем именно и в каком виде нужно “параллелить”. Какие бывают виды распараллеливания и т.п.
Это была самая сложная часть. В том плане, что я за ночь спал часа три только (а нечего было в самолёте высыпаться), только к утру уснул. Так что жутко хотелось спать. А так как о проблемах параллельности, мультиядерности и т.д. я уже много раз думал, и даже в этом блоге писал три года назад практически то же самое, что они сегодня говорили, то нового для меня в этой части было крайне мало, приходилось буквально заставлять себя держать глаза открытыми и открывать их, если всё же закрылись.

Хотя и из этой “философской” части несколько вещей показалось интересными:

  1. И Майкрософт, и Интел признают, что “затык” и проблема производительности сейчас лежит не на уровне “железа”, а на уровне софта. Представитель Майкрософт сказал прямо со сцены: виноваты мы с вами (все разработчики): мы просто не используем оптимально тех возможностей, которые даёт нам “железо”. А оно без проблем (и даже с меньшими затратами) может дать больше.
  2. Количество транзисторов в каком-нибудь Итаниуме отличается от количества транзисторов в Пентиум-4 примерно в 100 раз.
    Это значит, что вместо того, чтобы выпускать всякие Итаниумы на 2-4 ядра, Интел с тем же успехом и на том же количестве транзисторов мог (и может) выпустить процессор содержащий 100 ядер Пентиума-4. Про 80-ядерный процессор от Интел, впрочем, я тогда же писал.
    Если отвлечься от существующих проблем с софтом и вообразить, что мы можем их равномерно нагрузить – отдача во многом была бы куда лучше, чем от того Итаниума. Но такой процессор не выпускают потому, что мы сейчас не знаем, что с ним делать. Потому, что мы писали и продолжаем писать “однопоточный” софт. Поэтому Интел вынужден делать достаточно малое количество ядер (несколько-то потоков мы всё же делаем, да и несколько приложений одновременно запускаем), продолжая изголяться с частотой и другими параметрами.
  3. Но подвижки всё-таки есть: гибридные ядра вот уже появляются (это когда из четырёх ядер два “нормальные”, а ещё два состоят из микроядер, соотношение может быть 1:3 или 3:1, а могут и все 4 микроядерными быть). А это в свою очередь означает уже совсем другое количество потоков (посчитайте, по два на [микро]ядро хотя бы). Ну и количество ядер растёт – 8 есть, 16 ожидается.
  4. Софт, который пишется сейчас, скорее всего расчитывает продержаться на рынке пару-тройку лет. Даже с такими темпами роста прикиньте, то, что Вы пишете сейчас, способно ли эффективно использовать возможности процессоров, способных исполнять 128-256 нитей в параллели?
    Сколько Вы используете в своём приложении? Максимум три? Вам не кажется это смешным? То, что Ваше приложение будет точно так же тормозить на любой машине? Может пора перестать “изголяться” и пора начать думать и писать “нормально”? :)
    А ведь всё равно каждый, кто прочитает, через 10 минут откроет Visual Studio и продолжит клепать однопоточный код, подумал я. Ибо так проще и думать не надо. И это проблема.
  5. В Майкрософт серьёзно занимаются этой проблемой. Из тех примеров, что я помню: Visual Studio 2010 (которая сама написана на .NET с WPF-интерфейсом) очень активно использует Task Parallel Library (TPL), включёную в .NET 4.0 теперь. Это далеко не единственный пример был, просто я не проспал и запомнил :)

Да, про распараллеливание был ещё хороший пример приведён: докладчик показал последовательно три картинки. На первой был изображён молоток, на второй – воткнутый в доску гвоздь, на третьей – белка. И сказал замечательную фразу: “Когда у Вас в руках молоток, всё вокруг кажется гвоздём. Но не с точки зрения белки.” :)
Сказал он это к тому, что “мы дадим вам молоток, в виде TPL, OpenMP, F# с его immutable типами и т.д, но пользоваться им надо тогда, когда это имеет смысл и так, как это имеет смысл делать”.
По-русски это можно перевести как “дурная голова ногам покоя не даёт” и сказать, что броситься и заменить во всём приложении for на Parallel.For, а IEnumerable на IEnumerable.AsParallel() и “с чистой совестью” думать, что задачи распараллеливания выполнены – глупо.

Вторая часть была гораздо более интересной. Она была дивелоперской.
Человек, который непосредственно из команды разработки TPL, сделал отличный доклад, практически не имея слайдов презентации. Вместо этого он просто открыл Visual Studio и показывал, как делать нужно, как можно, как не нужно, что работает, что нет… Отлично объяснял почему именно и как оно работает, отвечал на вопросы, иллюстрируя ответы тут же кодом, запуская его и демонстрируя результат.
Мне понравилось.
Так, как тема была “паттерны параллельного программирования”, он объяснил, какие паттерны используются при разработке таких приложений, что эти паттерны из себя представляют, как они реализованы в TPL и как пользоваться этой реализацией.

Книжку по этим паттернам можно свободно скачать вот тут: http://www.microsoft.com/downloads/details.aspx?FamilyID=86b3d32b-ad26-4bb8-a3ae-c1637026c3ee&displaylang=en

Третья часть была посвящена Microsoft Windows HPC.
Мне она показалась малоинтересной, за исключением того, что я вообще узнал, что у Майкрософт есть такая версия системы, как HPC. Более того, ожидается вторая версия.
HPC – это аббревиатура от High Performance Computing, а операционная система расчитана на кластеры с большим количеством нод. Текущая версия поддерживает до 256 машин в кластере (я так понял, что не важно, сколько у каждой сокетов и ядер), вторая версия (R2 они теперь взяли моду всё называть) будет поддерживать толи тысячу, толи тысячи, я не понял. Но это всё равно много.
Оттуда можно WCF-сервисы “наружу” выставлять, обработка будет вестись на кластере (или куске кластера, как захочется). И они там тоже использовали те же паттерны параллельного программирования, хотя и без использования TPL, а гораздо на более низком уровне.

Это был просто workshop. Завтра начинается PDC.
Looking Forward.

P.S. Лос Анджелес удивил. Ладно мне коллега и босс говорили, что опасный город, я думал – австралы, не местные, побаиваются. Но когда сегодня обедал с одним местным, он открыл карту метро, провёл пальцем по половине города и сказал: “сюда вообще не надо ездить и выходить на этих станциях”… И потом когда тебе говорят “я в ЛА не использую общественный транспорт, у меня семья, дети, работа, я перемещаюсь или на машине или на такси” – это уже не просто настораживает ;)

8/4/2009 4:46:08 PM

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

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

Удивляться я буду нескольким вещам. Во-первых, как так – программист не хочет, чтобы его код тестировали? Может он еще и код-ревью проходить не хочет?? (шутка).
На самом деле, конечно, программист в тестировании заинтересован. Ибо это – вариант спихнуть часть работы на кого-то. Ведь в противном случае код либо придётся тестировать самому, либо краснеть за глупые баги в релизе.
Тестировать самому для программиста – пытка. К тому же, программист, я считаю, просто неспособен нормально протестировать приложение. Во-первых, он уже просто подсознательно производит действия, которые являются правильными. Например, программисту не придёт в голову полезть в XML-файл с данными, руками поправить там что-то, а потом попытаться с ним работать. Или заполнить весь жёсткий диск и посмотреть, как будет вести себя приложение при попытке автоматического сохранения состояния. А тестеры это делают (реальные примеры, это нас в Алкателе тест-команда такими вещами удивляла).
А во-вторых, он в основном не является конечным пользователем продукта и поэтому не в состоянии оценить и отработать нормальное пользовательское поведение, с чем тоже выходят иногда курьёзы.
Ладно, расскажу один – и пойдём дальше :)

На прошлой работе делали мы вторую версию некого существующего инструмента, в котором была интегрирована *nix-консоль. Консоль эта использовалась там для отображения прогресса того, что происходит на удалённой машине. Цветная вся такая.
И вот в один прекрасный день приходит нам толи от одного из пользователей, толи от тестеров пожелание: дескать, консоль эта работает нестабильно в такой-то ситуации, внимание, если вводить там команды. Типа, поправить бы в новой версии.
Упс, подумали мы и спросили тимлида. Он удивился и сказал: консоль точно не предназначалась для того, чтобы что-то в ней ещё вводить! Даже непонятно, как это можно сделать: она ж read only!. Решили узнать в другой команде, которая занималась написанием самой платформы. Тимлид ушёл, через пару минут вернулся с круглыми глазами. Рассказывает: подхожу к тамошнему инженеру, спрашиваю – команды вводишь в консоль? Ага, ввожу, говорит! Очень удобно – если что-то свалилось – тут же подправил, не надо логиниться, окружение поднимать! Только, говорит, я думал, что я один это знаю. И да, говорит, а можно подправить заодно, чтобы оно не падало? :)
Оказывается, в случае ошибки, когда вывод в консоль останавливался, она толи переключалась в том инструменте из режима read only, толи какую-то комбинацию клавиш нужно было нажать… Сейчас не помню, а исходников первой версии никто не видел, да и смотреть не хотел :) Но каким-то образом это сокральное знание расползлось по всему зданию (а может и дальше) и достаточно много чуваков пользовались такой фичей, считая, что они одни знают как это делать. И никто не жаловался на баги, потому, что знали, что это типа хак.
Вот так хак стал требованием :)

Помимо же явной заинтересованности я не вижу, как программист вообще может повлиять на процесс тестирования. Ну, разве что там существует какой-нибудь “руководитель”, с которым можно договориться, и который “волею, данною мне…” прикажет тестерам не тестировать определённый функционал ;) Другого пути я не вижу…

Расскажу про жизненный цикл разработки и место тестирования в нём на примере нашего веб-проекта.

Что мы имеем:

  1. Основную ветку (Trunk) в системе контроля версий (про ветки я уже писал: Про бранчи);
  2. Main Build с Main Build Agent – определение автоматического билда для интеграции и проверки кода;
  3. UAT Build с UAT Build Agent – определение автоматического билда для UAT;
  4. UAT Environment – неполный комплект серверов + база данных UAT (неполный потому, что всех типов серверов по одному);
  5. Staging Environment – полный комплект серверов + staging база данных (полный потому, что зеркалирует следующую конфигурацию);
  6. Production Environment – полный набор;

Что происходит:

  1. В соответствии с принятым в команде соглашением, любой новый функционал разработчики делают в отдельных ветках. Забавно: ветки обычно называют шуточным именем своей sub-команды или названием фичи, которую делают. Например, у нас была ветка “Team3G”, ветка “Old Skool” и ветки типа “FormPropsRefactoring”, etc.
  2. Когда новая функциональность готова, делается merge в Trunk.
  3. Каждый check-in в Trunk автоматически запускает Main Build, который забирает код из системы контроля версий, собирает его в релизной конфигурации и прогоняет юнит-тесты. Если что-то пошло не так, то он (Main Build) начинает паниковать и слать письма о том, что в результате такого-то check-in таким-то пользователем код перестал собираться и тесты не проходят.
  4. Ночью, а конкретно в 3:30AM, по расписанию срабатывает UAT Build. Этот зверь суровее: он тоже берёт последнюю версию, собирает и запускает юнит-тесты. Если всё прошло успешно, то он минифицирует и комбинирует javascript/css, автоматически заливает новую версию продукта на все UAT-серверы, синхронизирует базу данных (об этом тоже писал: Синхронизация баз данных), выполняет ряд служебных функций. После этого UAT готов к работе.
    В случае невозможности обновления UAT паники больше: письма идут и разработчикам, и тестерам, и менеджерам, которые используют UAT для “а! они это сделали! хочу посмотреть!”, и специалистам по требованиям (не буду называть их ПиЭмами, чтобы не было путаницы: они программистами не руководят).
    UAT Build может быть так же запущен руками любым членом команды в случае какого-то срочного багфикса или просто по договорённости с тестерами.
  5. У тестеров есть какая-то своя тулза или планировщик, который, насколько мне известно, запускает ночью автоматизированные веб-тесты. Они хвастались, что у них уже в районе 400 веб-тестов есть. Ну, это которые умеют работать с продуктом в браузере, извне. Логинятся, делают там чего-то.
  6. Утром приходят тестеры. Хитро ухмыляясь они смотрят на то, как прошли веб-тесты. Потирая ладошки они смотрят на ряд задач, которые были программистами помечены как законченные (Done). Закончен – значит ночью попал в UAT, думают они, щас мы его… И приступают к своей работе.
    Здесь я должен отметить: хочет программист, или не хочет программист, статус Closed задаче может поставить только тестер. И сделает он это только тогда, когда лично убедится, что штука работает. Ведь под статусом будет стоять его фамилия ;) Шучу. Но фамилия стоять будет. Если же штука не работает, то тестером в системе регистрируется баг, которому присваивается приоритет – и пошёл в работу. А задачу обратно в статус невыполненных.
  7. Когда тестеры довольны тем, что происходит на UAT и когда пришло время по мнению специалистов по требованиям, протестированный продукт заливается из UAT на Staging. Там – копия реальной конфигурации. Там работают маркетинговые ребята, там проводятся демонстрации. Там же работают бета-пользователи. Там же продукт тестируется снова для того, чтобы убедиться, что всё будет работать в production. Разработчики туда доступа уже не имеют.
  8. Когда все довольны тем, как работает staging, код из него переносится в production.

Вот и всё. В идеале перед пунктом 2) должен идти пункт 1.5), в котором будет сказано: “Когда разработчики считают, что задача выполнена, устраивается код-ревью изменений, внесённых в ветку”.

Отсюда видим:

  • Разработчик никак не может повлиять на то, кем, как и когда будет тестироваться его код. Лично я – не могу :)
  • Код обязательно будет протестирован, так как он выполнен в рамках какой-то задачи, а задача может быть закрыта только тестером.
  • В случае, если задача выполнена не полностью с точки зрения тестера, она будет возвращена команде разработчиков обратно, плюс может быть зарегистрирована дополнительная задача-баг, имеющая собственный приоритет (так, основная задача может иметь низкий приоритет, но если в результате её имплементации пострадало что-то другое, тестер может присвоить высокий или даже критический приоритет багу).
7/31/2009 6:55:07 AM

Михаил затронул интересную тему в комментах к предыдущему постингу: задачи и ответственность некого “руководитела команды”.
В частности он говорил о том, что все наши “неудачи” в начале процесса связаны с плохим “руководителем команды”, а если этого руководителя нет, то “и не удивительно” :)

Тема мне показалась интересной, а утверждение – спорным. В частности и потому, что “неудачи” были успешно пофиксены, а “руководитель команды” так и не появился. Просто мы стали командой. И всё.
Поэтому давайте рассмотрим, что же это за позиция такая: “руководитель команды”? Позиция, кстати сказать, весьма распространённая.

Итак, в чём заключается роль “руководителя команды” (они любят называть себя ПиЭм, поэтому я тоже буду использовать эту аббревиатуру, хотя это неверно).

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

Вроде на этом всё. Рассмотрим по пунктам.

Начать хочется с пункта 4, как самого интересного :)
Интересного в этом пункте то, что формальные методологии процесса разработки практически умерли, доказав свою неэффективность.
Перефразируя Ладыженского:
”Умер RUP.
Это много страшнее других смертей.
Обалденно стою
Над потерей потерь.”

То есть, найти в применении что-то, что не-agile сейчас действительно проблематично. А Agile – это уже даже не методология, а процесс… Тот же SCRUM, пожалуй один из самых распространённых в мире процессов. Тот же канбан, который, видимо, набирает силу (но к которому я отношусь с подозрением). Всё это происходит от того, что издержки от “тяжёлых” методологий велики.

“Тяжёлые” методологии умирают. Об этом же пишет Том ДеМарко, один из основоположников всего этого дела и автор книги “Controlling Software Projects: Management, Measurement, and Estimation”. Он в своей статье прямо пишет:

“In my reflective mood, I’m wondering, was its advice correct at the time, is it still relevant, and do I still believe that metrics are a must for any successful software development effort? My answers are no, no, and no.

В статье он называет самого себя “юным автором, которому нравились метрики” и заявляет о том, что всё это оказалось неверным.
Оригинал можно почитать тут: http://www2.computer.org/cms/Computer.org/ComputingNow/homepage/2009/0709/rW_SO_Viewpoints.pdf
Перевод – здесь: http://bishop-it.ru/2009/07/softwareengineeringisdead/

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

Перейдём к пункту 3.
Имея на руках задачи (об этом позже), кто может сделать разбивку задач на технические “таски”, сделать оценку сложности работ, оценку приблизительного времени исполнения лучше, чем сама команда разработчиков? Некий “руководитель”, который придёт и скажет потом “Вася с Петей делают то-то, у вас неделя, Миша, Маша и Маня – вот это, у вас 8 дней”? Да не смешите, это не работает :) Но даже если это сработает с определенной поправкой (допустим, “руководитель” хорошо знает способности всех пятерых), то это всё равно не будет лучше, чем если бы это сделали сами исполнители.
К тому же, в подавляющем большинстве случаев, программисты знают код и архитектуру лучше, чем любой волшебный ПиЭм :) Поэтому оценки будут вернее.
Есть ещё один аспект: команда может перераспределять подзадачи внутри себя. Никакой “ПиЭм” ей для этого не нужен. А эффективность возрастает существенно по сравнению с тем, что Вася сидит и делает данный ему “свыше” таск – практика.

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

О контроле за процессом разработки. Тут даже говорить-то не о чем – весь контроль – это фикция, сводящаяся к назойливому ежедневному (хорошо если не ежечасному) “ну, как продвигается?”. Да невозможно узнать “как продвигается” лучше, чем знают это конкретные исполнители. И если дать возможность команде самоорганизовываться – она станет способна решать эти проблемы. Сама.

О пункте 2. Простой вопрос: зачем?
При отсутствии фигни из пункта 3 отпадает всякая необходимость и в этом.

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

Итак, у нас осталась разработка требований, которая с руководством не связана.
Теперь давайте посмотрим на типичную команду, имеющую “руководителя-ПиЭма”. Кто он?
В 90% случаев (я видел только таких, но пишу 90%, мало ли :)) это люди, которые работали сначала разработчиками, потом.. как это по-русски.. senior software developer, а потом типа “выросли” до ПиЭма. То есть – программеры-переростки :)
Что такие люди знают об управлении требованиями? Об управлении людьми (буде они таки собрались ими управлять)? Об управлении чем-либо вообще? Ни-че-го. Хорошо, если книжек про это почитают.
И это хорошо ещё, если этот человек таки действительно занимается требованиями. Ибо часто бывает, что требованиями занимаются другие, например, непосредственно менеджмент, или представитель заказчика, а такой вот ПиЭм является просто переносчиком информации (вопрос “как продвигается” остаётся в силе).

Теперь задумайтесь: “повышая” (а посути понижая) хорошего разработчика до такого вот “руководителя команды” мы:

  1. Теряем высококвалифицированного специалиста.
  2. Получаем неквалифицированного (низко квалифицированного) человека, занимающегося требованиями.
  3. Вынуждены платить большие деньги этому человеку на новой позиции.
  4. Теряем гибкость и чёткость работы команды именно как команды, а не как Васи, Пети, Маши, Миши и Мани, делающих то, что в данный момент велел “руководитель”. Поверьте, именно командная работа существенно улучшает конечный результат.
  5. Увеличиваем риск ошибки (одна голова хорошо, но две – лучше). К тому же, та же самая голова никуда и не девается.

Скрипач не нужен…

Получается, что гораздо выгоднее перейти на рельсы самоорганизации команды, сделать её именно командой, вернуть такого программера-переростка на место, получив обратно +1.5 к programming skills в комманде.
А для работы с требованиями программист не нужен. Достаточно усердного человека, хорошо разбирающегося в офисе с минимальными навыками в программировании на уровне сделать запрос в ACCESS или простейший макрос на Office VB, чтобы просто понимал, что за магию творят другие :)
И станет он разбираться в продукте с “внешней” его стороны, и станет он распределять приоритеты необходимой для релиза функциональности, и станет он описывать требования ну никак не хуже вышеописанного ПиЭма. :)

7/25/2009 4:40:32 PM

Завтра – последний день отпуска. Неделя быстро пролетела. С понедельника возвращаюсь на работу.
Хочу пожелать себе в этой связи, чтобы я вернулся на работу, а багфикс там был уже закончен. Не люблю багфикс. Понимаю, без него не бывает. Но у нас ситуация особенная, можно сказать даже новая для меня: в самом начале проекта было допущено много ошибок. Организационных, методологических, всяких. В результате только с моего прихода в команду я переписал, наверное, четверть проекта – пытался построить архитектуру, с которой можно жить. Еще пара человек делали то же.
Но даже с учетом такого, иногда весьма серьёзного, рефакторинга всё это дело вылилось в несколькомесячный багфикс (в результате которого тоже было очень много рефакторинга).
Когда я уходил в отпуск неделю назад тучи уже практически рассеялись (потому и отпуск дали :)). Продукт работал, даже сроки не были сорваны.
Надеюсь, я вернусь – и всё будет хорошо. Можно будет работать дальше.

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

Вообще, на мой взгляд, основными допущенные изначально командой ошибками были:

  1. “Сделаем это просто и быстро”. Любая задача решается “в лоб” без оглядки на какую-либо общую инфраструктуру, архитектуру, что бы то ни было. Проще написать спагетти-метод на две страницы, чем изобретать какую-то декомпозицию, API и т.д. Он будет работать здесь и сейчас – это нам и нужно.
  2. “Будем думать только о реализации текущей задачи”. Программист получает таск (задачу) и делает её так, чтобы в максимально короткий срок выдать её решение. При этом человек не думает о том, насколько это решение укладывается в общую архитектуру, укладывается ли вообще и насколько просто/сложно будет потом это решение поддерживать. Сколько нужно усилий будет приложить потом, когда требования изменятся или расширятся. Как потом строить что-то поверх, имея в основе данное решение. Всё это приносится в жертву тому, чтобы поскорее поставить задаче статус “done” и объясняется тем, что “сделано быстро и просто, надо будет – просто переделаем этот кусок”.
  3. “Решим конкретную задачу”. При этом такое “решение” совершенно не является решением. Оно является костылём. Как-то что-то подпёрли – вроде пошло дело. Что-то помешало – подопрём и это немножко с другой стороны. Работает же! О! очень не люблю фразу “работает – не трожь”. Есть основания.
  4. “Кто делал эту часть?”. Люди, которые делают какую-то часть проекта. Другие люди не знают этой части, не знают, как оно сделано, почему оно сделано так, насколько оно вообще сделано (несмотря на статус “done”). Когда возникают какие-то проблемы или появляются новые требования, в команде возникает вопрос “Кто у нас делал эту подсистему?” и ответ “А это не я, это XXX” и задача автоматически делегируется этому человеку.
  5. “Поставим костыль”. Очень похоже на номер 3, но поскольку это оооочень плохо и мы ооооочень много на этом накалывались, напишу ещё раз :) Внося исправление, программист видит, что там, в коде, не решение задачи, а какой-то бред написан (утрирую). Даже если задача попала ему в соответствие с пунктом 4. А уж если нет… При этом он, в соответствие с 2 и 3 думает: “А ну его нафиг! Щас вот тут подправлю, подфиксю – и будет работать”. И подфиксивает. И оно работает. До следующего раза. Потому, что решение так и не было предложено. Потому, что для того, чтобы получить решение, нужно много отрефакторить и много переписать. В результате, как показывает практика, хотя кода становится в полтора раза меньше, но времени-то тратится куда больше на то, чтобы написать это решение плюс повыкидывать те костыли, которые уже успели понаставить.

Сейчас эти проблемы в нашей команде можно сказать решены. Поздновато они были решены, но такова жизнь. За это заплачено достаточно большой потерей времени (можно было сделать раньше) и достаточно большими переработками всей команды (отчего и устал и ушёл в отпуск, и многие сейчас уходят).
И всё это вылилось, как я сказал, в несколькомесячный трудный, унылый, утомительный багфикс. Наша команда ошибки осознала и исправила (хоть и не осталось практически никого из “первого состава”).
Всем остальным от всей души советую этих ошибок не допускать, а если они есть – вырывать с корнем прямо с понедельника :)

Cебе желаю, чтобы багфикс к понедельнику благополучно закончился :)

7/6/2009 12:28:00 PM

Что получается...

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

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

Через год мы переехали в Бельгию. Мы с коллегой поселились в одном доме, в одном подъезде, с разницей в несколько этажей. Так у нас появилась собственная беспроводная сеть. Мы напополам купили роутер, оформили подключение на мой адрес. Это был 4-х (после двух лет стал 8-ми) мегабитный канал; по тарифу нам полагалось 15 гигабайт трафика. На двоих, но что делать с 7.5 гигабайтами ни я после Питера, ни он после Челябинска не знали. Однако "втянулись". Сначала старались выбирать положеную нам квоту, потом устали от этого занятия. Евро-другой ничего не меняют (а гигабайт "сверху" стоил как раз евро). Иногда приходилось доплачивать, а иногда и нет. За статистикой уже никто не следил.
Потом коллега, узнав о моем переезде в Австралию, подключил себе собственный интернет, так что на нашу долю перепали все 15 гигабайт. Та же история. Прижились, иногда укладывались, редко - нет...

Переехав в Австралию я подключился на тариф, которого я даже не хотел. Шутка ли: 15 гигабайт дневного трафика и 20 гигабайт - ночного. Я говорю жене: "я понимаю, куда девать 15 дневного, но нафига нам 20 ночного?! Ночью я сплю!". Но выбор не велик, так и повелось.
Вот, живу в Сиднее уже без двух недель год. (Ого, год! Я еще от Бельгии не отвык, тут все еще в новинку, а уже год прошел! Вроде таааак тянулся, а тут бац!). Бывало, конечно, что трафика не хватало. Но редко.
А пару месяцев назад жена настоятельно предложила за дополнительные 10 долларов перейти на тариф "30 гигабайт дневного и 30 гигабайт ночного трафика". Я ей говорю: "Лена! Нафига нам в 2 раза больше дневного?! Солить, чтоли?! Про ночной я вообще молчу! 20 выбираем иногда - ну и хватает же!".
Значится, привел убедительные аргументы. Я же мертвого уговорить могу выйти из могилы и сплясать :)
Короче, полез я на сайт провайдера и перешли мы на этот тариф. Попутно я еще ползунок там нашел, регулирующий скорость... Стоял на половине.. Выкрутил его сначала на три четверти, потом полностью. Пусть. Сказано "аж до 20 с чем-то мегабит в секунду" - пусть будет.

Интересная штука - этот интернет. Расчетный месяц заканчивается у нас 13-го числа. На текущий момент скачано уже 92% дневного трафика и где-то 89-90% ночного.
Забавно. Получается, что ощущения удовлетворенности интернетом и потребности в его использовании от цифры не зависят. Адаптируются они к цифре как-то. Потому как при любом значении допустимой нормы она иногда перерасходуется, чаще не добирается...
А пользователь остается одинаково доволен! Во как...

7/2/2009 4:20:12 PM

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

Пока думаю о следующем:

  1. Development Branch (Trunk/Main).
    Основная, с точки зрения разработчика, ветка. В эту ветку допускаются… check ins, commits, как это по-русски… “чекины” буду говорить. Так вот, в эту ветку допускаются чекины изменений, который с точки зрения разработчика готовы к тестированию. Кроме того, здесь фиксятся баги, найденные тестерами.
    Поэтому с точки зрения тестера эта ветка – самая нестабильная в проекте, первый этап.
  2. Feature Branches (Trunk/<FeatureName>).
    Это ветки (“песочницы”, как любил говорить мой бывший коллега) разработчиков. Каждый разработчик, или группа товарищей, могут создавать себе таких веток столько, отпочковывая их от Trunk/Main, сколько им нужно. Предполагается, что в такой ветке идёт разработка какой-то фичи, новой функциональности. Когда разработчики считают, что фича готова, прошли тесты и код-ревью (у кого есть, завидую) и всё такое – они сливают свою ветку обратно с Trunk/Main, отмечают работу как “готова к тестированию” и фича переходит в руки тестеров.
  3. UAT (User Acceptance Test) Branch.
    Бета, так сказать. Стабильная, уже с точки зрения тестеров, ветка. Как туда попадают фичи – отдельный разговор. Ну, например. В случае “классического” итерационного процесса (любой Agile) завершение итерации знаменуется достижением поставленных для данной итерации задач. “Достижение” – это когда фичи сделаны и тестеры довольны. И вот тут мы можем слить изменения из DEV в UAT.
    Либо же изменения вливаются “пофичево”. Фичу оттестировали на DEV – слили в UAT. Это требует больше усилий, правда. И иногда может оказаться не совсем возможным.
    Предмет разговоров, короче. Самое интересное место.
  4. Release Branches (Release/<ReleaseName>).
    Стабильные, релизные ветки. Здесь всё просто: то, что прошло UAT время от времени назначается релизом. Например, когда достигнуты все цели, поставленные перед релизом, то есть, сделаны и оттестированы все необходимые фичи.
    Делается ветка для этого релиза, которая никогда больше не будет ни с чем сливаться, ни в одну, ни в другую сторону.
    Зачем тогда ветка? А просто потому, что там тоже могут оказаться баги :) Которые может быть нужно срочно пофиксить. И тогда это фиксится прямо в ветке текущего релиза. И никуда не сливается. Просто потому, что разработка идёт дальше и как сам баг, так и его фикс уже могут просто не иметь смысла в контексте текущей разработки.
    К тому же фикс в релизе может означать просто какую-то заглушку, какой-то, скажем прямо, хак. В то время, как в дивелоперской ветке этот баг, если он там имеет смысл, фиксится уже со всеми необходимыми рефакторингами и т.д.

С точки зрения “сливания” тоже получается, вроде, неплохо, однонаправленно.
Ветки разработчиков вливаются в DEV (хотя они могут и DEV в свою ветку слить, почему нет, это их право). Дальше всё строже: DEV сливается на UAT только в одну сторону. Поэтому с конфликтами тут всё очень и очень просто – их не должно быть, ибо никакой разработки в UAT не ведётся.

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

А как с этим у вас? Какие подходы применяются?

6/25/2009 2:34:06 PM

Зашел тут как-то спор на работе по поводу юнит-тестов. Спорили-спорили. Интересно, но все остались при своих. Полез смотреть в интернет, оказывается есть два “лагеря”, которые никак не могут примириться.

Проблема простая: тестировать или не тестировать приватные методы.

Сторонники одного лагеря настаивают на том, что юнит-тестами должны быть покрыты только публичные функции и классы. Объяснение этому такое:

  1. Тестировать нужно интерфейс класса или подсистемы, который не зависит от внутренней реализации.
    Любое изменение “внутренностей” этого класса или подсистемы не должно сказываться на функционировании интерфейса. Таким образом, покрыв юнит-тестами интерфейс мы всегда имеем возможность убедиться, что подсистема/класс функционирует именно так, как нам нужно. А что и как у неё делается внутри, с этой точки зрения не важно.
  2. Тестирование приватных функций отнимает много времени, усложняет поддержку и нерационально.
    В ходе любого проекта происходит масса рефакторинга. По моим оценкам, на рефакторинг уходит до 20% времени при “нормальной” организации работы и неплохом качестве архитектуры и кода. Как только в проекте появляются юнит-тесты, так сразу возникает необходимость поддержки не только кода продукта, но и юнит-тестов в актуальном состоянии. При этом реализация классов/подсистем меняется гораздо сильнее и чаще, чем интерфейсы. Всяческие там оптимизации и т.д. Поэтому поддержка юнит-тестов на уровне интерфейса – оправдана, так как даёт уверенность при использовании подсистемы/класса. А покрытие ими реализации – не оправдано, так как, во-первых, если “падает” какой-то внутренний функционал, то “падает” и один из “интерфейсных” вариантов использования, а во-вторых существенно увеличивает объем работы.
  3. Подход полностью соответствует TDD.
    Создавая публичный метод мы, де-факто, создаём интерфейс, его и тестируем. С этой точки зрения нам, опять же, совершенно не важно, что там делает этот метод внутри и как именно.

Второй лагерь настаивает на обратном:

  1. Полезно тестировать каждый отдельно взятый функциональный аспект приложения.
    В термине “юнит-тестирование” под “юнитом” понимается настолько малый и обособленный функциональный фрагмент, насколько это возможно. Фрагмент этот не обязательно должен быть публичным. Разработчики имеют право быть уверены в том, что каждый маленький, но важный кусок (а неважный никто и писать бы не стал – поленился бы) выполняет свою задачу. Независимо от зоны его видимости, которая, кстати, может меняться в процессе рефакторинга.
  2. Приватная функция может быть использована в нескольких местах.
    То же касается и приватного класса. Для того, чтобы использовать эту функцию или класс, неплохо было бы быть уверенным, что этот кусок кода хорошо делает свою работу.
  3. Бόльшая определённость в покрытии юнит-тестами.
    Для каждой отдельной конечной приватной функции достаточно легко написать тест, грамотно покрывающий варианты её использования. Другое дело, когда тестируются только публичные функции, вызывающие другие (приватные) функции. Написать тесты для такой сложной функции может оказаться сложнее. Кроме того, никогда точно не знаешь, какой объем вариантов использования покрыт.

В общем, нет согласия в рядах.

А к какому лагерю склоняетесь вы?

Powered by BlogEngine.NET 1.6.0.0

About the author

Alexey Raga Alexey Raga
.NET software developer.

E-mail me Send mail

Twitter


Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010

Sign in