Как Гугл тестирует программы

Примечательно, что:

  • В гугле тоже люди, только они тестируют, не сразу и не все.
  • Должна быть ответственность программиста за код и проект, сам должен тестировать (автоматизированно).
  • Гугл поощряет ротацию сотрудников по проектам, но не чаще, чем раз в полтора года.
  • Есть разные роли: разработчик в тестировании, инженер по тестированию, тест-менеджер; но всё это бренно, потому что останется только одна — «тестировщик», остальным дорога либо в разработку, либо в менеджерство. Сами придумали названий — сами их и похоронили.
  • В приложении к книге есть тест-план для Chrome OS, но «Тест-план мертв!» Вместо тест-плана есть Методология ACC (Attribute Component Capability). По ней же и риски легко выявить.
  • Вайтекер натворил делов в Google и соскочил в Microsoft.
  • Нет единства — команды используют свою терминологию, имеют своё виденье тестирования, пропорции, и будущее.
  • Вкладываются в тестирование, когда проект уже выстрелил — забудь о TDD, BDD, и прочей.

Рефаторинг Фаулера

Перечитал «Рефакторинг» Фаулера. Ценнейшей главой считаю «Принципы рефакторинга», где объясняется зачем, когда, почему, преимущества и ограничения рефакторинга.
Самое главное — определение. В определении самое главное, что рефакторинг «не затрагивает наблюдаемого поведения». В наше время, когда термин получил широкое распространение, нередко можно услыхать: «Полсистемы сегодня отрефакторил! Теперь стало правильно работать».

«Запахи кода» во многом пересекаются с классификацией других авторов. Примечательно, что Кент Бек предложил эстетику программирования модифицировать в запах.
Большинство «элементарных» рефакторингов сводится к нескольким действиям:

  • выделить (класс, метод, интерфейс, переменную, …)
  • встроить
  • переместить

Большинство программистов используют ООП, и знают, что дублирование, длинные методы и классы, ленивые классы, много параметров в методах — это беда.
Хотелось бы остановиться на нескольких простых случаях, которые часто упускаются из виду.

Условные операторы:

  1. Удаление управляющего флага — используем break и continue, а лучше return.
  2. Замена вложенных условных операторов граничным оператором — это еще Хант писал («Программист-прагматик«), называя «сторожевой башней».
  3. Замена условного оператора полиморфизмом — если уж ООП, то нада использовать чудесную силу полиморфизма — пусть сам класс отвечает за своё безобразное поведение.
  4. Замена исключительной ситуации проверкой — так легко заиграться exception-ами, когда  открываешь для себя этот чудный мир исключений.

ООП-эшное ООП:

  1. Замена массива объектом (схож с заменой записи классом данных) — пусть даже пустым, поведение появиться позже, но уже лучше, чем 10 параметров метода.
  2. Введение граничного объекта — группировка «парметров, естественным образом связанных друг с другом», например, класс DateRange вместо двух Date.

Общие:

  1. Замена кода типа сотоянием/стратегией (или хотя бы классами/подклассами) — если код типа влияет на поведение классов, то заменить его подклассами или применить одноименный паттерн «шайки четырёх».
  2. Разделение запроса и модификатора — самый очевидный пример — в методах, начинающихся на get{MethodName}, только возвращать, а менять в set-ах.
  3. Свёртывание иерархии — лишний, пустой, ленивый класс не оправдывает своего существования.
  4. Замена наследования делегированием — я за композицию (не отрицая полезности наследования), а вы?
  5. Отделение предметной области от представления — все в округе говорят об «MVC», а на деле часто формирование данных и отображение данных перемешаны в коде, например, когда нужно сформировать отчет в csv или xls формате.

Спорить с полезностью рефакторинга по Фаулеру решается только полный «нигилист», а вот эффективно применять технику может не каждый.

Длинный хвост Криса Андерсона

