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

Прикольный workaround для деплоя репортов в Reporting Services

Reporting Services штука полузная. Сделаные в VS репорты для него можно деплоить по разному. Через web интерфейс, с помощью SQL Server Management Studio. Но иногда нужны автоматические скрипты. Для этого есть утилитка rs.exe.
rs.exe -i MyReportScript.rss -s http://localhost/reportserver
MyReportScript.rss - это скрипт на VB, который и загружает репорт или репорты.
Вот так примерно выглядит код загрузки:

  1. Try
  2.   Dim stream As FileStream = File.OpenRead(reportName + ".rdl")
  3.   definition = New [Byte](stream.Length) {}
  4.   stream.Read(definition, 0, CInt(stream.Length))
  5.   stream.Close()
  6.   Catch e As IOException
  7.   Console.WriteLine (e.Message)
  8. End Try
  9.  
  10. Try
  11.   warnings = rs.CreateReport(reportName, reportsPath, True, definition, props)
  12.   Console.WriteLine("Upload Report: {0}.", reportName)
  13.   Catch e As Exception
  14.   Console.WriteLine (e.Message)
  15. End Try

Репорты делал не я и делались они 2005 студии. У меня стоит 2008, после пары изменений, я получаю вот такое сообщение:
System.Web.Services.Protocols.SoapException: The report definition is not valid.  Details: '.', hexadecimal value 0x00, is an invalid character. Line 4334, position 10.
Через Management Studio загружается нормально.
Конечно же файл репорта представляет из себя просто ужасный xml. И что мы видем в строчке 4334? Заключительный закрывающийся тэг:
Становится совсем не понятно, но всемогущий гугль легко находит линку:
RS.EXE fails to deploy a report upgraded from SQL Server 2005 Reporting Services - "report definition is not valid"
Предложенное решение проблемы меня просто поставило в тупик

  1. Replacing
  2.      My_Byte_Array = New [Byte](stream.Length) {}
  3. With
  4.      My_Byte_Array = New [Byte](stream.Length - 1) {}

Вообщем даже не представляю как это у них получилось cгенерировать такую проблему в новой студии, вообщем просто в шоке =D
Хотя я иногда и по круче отжиги делаю :)

З.Ы.: Сорри за не самую красивую подсветку, просто мой любимый Online syntax highlighter что-то с VB на отрез отказался работать, а HTML Source Code Syntax Highlighter хоть и подсвечивает код, но не очень красиво.

З.Ы.Ы.: Катя подсказала более крутой сервис для подсветки кода, так как ей нужен был Object C, то она нашла вот этот, количество языков поражает. Только надо выбрать опцию Combine Style and HTML, чтобы он не генерировал отдельно css стиль, а всё выдавал html кодом. Качество подсветки хорошее.

воскресенье, 18 апреля 2010 г.

Java - отличная платформа, но слишком неповоротливый язык.

Хотел поделится порцией очевидностей. Java - это действительно отличная платформа для разработки, с больших комьюнити, огромным числом Open Source библиотек, инструментов и т.п. Но вот язык Java этой платформы слишком устарел. Лично я не поклонник нагромождения синтаксического сахара, как например в Ruby. Но я сравниваю с C# и там есть много действительно полезных плюшек, практически полезных (я вообще пишу только о том, с чем лично столкнулся).
Вот два небольших примера.
1. Есть очень популярная задача, организовать конвейер для обработки документов, которые по сути из себя представляют Map или, если говорим о C#, Dictionary. К Dictionary в дот нете, у меня есть одна большая претензия, он слишком часто кидает исключения. Но речь не об этом. Вот так выглядит простой документ, я добавил в него метод AddProperty, с помощью которого можно не только добавить элемент, но и перезаписать старый:
  1. public class Document : Dictionary<string, object>  
  2.     {  
  3.         public Document AddProperty(string name, object value)  
  4.         {  
  5.             if (ContainsKey(name))  
  6.                 Remove(name);  
  7.   
  8.             Add(name, value);  
  9.             return this;  
  10.         }  
  11.     }  
Собственно ничего интересно, за исключение полезной штучки, метод возвращает не void, а самого себя.
API конвейера тоже простое:
  1. public class Pipeline  
  2. {  
  3.     public void AddProccessor(Func<Document, Document> proccessor)  
  4.     {  
  5.     }  
  6.   
  7.     public void Execute()  
  8.     {  
  9.     }  
  10. }  
Вот тут почти самый главный момент. Делегаты это хорошо, мне надоели в том же свинге листенеры с одним методом, это ужас какой-то.
Но самое интересное теперь. Иногда требуется добавить очень простую обработку, которая просто добавляет пару полей к документу. В java пришлось бы поступить как в свинге, анонимный класс с реализацией метода интерфейса листенера. Но в C# коллега подсказал очень и очень красивое решение:
  1. var pipeline = new Pipeline();  
  2. pipeline.AddProccessor(record => record.AddProperty("NewProp", "Value").AddProperty("AnotherProp", 1));  
Действительно в одну строчку.
2. На эту тему копий сломано не мало, перегрузка методов или параметры по умолчанию. Кто бы, что ни говорил, но C# 4.0 c параметрами по умолчанию плюс именование параметров, лично для меня, отличное, красивое и удобно решение.
Вот есть метод:
  1. public static string format(string value,   
  2.             bool option1 = false, bool option2 = false)  
  3. {  
  4.     return value;  
  5. }  
