Monday, 13 August 2012

JUnit неумолимо стремится в направлении к TestNG. Но оочень медленно. Так, появились TestRule, ClassRule, Categories, что подозрительно смахивает на Test Listeners, Method Interceptors, Test Groups, которые есть в TestNG уже миллион лет.

Friday, 10 August 2012

Что такое модульное тестирование и что им не является

Довольно давно я заинтересовался таинственной аббревиатурой TDD. Как известно, наверное, каждому разработчику, расшифровывается она как Test-Driven Development, то есть - разработка через тестирование. Чем-то меня эта идея зацепила, и с тех пор, вот уже более 5 лет, я не оставляю попыток изучить и овладеть этой методикой. Сразу скажу, что я ни разу не работал в команде которая её применяла, более того, я даже ни разу не работал в команде систематически и успешно применяющей автоматизированное тестирование. Хотя с несистематическим успешным применением автоматизированного тестирования и лично моим, на мой взгляд, успешным применением TDD время от времени я сталкиваюсь. Хотелось бы рассказать о тех шишках, что я набил, о заблуждениях и прочих вещах, которые меня сопровождали на пути изучения.

Сразу скажу, что TDD - это сложно и требует немалых усилий. Но я считаю, что в конечном счёте эти усилия окупаются. Всё написанное представляет моё ИМХО, но подкреплённое большим количеством прочитанных статей, книг, и практическим опытом.

Зачастую ставится знак равенства между TDD и модульными тестами (Unit Tests). Это неверно, но почему мы поговорим в другой раз. Модульные тесты в любом случае являются очень важной составляющей TDD. И если у вас есть TDD, ограничивающееся модульными тестами, то это, скорее всего, лучше, чем если у вас нет автоматизированного тестирования вообще (скорее всего =) ).

Давайте разберёмся, что же такое модульные тесты. Это, на самом деле, не так-то просто. Определения можно давать по-разному. Так, мне приходилось сталкиваться с термином "Unitary Testing", которое выглядит подозрительно похожим на Unit testing. Но на практике это было ручное тестирование целой отдельно стоящей системы.

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

Проблема в том, что рассуждение о коде в уме - не смотря на то, что это очень полезное занятие - весьма подвержено ошибкам. Мы, как известно, можем одновременно помнить и рассуждать о 7 +- 2 вещах на одном уровне абстракции одной предметной области. Код, к сожалению, далеко не всегда написан на одном уровне абстракции, кроме того, в нём нередко смешаны понятия совершенно разных предметных областей, а ещё есть такое явление как "протекающие абстракции" (Джоэль Спольски). Ну и самих объектов кода нередко больше семи, а если уж вспомнить о количестве их состояний.. В общем, правило 7+-2 нарушается постоянно и очень сильно - в сторону +. Поэтому, наши мы не можем надёжно рассуждать о поведении кода. Если вы можете, то либо вы гений, либо ошибаетесь) Конечно, нужно стремиться к тому, чтобы то, что мы пишем, подчинялось этому правилу, но это совершенно отдельная тема. Кроме того, нам часто приходится работать с чужим кодом, и совсем не факт, что его авторы вообще знают об этом правиле.

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

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

С автоматизацией разобрались, что ещё можно сказать относительно нашего определения? Что такое модуль, например? Это вопрос субъективный, как уже было сказано выше, под ним можно подразумевать и отдельную систему которая входит как часть в какой-то сложный программный комплекс. Но обычно под модулем (unit) подразумевается функция, метод, класс или небольшой набор классов, которые в совокупности решают некоторую задачу. С подобным определением все, в основном, согласны, но, тем не менее, оно может вызывать ряд вопросов.

