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.