Параметры по умолчанию позволяют не забивать и так не маленькие исходные тексты кучей не нужного текста. Но к сожалению они не идеальны без одной маленькой штучки. Вот скажите, что надо сделать, чтобы вызвать описанный метод, но чтобы option2 был true. Придется или перегружать метод, или при вызове передавать false для option1. Но проблема решена в C# 4.0. При вызове метода передаваемые параметры можно именовать, так что теперь можно не беспокоиться об очерёдности параметров, а также решить указанную выше проблему простым способом:
  1. format("test", option2: true);  
Да, для JVM есть много интересных альтернативных языков, например мне нравится Clojure. Но например у него есть проблемы с производительности и вообще, его активно портируют на CLR. Хотелось бы, чтобы и основной язык платформы более активно развивался.

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

И совсем напоследок цитата дня (которую правда уже постил в Buzz'е, но уж больно понравилась):
  1. select fun, profit from real_world where relational=false  

понедельник, 5 апреля 2010 г.

Java Decompiler

Да, по названию поста будет понятно о чём речь :)
По старой традиции использовал для этих целей всегда JAD. Но он уже достаточно давно заброшен и не справляется с некоторыми фишками. Нашёл хорошую альтернативу, так прям и называется Java Decompiler. Работает как отдельное приложение, так и как плагин к эклипсу.
Больше всего не давали жить две штуки (исходники, которые мне нужны, были просто напичканы ими): ассерты и дженерики. Вот на составил небольшой демонстрационный примерчик:
Исходный текст:

  1. public class Example {  
  2.       
  3.     public class Doing<T extends Some> extends Base<T> {  
  4.         @Override  
  5.         public T doSomething(T param) {  
  6.             assert(param == null);  
  7.             return param;  
  8.         }  
  9.     }  
  10.   
  11.     public abstract class Base<T extends Some> {  
  12.         public abstract T doSomething(T param);  
  13.     }  
  14.   
  15.     public class Some {  
  16.         public Some doing() {  
  17.             return this;  
  18.         }  
  19.     }  
  20.       
  21. }  
То что выдал JAD:
  1. // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.  
  2. // Jad home page: http://www.kpdus.com/jad.html  
  3. // Decompiler options: packimports(3)   
  4. // Source File Name:   Example.java  
  5.   
  6. public class Example {  
  7.     public abstract class Base {  
  8.   
  9.         public abstract Some doSomething(Some some);  
  10.   
  11.         final Example this$0;  
  12.   
  13.         public Base() {  
  14.             this$0 = Example.this;  
  15.             super();  
  16.         }  
  17.     }  
  18.   
  19.     public class Doing extends Base {  
  20.   
  21.         public Some doSomething(Some param) {  
  22.             if (!$assertionsDisabled && param != null)  
  23.                 throw new AssertionError();  
  24.             else  
  25.                 return param;  
  26.         }  
  27.   
  28.         final Example this$0;  
  29.         static final boolean $assertionsDisabled = !Example  
  30.                 .desiredAssertionStatus();  
  31.   
  32.         public Doing() {  
  33.             this$0 = Example.this;  
  34.             super();  
  35.         }  
  36.     }  
  37.   
  38.     public class Some {  
  39.   
  40.         public Some doing() {  
  41.             return this;  
  42.         }  
  43.   
  44.         final Example this$0;  
  45.   
  46.         public Some() {  
  47.             this$0 = Example.this;  
  48.             super();  
  49.         }  
  50.     }  
  51.   
  52.     public Example() {  
  53.     }  
  54. }  
И наш чемпион Java Decompiler:
  1. public class Example {  
  2.     public abstract class Base<T extends Example.Some> {  
  3.         public Base() {  
  4.         }  
  5.   
  6.         public abstract T doSomething(T paramT);  
  7.     }  
  8.   
  9.     public class Doing<T extends Example.Some> extends Example.Base<T> {  
  10.         public Doing() {  
  11.             super(Example.this);  
  12.         }  
  13.   
  14.         public T doSomething(T param) {  
  15.             assert (param == null);  
  16.             return param;  
  17.         }  
  18.     }  
  19.   
  20.     public class Some {  
  21.         public Some() {  
  22.         }  
  23.   
  24.         public Some doing() {  
  25.             return this;  
  26.         }  
  27.     }  
  28. }  
Разница заметна на лицо, комментарии излишни :)

Подсветка кода

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

Единственный недостаток, с <, > вообщем запрещёнными символами, которые, например, встречаются в LINQ выражениях. Придётся самостоятельно делать эксейпинг.

Да, и ещё одним преимуществом такого статического подхода, является корректное отображения кода в RSS ридерах и пр. трансляторах, js они не могу проинтерпретировать, а со статичным html'ем справляются на ура.

UPDATE: Не знаю как просмотрел, но есть отличная js библиотечка для динамической подсветки highlight.js от Ивана Сагалаева. Поддерживает целых 35 языков и всё время пополняется, кроме того, у неё есть отличный набор из более чем десятка тем. Я себе под новый дизайн выбрал Dark.

<?xml version="1.0"?>
<response value="ok" xml:lang="en">
  <text>Ok</text>
  <comment html_allowed="true"/>
  <ns1:description><![CDATA[
  CDATA is <not> magical.
  ]]></ns1:description>
  <a></a> <a/>
</response>

понедельник, 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'ем.