Предположим, мы тестируем функцию main. Является ли данный тест модульным? Мы же тестируем одну функцию. Правда, она может запускать HTTP веб-сервер, который, обрабатывая запросы, запускает задачи в Hadoop кластере. С другой стороны, наш main (всё приложение, то есть) может просто запрашивать у пользователя два числа и складывать их. А этот тест - модульный? В первом случае main вызывает всю систему. Вряд ли в ней "небольшой набор классов" (пусть небольшой - это всё те же 7+-2). А второй? Класс один. Наш класс один. Но мы запрашиваем данные и выводим их. А это вовлекает стандартную библиотеку. А в ней, даже если говорить только о том пути по которому идут наши данные, наверное ,не такой уж и "небольшой набор классов". Впрочем, мы не знаем сколько и должны это проанализировать, если есть исходный код. А если нет? В общем, определение несколько размыто.

Уточним его: "Модульный тест - тест, проверяющий работу модуля в изоляции". Кстати, википедия тоже говорит об изоляции, но не включает её в определение. Что значит в изоляции? Перечислим наиболее распространённые варианты:
  • Не использует третьесторонние интерфейсы, кроме собственно тестового фреймворка и API, либо специально предназначенных для тестирования вроде Hamcrest или mocking-фреймворков (JMock, Mockito и другие), либо "простые" вспомогательные API вроде Guava Functional/Collections, Apache Commons Lang. Их отличительной чертой является то, что в основном они устраняют недостатки языка Java и его стандартной библиотеки, являются Pure-Java и не используют и не предоставляют какой-бы то ни было иной функциональности - особенно упомянутой в следующих пунктах. 
  • Не использует файловую систему 
  • Не использует сеть 
  • Не использует базу данных 
  • Не использует многопоточность, многопроцессность и иные ипостаси конкурентных, распределённых и параллельных вычислений. 
В общем, похоже, что вообще ничего использовать нельзя. Почему? Как быть?

Начнём с вопроса "почему". Модульные тесты - это самая базовая система безопасности вашего проекта, Это сторожевая собака во дворе. Или даже забор. У вас может быть ещё и сигнализация в доме, но я думаю, что вы бы предпочли, чтобы злоумышленники до её активации не добрались. Эта система безопасности должна проверять каждое изменение и как можно быстрее. Здесь можно долго рассуждать важности быстрой обратной связи, но (пока?) примем за аксиому - чем раньше мы получаем обратную связь - тем лучше. Если мы что-то написали и оно не работает или ломает что-то, то лучше узнать об этом до коммита изменений, хуже после коммита и вообще плохо если система уже в эксплуатации и используется тысячами пользователей. Как узнать? Запустить тесты. И чем чаще и чем больше тестов мы запустим - тем больше наша уверенность в том, что наши изменения корректны. А если они некорретны, то мы об этом узнаем быстро. Но, допустим, тесты всей системы занимают полчаса. Никто не будет их запускать после каждого изменения. А если наш тест ломится в базу и что-то там долго делает, то мы очень быстро придём именно к этому. Кроме того, у базы могут измениться настройки. Может измениться схема. Она может вообще быть недоступна из-за обновления сервера. На диске может кончится место. Может измениться интерфейс удалённой системы. Ваш сетевой кабель могла перегрызть мышь, или просто он разболтался и плохо держится. После очередного обновления операционной системы могли измениться настройки файервола. Ваш коллега может качать торрент South Park, из-за чего сеть работает слишком медленно. Третьесторонняя библиотека может содержать ошибки или сама ломиться на диск, в базу и в другие места. И так далее и тому подобное. Всё это, во-первых, замедляет выполнение тестов; во-вторых, приводит к случайным ошибкам тестов. В результате, мы либо запускаем тесты реже, либо запускаем меньшее количество тестов, либо вынуждены запускать из по нескольку раз, либо всё сразу. Все эти ситуации мы тоже должны учитывать. Но вспомните про 7+-2 вещи. Это совсем другая область и другие вещи. Сейчас мы работаем над функцией и хотим, чтобы она вела себя правильно. Когда мы этого добъёмся - мы проверим, что всё работает в целом и изменим, то, что необходимо. Но сейчас мы работаем над нашим кодом, который должен демонстрировать определённое поведение. И мы не хотим отвлекаться на час, звонить DBA, который в отпуске, а потом с трудом вспоминать, на чём же мы остановились. И это в лучшем случае! А в худшем мы вообще не сможем продолжить работу над задачей, пока DBA не выйдет из отпуска. Итак, мы убедились, что модульные тесты должны быть изолированы.

