понедельник, 22 марта 2010 г.

Ant Magic

Совсем недавно на проекте столкнулись с забавным поведением компиляции из анта. Решил описать, так как по моему это некорректное поведение анта. Вот так выглядит проект:
Код простой. Класс 1 вызывает метод класса 2.
  1. import test.sub2.Sub2;  
  2.   
  3. public class Sub1 {  
  4.    
  5.  public static void sub1() {  
  6.   Sub2.sub2();  
  7.  }  
  8.    
  9. }  
  10.   
  11. package test.sub2;  
  12.   
  13. public class Sub2 {  
  14.  public static void sub2() {  
  15.  }  
  16. }  
Класс Sub2 из другого модуля и не должен компилироваться с основным. Класс 1 тоже не должен компилировать с основным, они оба из модуля 2, но лежат в разных пакетах и пакет Sub1 по случайности не был исключён из компиляции основного модуля 1. Т.о. ант скрипт выглядит вот так:
  1. <project name="TestProject" default="compile">  
  2.   
  3.  <target name="compile">  
  4.   <delete>  
  5.    <fileset dir="bin">  
  6.     <include name="**/*.class"/>  
  7.    </fileset>  
  8.   </delete>  
  9.   <javac srcdir="src" destdir="bin">  
  10.    <exclude name="test/sub2/**" />  
  11.   </javac>  
  12.  </target>  
  13.   
  14. </project>  
Чего я ожидал, что класс Sub2 не будет компилироваться, так как я его исключил и будет ошибка компиляции так как Sub1 пытается импортировать класс, которого нет в classpath.
Но не тут то было, его тоже скомпилирует и всё пройдёт саксес. Хорошо тут специально симулированный простой случай, но начинается полная (_!_) когда Sub2 вызывает ещё какой-то класс, в котором есть специфические методы из библиотек, которых нет в classpath модуля1 и соответственно это умный ант разрулить не может. И человек рвёт на себе волосы, потому что по сути он всё сделал правильно, модуль 2 компилируется без проблем, какого падает компиляция модуля 1, хотя в его классах не было изменений, не понятно. Вообщем вот он какой magic.

суббота, 6 марта 2010 г.

Google Chrome vs (js performance) Opera 10.50

Я в шоке, я негодую! Как можно было заметить по моему блогу я фанат Google Chrome (хотя в целом фанат всей продукции корпорации Добра =D). В качестве основного интернет браузера уже давно только его использую. Но внутренние сервисы на работе иногда открыты по Оперой 10.10. Вот вечером вышел спор/обсуждение с коллегой. За короткий промежуток Opera 10.50 из альфы перешла в релиз. Но речь не об этом. А о том, что горячие норвежские парни переделали javascript движок, добавив модную JIT компиляцию. И знаете что?! Как я ни старался, ни на рабочем компьютере, ни на домашнем, Google Chrome (5.0.342.2 dev) не смог сделать Oper'у в SunSpider тесте! Я просто в шоке:
** TOTAL **:           1.14x as fast     657.2ms +/- 1.7%   576.8ms +/- 2.9%
Немного, но быстрее, и это печалит. Надеюсь потому что у меня Dev версия Хрома. Я уже к Хрому привык, а теперь снова надо думать и это не только потому js быстрее, они снова переделали интерфейс, теперь вкладки очень похожи на Хромовские. И в целом интерфейс стал отзывчивее. Хотя коллега говорит, что есть проблема с отображением и иногда даже паданием некоторых сайтов.
Норвежцы однозначно молодцы!!
UPD:  Производительность «Оперы» 10.50 - странно, а тут немного другие результаты, Хром немного делает оперу.

Результаты ещё пары тестов:

V8 Benchmark Suite - version 5
Google Chrome (5.0.342.2): 3241
Opera 10.50 : 3587

Peacekeeper
Google Chrome (5.0.342.2): 2954 Points
Opera 10.50: 2713 Points

В Peacekeeper всё таки Хром вырвался вперёд, но странно что в собственном V8 тесте не смог.