Длинный хвост Криса Андерсона — книга о смещении культуры, а за ней и экономики, из «хитовости» (массовости) в «нишевость» (изобилие). Чтобы возник «длинный хвост» должны выполняться 3 аспекта:

  1. Демократизация средств производства — например, ПК, который дал возможность каждому быть дизайнером, музыкантом, программистом, или ещё чего хужее.
  2. Демократизация инструментов дистрибуции — Интернет, в частности (доставка электронной версии книги ничего не стоит).
  3. Объединение спроса и предложения — фильтры, например, google, блоги, рекомендации.

«Правило 20/80″ (Закон Парето) постоянно неправильно понимают по трём причинам:

  1. Соотношение практически никогда не равно 20/80, для большинства рынков 10/80
  2. В сумме необязательно должно быть 100 (например, 10/80), потому что одно число — процент от от числа продуктов, а другое — процент от продаж
  3. Нет соглашения о представлении — 10% продуктов отвечают за 80% продаж, — тоже самое, что и 20/95.

«Телевидение вульгарно, похотливо и тупо не потому, что аудитория вульгарна и тупа. Телевидение таково просто потому, что вульгарность, похоть и тупость людей очень похожи, в то время как их утонченные эстетические вкусы совершенно различны.» (David Foster Wallace)

9 правил для успешных агрегаторов в «длинном хвосте»:

  1. Концентрируйте или распределяйте товары — хранить на большом складе, или как Amazon на складах партнёров.
  2. Пусть потребители делают всё сами.
  3. Один способ дистрибуции не может подходить всем.
  4. Один продукт не может нравиться всем — альбом, отдельная композиция, 30 секундная версия, видеоклип, ремиксы.
  5. Не всем нужна одинаковая цена — зависимость цены от времени, популярности, чего-то еще.
  6. Делитесь информацией — фильтры, рекомендации, прозрачность системы.
  7. Объединяйте, а не разделяйте — предлагать всё потребителю (+ предоставлять удобные инструменты фильтрации).
  8. Доверьте выполнение работы рынку — не угадывайте, а измеряйте.
  9. Осознайте притягательность бесплатного.

Нужно добавить, что Длинный хвост Криса Андерсона писался почти 10 лет назад, и многие крамольные мысли сейчас уже выглядят очевидными (про гугл, ебей, лего, амазон, и прочие).

Книга «Управление стартапом» Кэтрин Кэтлин и Джейна Мэтьюз

«Эта книга — часть разнообразных обучающих ресурсов, созданных Центром Кауффмана для предпринимателей». Переведена в 2011 году, оригинал впервые издан в 2001.

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

Выделено 3 этапа:

  1. Начальный рост — делегировать, определять направлени
  2. Быстрый рост — создатель команды, наставник, планировщик, распространитель информации
  3. Постоянный рост — катализатор изменений, строитель организации, новатор стратегий, культурный лидер

Юинг Мэрион Кайффман не очень оригинален, формулируя свою основную ценность в компании так: «Отношение к другим должно быть таким, какого вы хотели бы для себя». Даже до Иисуса об этом кое-что слыхивали.

Плюс сформулированы еще «семь Си» культуры:

  1. Ориентация на клиентов
  2. Распространение информации
  3. Сотрудничество
  4. Творческий подход
  5. Постоянное обучение
  6. Управление изменениями
  7. Конструктивное лидерство: требуйте, чтобы CEO и все менеджеры добивались согласия сотрудников с миссией и целями компании и принятия ими соответствующих решений, развивали таланты, строили отношения и правильно мотивировали людей для максимальной эффективности.

Коротко: делись лидерством, доверяй и проверяй, не ври, планируй, двигайся, учись, расти.

В целом книга «Управление стартапом» Кэтрин Кэтлин и Джейна Мэтьюз настолько уникальна, что моя резолюция — не читать! Не «Идиот» Достоевского. Да, и идиот нынче пошёл уже не торт.

Используй отрицание в именах методов

Странно, но бурю эмоций вызывает чаще какая-нить мелочь, пустячок.