Следующий вопрос: "Как быть?". Надо писать код так, чтобы его можно было тестировать в изоляции. Поскольку система в целом в изоляции работать не может, то очевидно, что все тесты не могут быть модульными. Так или иначе необходимо тестирование всей системы, а также связок системы с внешними сущностями и ресурсами. Хорошо, если эти тесты тоже автоматизированны. Но это другой класс тестов и надо это понимать. Для них действуют другие правила: они запускаются реже, работают дольше и могут иногда случайно выдавать ошибки. Мы не запускаем их после каждого изменения. Чем большая часть системы может быть протестирована в изоляции - тем лучше. Выглядят они обычно тоже не так, как модульные.

Как понять, что тест, с которым вы имеете дело - не модульный? Есть несколько признаков:
  • Нарушение любого из пунктов изоляции. В том числе, использование Spring Runner, логирования, применение HSQL (даже в оперативной памяти). 
  • Вовлечение большого количества классов. 
  • Скриптовые тесты - вы выполняете ряд действий над системой, чтобы провести её через ряд состояний, проверяете что-то, делаете дальнейшие действия, проверяете ещё что-то. 
  • Частный, но распространённый случай предыдущего - множество проверок. Впрочем, это может быть и показатель плохого качества кода - тестового или/и рабочего. 
  • Зависимость тестовых методов друг от друга 
  • Использование статических данных. Случайные ошибки тестов. 
Всё вышеперечисленное может присутствовать в тестах. И эти тесты могут быть очень полезны. Просто они не будут модульными. Это нужно понимать, потому что, не имея модульных тестов, вы лишаетесь максимально быстрой и надёжной обратной связи. Это может быть разумным компромиссом, но если вы не понимаете разницы, то этот компромисс неосознан (и неразумен). А неосознанный компромисс в программном проекте, как и любое неосознанное решение, может быть бомбой с часовым механизмом.

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

Wednesday, 7 July 2010

Haskell: inspirations from the future

Совершенно случайно наткнулся на некую коллекцию ссылок под звучным названием Ultimate Computer Language Guide, и обнаружил там следующее определение:
Haskell

Haskell is a scripting language inspired by Python. The current version is Haskell 98.
По данным википедии Хаскелл появился на год раньше Пайтона. Отсюда я сделал вывод, что создатели Хаскелла настолько круты, что, создавая язык, они черпали хорошие идеи даже из таких источников, которым ещё только предстояло появиться!

Tuesday, 6 July 2010

PowerShell - AWK для Windows?

В жизни программиста нередко возникает такой момент, когда нужно автоматически перелопатить много текстовой информации, извлекая из неё что-то, либо модифицируя. Программисты и администраторы Unix всегда под рукой имеют целую кучу средств. Bash предоставляет базовые возможности вроде замены подстроки; для более мощных преобразований есть sed и awk.

Для меня всегда было загадкой, что же делать бедным программистам, живущим на Windows? Конечно, всегда можно поставить cygwin и использовать те же самые bash, sed и awk. Можно сразу взять быка за рога и установить Perl или Python. Но всё это какие-то ... неродные что ли решения. Вот были бы какие-нибудь стандартные программы для таких операций. С помощью стандартного коммандного процесора cmd заниматься текстовыми преобразованиями весьма проблематично...