суббота, 27 февраля 2010 г.

XML - универсальное зло

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

    1. DSL (domain-specific language). Это настолько ужасное место для применение XML, что даже есть книги по тому как это эффективно делать. Моё мнение совпадает со старой статьёй Фаулера: Language Workbenches: The Killer-App for Domain Specific Languages?. Статья уже достаточно старая. Народ, есть же куча генераторов парсеров, которые выдают исходный код на куче всевозможных языков. В качестве рекламы, уже почти полгода как зарелизался продукт от JetBrains: Meta Programming System. Это действительно классная штука. Сам пока баловался только на уровни простых примеров. Но сами JetBrains выпустили отличный баг трекер на нём (сами его используем, язык поисковых запросов у них очень удобный). Я считаю не стоит ленится и сделать свой язык, при этом забыв про XML, и вы посмотрите, у вас получится отличный продукт. Хороший и жизненный пример это aspectj и spring aop. Во втором случае, как всегда в спринге, приходится писать здоровенный xml, а в первом просто немного простых директив непосредственно в коде, при этом отличная интеграция с эклипсом. Показывает например методы, на которые распространяется аспект. По моему даже обсуждать глупо, в этом случае однозначно свой велик.
    2. Разновидность первого, это различные конфигурационные файлы. Скажем так, это более простой случай DSL. Для Java мне кажется достаточно хорошим решением в замен являются аннотации. Очень-очень часто, смена конфигурации несёт переделку кода, так что все равно пересобирать проект. Если динамический язык как Python, то вообще нет вопросов. При использовании средств языка, при создании конфигураций, можно получить много бонусов при использовании IDE, более точный поиск и автоматический рефакторинг. Но, если действительно, нужен текстовый конфиг, который будет часто изменятся, то я считаю лучшее решение это YAML. Чем то напоминает JSON, только более расширенный. Убил бы человека, который придумал, что XML удобный для чтения формат, читать его конечно можно, но это не черта не удобно, столько уже этого насмотрелся во всяких java framework's. Вообщем, если действительно пишете очередной фреймворк, и вам нужны файлы конфигурации, пожалуйста присмотритесь к простым property файлам, может быть вам будет достаточно. Нет? Тогда может YAML, это действительно очень расширяемый и удобный формат, причём всяких парсеров, так же как для XML, для многих языков более чем достаточно.
    3. Обмен данными. Да, вот тут уделать XML не так легко. Рассмотрим два случая:
      1. Формат данных навряд ли будет изменятся. Спросите где это возможно? Например ETL приложение. Одним из ключевых элементов такого приложения является Промежуточное хранилище. В большинстве случаев, внутри такой системы элементы представляют собой словарь атрибутов. Поэтому в качестве промежуточного формата данных можно выбрать бинарный формат [name|value|....]. Причём например если известен максимальный размер имени и значения, при выборке, можно выбирать только нужные поля, пропуская в массиве байтов остальные. 
      2. Будет изменятся. Тут есть проблемы, можно конечно рассмотреть сериализацию объектов, но тогда может возникнуть проблема с десериализацией в разных языках. Можно присмотреться к уже реализованным бинарным протоколам, например Google Protocol Buffers. Конечно, если вам надо распарсить одну XML в час, то вам наверно всеравно, но если пару десятков тысяч в секунду, то приходится задумываться над эффективностью действий. Да и хранение + последующая выборка избыточны и не добавляют производительности приложению. Да, открытось бинарных протоколов оставляет желать лучшего, тогда возвращаемся к упомянутым выше YAML и JSON. Хотя бы для начала посмотрите, как можно решить вашу задачу с их помощью, перед тем как кричать XML.
В целом посыл поста был один. Не стоит использовать XML как универсальное средство решение любой проблемы, потому как есть более эффективные способы решить вашу проблему и стоит вначале оценить их и сравнить с волшебным XML'ем.

Google Chrome и Плагины