Даже соглашение, как скобочки в коде ставить должно, цепляет, и доводит до исступления рьяных знатоков. Куда уж тут мелочи разряда iphone или андройт, или linux против Unix. Порой и ссоры случаются у Ивана Ивановича ради куда менее значимых событий.

Вот так и в этот очередной раз философия вошла в нашу работу. Я сказал: «Используй отрицание в именах методов». Сказал себе, никого не принуждал, и стал использовать. А почему?

По моему опыту ошибки в условной конструкции возникают чаще других «низкого» уровня ошибок. Сам очень грешен этим недугом — вот и борюсь всеми силами. В частности не гнушаюсь инкапсулировать несколько условий в одно читабельное. Читабельнее читается слово по моему мнению, в отличие от слова со специальными знаками, обозначающими какие-то операции в используемом языке программирования. А в некоторых языках (например, python) даже слово служебное «not» вводят вместо значков.  Итак. Допустимо ли подобное нахальство? Что предпочтительнее?

if (!$this->isBetaUser) или

if ($this->isNotBetaUser)

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

Бывают же и готовые решения, которые хоть разок можно опробовать. И, безусловно, не возводить в догму. У каждого свой путь достижения профессионализма: кто-то «всё сам знает», а кто-то и к «старикам» мирового программирования прислушается иногда. Например, есть такой Роберт Мартин, который не обошёл данный вопрос стороной в книге «Чистый код. Создание, анализ и рефакторинг». Страницы с 293 по 300-ю. Описывает рефакторинг примера. Только некоторые выдержки для ленивых.

if (expected == null || actual == null || areStringsEqual())

«Инкапсуляция поможет лучше выразить намерения разработчика. Поэтому»

if (shouldNotCompact)
private boolean shouldNotCompact() {
    return expected == null || actual == null || areStringsEqual();
}

«Отрицательные условия чуть сложнее для понимания, чем положительные [G29].
Чтобы проверяемое условие стало более понятным, мы инвертируем его:»

if (canBeCompacted())
private boolean canBeCompacted() {
    return expected != null && actual != null && !areStringsEqual();
}

А в итоговой версии получилось так.

if (shouldBeCompacted())
private boolean shouldBeCompacted() {
    !shouldNotBeCompacted();
}

private boolean shouldNotBeCompacted() {
    return expected == null ||
        actual == null ||
        expected.equals(actual);
}

«можно заметить, что я отменил некоторые решения, принятые ранее… смысл выражения shouldNotBeCompacted снова изменился. Это типичная ситуация. Одна переработка часто приводит к другой, отменяющей первую. Переработка представляет собой итеративный процес, полный проб и ошибок, но этот процесс неизбежно приводит к формированию кода, достойного настоящего профессионала.»

Используй отрицание в именах методов, или не используй, а вывод один.

Scrum по Майку Кону

Кого сейчас можно удивить техническими приёмами — тестирование, рефакторинг, непрерывная интеграция, парное программирование?

Кто не слышал про спринт, планирование, итеративный подход разработки ПО, спонтанное проектирование, митинги (по нашему «планёрки» или «летучки», значит)?

Или кто-то предпочитает индивидуальный режим работы командному (коллективному)? Или вааще не верит в социализм.

Практический опыт от построения scrum команд, в том числе и трансконтинентальных, до их эффективной работы подкрепляется теоретическими и статистическими выкладками, как правило не собственного авторства — ссылается на авторитетов.

Интерес вызвали следующие темы.

  • Новые роли многофункциональной команды.
  • Постепенное уточнение требований и айсберг журнала запросов на выполнение работ.
  • Управление самоорганизующимся коллективом (контейнеры, различия, обмены) — никуда без управления даже в самоорганизации.
  • Оценки и обязательства — это не одно и то же
  • Выплатите технический долг (Уорд Каннингем), чтобы не «оказаться в тупике»

Удивило:

  • Смещение акцента со спецификации (Кросби) на общение — на различных уровнях, вплоть до отказа от документации
  • Построение команды — осознанная коллективная ответственность, непротиворечивость воздействий на команду