Итак, где же решение? Довольно давно на горизонте Windows замаячил инновационный шелл под скромным названием PowerShell. От всех остальных шеллов в мире он отличается объектной-ориентированностью и строгой динамической типизацией. Как это выглядит на практике, объяснять довольно долго, и об этом прекрасно рассказано в книге "PowerShell in Action". Получилось непривычно, но вполне эффективно. Ладно, шелл шеллом, а как быть с обработкой текстовых данных? Способен ли этот шелл заменить собой AWK для Windows? Как выяснилось, ответ положительный.

Перед нами простой AWK скрипт, который обновляет два определения в rpm .spec-файле:
awk '
$1 " " $2 == "%define name" {
    printf  "%s %- 17s %s\n", $1, $2, "'$PKG_NAME'"
    next
}
$1 " " $2 == "%define _requires" {
    printf  "%s %- 17s %s\n", $1, $2, "'$REQUIRED_PKG_NAME'"
    next
}
{
    print $0
}' $SPEC_FILE > $SPEC_FILE.new
Он не претендует на шедевральность, страдает повторами, но своё дело делает исправно. Как он работает? Awk читает $SPEC_FILE построчно и каждую строку передаёт в скрипт, предварительно разбив её на поля по пробелам. Каждое поле доступно в виде переменной вида $n, где n - число от 0 до количества полей. Так, строка "Hello World" будет разбита следующим образом: $0 = "Hello World", $1 = "Hello", $2 = "World". Сам скрипт организован в виде последовательности шаблонов и соответствующих им действий. Если шаблон соответствует текущей строке, то соответствующее действие выполняется. Действие без шаблона выполняется для каждой строки, если до него доходит управление. Шаблон в awk понятие довольно общее - это может быть регулярное выражение или условное выражение, которое может сопровождаться побочными эффектами, например, выделением подгрупп из поля с помощью регулярного выражения.

Предоположим, что у нас есть следующая спека:
# skipped 
%define name              PKG_NAME
%define _requires         REQUIRED_PKG_NAME
# skipped

После применения скрипта, полагая что
PKG_NAME=NEW_PACKAGE и REQUIRED_PKG_NAME=OLD_PACKAGE,
получим:
# skipped
%define name              NEW_PACKAGE 
%define _requires         OLD_PACKAGE 
# skipped

Как достичь аналогичного результата в PowerShell? Как оказалось, очень просто. В PowerShell есть интересный оператор switch. Может он неожиданно много. На первый взгляд, он ничем принципиально не отличается от аналогичных операторов в языках типа C. Но в PowerShell этот оператор гораздо более гибок. Нас интересуют следующие его свойства:
  1. Он может содержать в качестве шаблонов произвольные типы PowerShell, в частности строки;
  2. Он может принимать параметры (оператор, который принимает параметры, с ума сойти), которые влияют на интерпретацию шаблонов и анализируемого выражения. Мы применим:
    1. -regex: интерпретирует шаблон-строку как регулярное выражение и проверяет анализируемое значение на соответствие ему;
    2. -file: интерпретирует анализируемое выражение как имя файла, и построчно (звучит знакомо :) ) передаёт его в оператор switch.

Итак, аналогичный скрипт на PowerShell:
$(switch -regex -file ($SPEC_FILE) {
    '%define name' {
        "{0,-25} {1}" -f $matches[0], $PKG_NAME
    }
    '%define _requires' {
        "{0,-25} {1}" -f $matches[0], $REQUIRED_PKG_NAME
    }
    default {
        $_
    }
})
Он удивительно похож на исходный. Впрочем, это, скорее, не удивительно, потому что, по утверждению создателей PowerShell, они учли весь тридцатилетний опыт Unix-шеллов и опыт современных скриптовых языков как Perl и Python. Хочется отметить следующие особенности:
  1. Автоматическая переменная $matches, которая чудесным образом появляется после выполнения операции соответствия регулярному выражению. 
  2. Другая чудо-переменная: $_ - обозначает анализируемое выражение, то есть всю текущую строку в данном случае. 
  3. Получившиеся строки не печатаются (print, echo, write) и не возвращаются (return), не собираются в массив, а эмитируются (emit). Эмитирование - это неявное возвращение результата. Так, в Bash'е результат выполнения скрипта - это результат последней команды в нём, если нет явного вызова exit. В Groovy, функции возращают результат последнего выражения, если не указано слово return, и если функция не типа void. В PowerShell функция (или любой скрипт-блок как в switch) может эмитировать любое количество результатов, и возвращаются они все. По умолчанию, эмитированые значения выводятся на экран. Но мы перехватываем результат оператора switch c помощью нотации подвыражения $(<statements>). Таким образом, эмитированый результат оператора становится значением подвыражения, а с этим значением можно сделать всё что угодно - хоть переменной присвоить, хоть в файл вывести.