Google Chrome классный браузер, полюбил его за скорость и интерфейс. Раньше писал про плагины, которые у него появились. Это круто, что они работают в отдельных процессах, если один падает (что иногда случается так как сижу на dev канале хрома), то просто появляется сообщение и кнопочка перегрузить его. Но есть одна проблема, как только стартует первый процесс браузера, он стартует все плагины, у меня их 6, т.е. стартует ещё 6 процессов. А так как в процессе работы я часто закрываю и открываю его (привык начиная с первой версии хрома), то время первого старта браузера сильно замедлилось, что меня печалит. Поэтому теперь держу gmail открытым как приложение, остальные экземпляры стартуют быстрее. Но вообще да, как-то не очень получается с этими плагинами.
А ещё одно наблюдение, что-то страницы стали грузится не в отдельных процессах иногда, как-то страно это.

четверг, 11 февраля 2010 г.

Java: Read escaped quote as escaped quote from xml

Всё началось с того, что на проекте мы используем написанный нами фреймворк для автоматического тестирования. Многое в нём завязано на xml. В частности очень важная задача сравнение двух xml, "сравнитель" оброс большим количеством всевозможных плюшек. Вот понадобилось ещё одну реализовать. Подробно о ней написала моя коллега: StackoverFlow:Read escaped quote as escaped quote from xml. Ничего дельного ей не ответили до её ухода в отпуск. Задача мне показалась интересной, поэтому решил побаловаться с ней. Вкратце, проблема состоит в том, что когда DOM парсер строит дерево, к значениям элементов применяет unescaping. Нам бы хотелось, чтобы он так не делал, потому что нам надо сравнить два DOM дерева построенных по двум xml файлам, и убедиться именно в их идентичности, что эскейпинг проведен правильно.
На предыдущем проекте пришлось много сражаться с особенностями open source библиотек, которые мы использовали. Причём на форумах тоже было очень молчаливо, а задания делать надо было. Тогда я и заразился любовью в копании в исходниках open source библиотеки, чтобы решить свою проблему, очевидный и очень эффективный метод :)

воскресенье, 24 января 2010 г.

Dynamic Expressions

Всё началось с того, что был нужен простенький DSL, который бы возвращал бы bool по некоторому словарю объектов, т.е. удовлетворяет ли он условию заданному через DSL. Было у меня два поста, о том как написать свой парсер языка и о том, как с помощью Expressions tree, обработать дерево языка построенное парсером. Так я и делал вначале. Получилось несколько громоздко, меня покритиковали :) Поэтому решил упростить себе и другим жизнь, вот на этой странице C# Samples прочитав внимательно соглашение и нажав I accept, можно скачать набор примеров, в частности большое количество примеров по LINQ. И среди них есть папка LinqSamples\DynamicQuery. Там есть файл Dynamic.cs с набором классов, которые делают то, что я описал ранее, т.е. преобразуют текстовую запись LINQ в Expressions tree и далее компиляция его в делегат. Это просто замечательно, то что доктор прописал, готово и отлично работает. Внутри папки есть Dynamic Expressions.html файл с подробной инструкцией, а также таблицей поддерживаемых методов.
Вот например, то что я писал выше, создание простого калькулятора из примера:
  1. ParameterExpression argument = Expression.Parameter(typeof(int), "argument");  
  2. LambdaExpression e = DynamicExpression.ParseLambda(new ParameterExpression[] { argument }, null"argument + argument");  

Я использовал в своём приложении, очень удобно. Единство, пришлось сделать небольшой хак.

Expression trees: продолжаем писать компилятор

Обычно компилятор состоит из двух частей: парсер и генератор. Как быстро и легко написать парсер я уже писал LINQ: интересный подход к написанию парсеров.
Теперь займемся генератором. Вернее подход будет несколько другим. Я разрабатывал внутренний язык, который будет использоваться внутри .NET приложения, т.е. необходимо выполнить  инструкцию написанную на этом языке. И тут к нам на помощь придут Expression trees. Теперь подробнее...