Scrum по Майку Кону, конечно, идеализирован немного. Но автор напоминает, что методология то «гибкая», а значит нужно безостановочно эволюционировать в своих достижениях.

Также занимательны цифорки от Герта Хофстеда.

Сравнение культур по Хофстеду - Индия и Россия

Сравнение культур по Хофстеду — Индия и Россия

Расшифровка индексов:

  • PDI — терпимость к неравномерному распределению власти
  • IND — индивидуализм
  • MAS — значимость материального успеха
  • UAI — терпимость к неопределенности
  • LTO — оринтация на долгосрочный успех

Лучшие практики тестирования кода

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

  1. Тесты — это код (все правила функционального кода распространяются на тесты).
  2. Тесты должны быть простыми, а значит, — короткими, а значит — понятными.
  3. Тесты должны быть независимыми.
  4. Статические методы — смерть тестируемости (Miško Hevery).
    class Foo
    {
       public static function doSomething()
       {
          return Bar::helper();
       }
    }
  5. Registry и Singletone использовать при крайней необходимости, впрочем как и любое глобальное состояние, которое неподконтрольно тесту.
  6. Не тестировать приватные методы и свойства — если возникает необходимость в тестировании приватного метода (что позволяют делать фреймворки семейства xUnit), значит что-то пошло не так, и пора пересмотреть архитектуру тестируемого класса (возможно и модуля).

Безусловно, реальный мир не идеален, в отличие от автора. Да и догмы не вечны. И на свет появляются монстры:

  • в 6 моков для тестирования поведения одного класса;
  • Dependency Injection Container как необходимость иметь глобальный, но контролируемый, инструмент;
  • подготовка фикстур в 10-ки раз превышающая функционал теста по времени и количеству строк кода;
  • отражение (Reflection), как крайняя мера отчаяния;
  • и многое чего еще.

И всё же есть The Way of Testivus (+ перевод), а значит эти «тестивусы» где-то среди нас.

Модуль media gallery в drupal не загружает файлы на nginx

Наткнулся на вековые, как позже выяснилось, вилы.

При эталонной конфигурации nginx для drupal, и установке модуля media gallery, не создавались «на лету» уменьшенные версии изображения.

Предполагал, что файл не грузится. Проверка настроек nginx и php на эту тему (плюс ручное тестирование) убедило в обратном.

Причина столь безобразного поведения — конфигурация nginx.

Вот такое решение предлагается для imagecache module drupal to nginx:

location ^~ /sites/default/files/styles/ {
  index  index.php index.html;
  if (!-e $request_filename) {
    rewrite  ^/(.*)$  /index.php?q=$1  last;
    break;
  }
}

Руководствуясь рекомендацией «DO NOT DO THIS! This is a terrible use of if«, удалил проверку.

И поехало.

Функциональное и интеграционное тестирование. Определения.

Из русской википедии.

«Интеграционное тестирование (англ. Integration testing, иногда называется англ. Integration and Testing, аббревиатура англ. I&T) — одна из фаз тестирования программного обеспечения, при которой отдельные программные модули объединяются и тестируются в группе. Обычно интеграционное тестирование проводится после модульного тестирования и предшествует системному тестированию.»

«Функциональное тестирование — это тестирование ПО в целях проверки реализуемости функциональных требований, то есть способности ПО в определённых условиях решать задачи, нужные пользователям.»

Вопрос: «Проверка авторизации на сайте — это какой тест?»

По моему мнению, удовлетворяет обоим определениям. Один тест, а два названия — падарокс!

Разрешение падарокса я нашел в нерусской википедии: «Functional testing… a type of black box testing». Соответственно при интеграционном тестировании известны все интерфейсы взаимодействия отдельных модулей («по белому»).

Вот так Selenium тесты оказались в каталоге «functional».

Установка python 3 с virtualenv в ubuntu

Вот так установил питона 3-ю версию в ubuntu 12.04.

sudo apt-get install python3

Создал и активировал окружение с python 3.

virtualenv -p /usr/bin/python3 python3env
source python3env/bin/activate

Проверить версию.

python -V