Выразительные возможности PowerShell и оператора switch вполне соответствуют возможностям языка AWK. Из отличий хочется прежде всего упомянуть отсутствие автоматического разбиения на поля по разделителю. Строка обрабатывается целиком. Но называть это минусом я бы не стал. По моему (впрочем, небольшому) опыту, обработка строки целиком нередко оказывается даже более удобной. Кроме того, строку всегда можно разбить на поля с помощью методов String.split или Regex.split. Не стоит забывать, что ноги у PowerShell растут напрямую из .NET. PowerShell позволяет использовать более органичный синтаксис для перехвата групп регулярного выражения, чем AWK (там пришлось бы использовать такой шаблон: match($0, /%define name/, matches)).

PS: Написав всё это, я осознал, что данная задача настолько тривиальна, что можно было бы вполне обойтись двумя заменами регулярных выражений по всему тексту файла. Тем не менее, она неплохо иллюстрирует сходства и различия подхода к обработке текста в AWK и PowerShell.

Saturday, 3 July 2010

Загадка IBM Rational

Как удаётся сущестовать и преуспевать компаниям наподобие IBM Rational? Я думаю, часть ответа заключается в слове IBM. У этой компании огромный опыт на рынке.

Производство программного обеспечения никогда не было их сильной стороной, и большей частью они производили монструозные продукты вроде OS/360, WebSphere, линейка VisualAge, линейка Rational. Иногда бывают приятные проблески наподобие Eclipse. Который, впрочем, стоит существенно в стороне, т.к. разрабатывается по Open source модели и исключительно бесплатен.

Но благодаря богатому опыту ведения бизнеса и большим ресурсам, они могут оказывать значительно политическое и маркетинговое давление на другие компании, в первую очередь, достаточно крупные. Давление, естественно, происходит через топ-менеджмент. Топ-менеджмент обладает знаниями о высокоуровневых потребностях своего бизнеса, но понятия не имеет о конкретных потребностях тех людей которые непосредственно создают программный продукт: девелоперов, тестеров, архитекторов, билд мастеров, бизнес-аналитиков и так далее. Просто потому, что топ-менеджер либо никогда не был в этой категории, либо был, но давно, и, следовательно, его представления о потребностях частично устарели (т.к. технология не стоит на месте) и частично стёрлись из его памяти. И топ-менеджмент с радостью покупается на рекламные объявления IBM, которые специально пишутся так, чтобы быть убедительными для топ-менеджмента. Окрылённый топ-менеджер выкладывает круглую сумму, уверенный что он сразу получит стек продуктов, который покрывает весь жизненный цикл разработки программного продукта, и готовый процесс, который будет идеально работать в его ситуации. Кстати, круглость этой суммы во многом объясняется стоимостью этого значительного политического и маркетингового давления, а вовсе не стоимостью разработки этих продуктов или их уникальностью.

Стек продуктов и процесс - это другое ключевое оружие IBM Rational. Когда спустя некоторое время оказывается, что этот стек неудобен, что процесс не работает и не соблюдаются, то происходит несколько явлений:
  1. Топ-менеджер отказывается признать свою ошибку. Единственное, что ему остаётся это утешаться консультациями IBM продолжая отстёгивать им деньги; обвинять всех вокруг в том, что у них плохая квалификация для использования этих продуктов; требовать соблюдения процесса любой ценой, включая человеческие жертвы; утверждать что другие системы ничуть не лучше, т.к. лучшей быть не может в принципе; и так далее. Причина этого в том, что люди с неохотой признают свои ошибки, а чем больше ответственность и тяжелее последствия ошибки, тем существенней этот фактор. Надо отметить, что на момент покупки (скажем 2003 год) стек Rational действительно мог быть лучшим в своём классе. Но технология не стоит на месте и сейчас многие продукты Rational безнадёжно устарели, что ещё более усугубляется сложностью обновления хотя бы до их новейших версий - по причине цены.
  2. Цена миграции оказывается уже весьма высока и сравнима со стоимостью скажем годового владения стеком Rational или даже выше. Все артефакты уже хранятся в этих системах, все сотрудники уже наняты и обучены. Миграция требует больших расходов за короткий промежуток времени. Психологически, легче тратить понемногу, но в течение длительного промежутка, чем много, но сразу. Именно в этом состоит успех потребительского кредитования (с ипотечным кредитованием немного другая история, автокредиты находятся посередине). И компания продолжает тратить - понемногу, но постоянно (вспоминается анекдот: "Скупой платит дважды, тупой платит трижды, а лох платит постоянно").
  3. Миграция рискована и требует смелости. А люди не любят риск и изменения. Не стоит ожидать от топ-менежмента большой смелости. В первую очередь, от них стоит ожидать большой политической гибкости, иначе они не оказались бы и не удержались бы на своём месте. А значит, они будут стремиться сохранить статус кво, и волков сытыми, и овец целыми.
  4. Срабатывает следующий психологический эффект: "Мы уже потратили кучу денег на это. Переход на другое решение означает, что мы потеряем уже вложенные деньги. Так давайте доплатим ещё немного, всё вот-вот заработает!". А денег вложено действительно много, потому что этот стек требует кучи железа для своей нормальной работы, множества лицензий, высокоскоростной сети, а также специально обученных людей - администраторов.
  5. Администраторы активно защищают решения Rational внутри компании. Кроме того, поскольку они являются специалистами, их мнение имеет вес. Почему так происходит? Продукты Rational очень сложны и требуют специальной подготовки для своего администрирования. Администраторы за эту работу получают свои кровные. Чем больше возникает проблем с продуктами, тем чаще вынуждены пользователи обращаться к администраторам за помощью и тем ценнее они выглядят. Администраторы убеждены в важности и полезности своих продуктов, потому что они получили специальное образование и затратили на это много усилий, а, возможно, и своих собственных денег. Это образование, в частности, и направлено на создание впечатления важности и полезности. С другой стороны, администраторы, как и топ-менеджеры, тоже часто не в курсе конкретных потребностей пользователей, а знают только высокоуровневые потребности бизнеса - по тем же причинам. Если компания придёт к выводу, что продукты Rational необходимо заменить, то администраторы либо останутся без работы, либо будут вынуждены переучиваться.Таким образом, компания-клиент IBM Rational оказывается экономически и психологически привязанна к поставщику (vendor lock in).
В этом, как мне кажется, заключается секрет успеха IBM Rational, которые умудряются уже много лет успешно производить и продавать программные продукты для разработки программных продуктов, несмотря на тотальную нелюбовь со стороны подавляющего большинства разработчиков. И недостатки своих продуктов.

PS: Новое порождение IBM Rational - платформа Jazz. На видео выглядит неплохо. Но, опять же - цена, стек продуктов, сложность.. Я скачал бесплатную версию Rational Team Concert на 10 девелоперов. В архиве она занимает 764Мб, что заставляет думать о соответствующих системных требованиях. Лезть внутрь даже не хочется. У IBM Rational плохая репутация. Кажется, что Jazz - это всё тот же Rational волк в Agile шкуре.



3 reasons for not using Rational ClearCase

  1. Developers hate it.
  2. Developers really hate it!
  3. If you find some unbeatable ClearCase's feature that is sooo much necessary in your environment see reason number 1.

Friday, 30 October 2009

Гадание на кофейной гуще

Иногда в диких суевериях можно обнаружить зерно здравого смысла. Правда, его не так-то просто раскопать под слоями предрассудков , наросших за годы. Возьмём гадание на кофейной гуще. В прошлом это было довольно популярное занятие. Гадание на кофейной гуще считалось наиболее действенным по сравнению с прочими способами. Под гаданием подразумевается способ выяснить будущие или неизвестные события. Наверное, сейчас меньше людей чем в былые времена верят в то, что гадание действительно позволяет что-то предсказать. Но изобилие эзотерических центров и услуг говорит о том, что их, всё же, не мало. Впрочем, гадание может быть и просто развлечением - и весьма полезным.

Оставим в стороне вопрос о гадании одного человека другому, вместо этого рассмотрим случай, когда гадают сами себе. Есть ли в этом смысл? В рамках своего мировоззрения, я полагаю, что предсказать будущие события или выяснить что-то неизвестное таким образом нельзя. Я уверен, что сверхъестественное предсказание будущего – фикция. Тем не менее, определённый смысл в гадании на кофейной гуще, вероятно, есть.

Мозг человека состоит из двух полушарий, каждое из которых выполняет специфические функции нашего мышления. Условно говоря, правое полушарие отвечает за пространственное и визуальное мышление, за сопоставление с образцом, за интуицию, а левое – за вербальное, абстрактное и логическое мышление. Оба полушария и их функции, как несложно догадаться, необходимы. Полушария выполняют свои функции совместно для решения встающих перед нами задач. В идеале. Но в последние годы (лет так 30-40) крепнет мнение, что научно-техническая революция и порожденная ей социальная структура создали перекос в нашем мышлении в сторону логики и аналитического мышления. Действительно, успехи науки последних нескольких веков были бы невозможны без применения логики. Но абсолютизация логики и возведение её в ранг единственного средства познания лишает нас многого. На деле, функция логики, скорее, в верификации найденных решений, чем в их поиске. А как же поиск? А поиском занимается старательно ограничиваемое всей нашей культурой правое полушарие.

Для того чтобы исправить этот интеллектуальный дисбаланс и направить всю мощь человеческого мозга на решение задач, существуют разнообразные методики. Зачастую, они выглядят довольно странно для стереотипного взгляда людей технического мира. Одна из них называется потоком изображений (image streaming). Идея состоит в следующем. Человек остаётся в одиночестве, в спокойной обстановке. Он задаёт себе вопрос. После этого закрывает глаза, "отпускает" разум в свободное плавание, и начинает изучать возникающие перед глазами визуальные образы, стараясь увидеть их в деталях, почувствовать их остальными чувствами и описывая их вслух. В результате можно найти неожиданные ассоциации, идеи, которые могут приблизить к решению, или даже само решение. Можно конечно и ничего не найти. В таком случае вы просто размяли мозги и увлекательно провели 10 минут своего времени.

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

А теперь вспомним, как происходит гадание на кофейной гуще. Особым образом заваривается крепкий кофе, выпивается, громко задаётся интересующий вопрос. После этого, человек в течение некоторого времени изучает пятна, образуемые кофейной гущей, интерпретируя их. Да это тот же самый поток изображений! Только для там для индуцирования визуальных образов используется либо возможности самого мозга, либо свет или массаж глаз. Но с тем же успехом, можно индуцировать визуальные образы и наблюдая кофейную гущу (а также облака, огонь и тому подобное). Употребление перед гаданием тонизирующего напитка, создание таинственной атмосферы, применение "магических" заклинаний может также способствовать переходу мозга в режим, более подходящий для свободного поиска решений с помощью возможностей правого полушария.

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

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