Показаны сообщения с ярлыком java. Показать все сообщения
Показаны сообщения с ярлыком java. Показать все сообщения

пятница, 29 июля 2016 г.

Spring. Хоть и неплохой, но почему я его не люблю.

Не знаю, работали ли вы со спрингом, но я внесу свои 5 копеек на тему почему я его не люблю.
В нормальной спеке а ля J2EE есть чоткая граница между интерфейсами и реализацией. При этом несмотря на казенность языка J2EE спеки в принципе ее можно прочесть и обозреть. Спринг же это монстр с кишками наружу. Да еще и с отсутствием внятного иерархичного описания. То есть у него внутри кишки перемешаны - типа херачь не хочу. И снаружи доки переписаны - точки входа и построения нормального представления нет. Все нормальные спеки древовидные потому что если так, до даже если ты не знаешь куда тебе надо попасть ты всегда знаешь куда тебе идти. В плоской структуре чтобы понять куда тебе попасть тебе надо знать все про все. Это ахтунг.
Вот простой пример. Допустим я решил что хочу что-то сделать после инициализации бинов в контейнере. Казалось бы - иди в документацию, кури оглавние и там ищи что-то типа контэйнер state machine. Как бы не хуй. Иди в ClassPathXmlApplicationContext и кури конструктор. Иниибет. Ну это как бы норм для наколенной поделки, но тут как бэ версия 4.3.2. Не какая-то там альфа на хоум пейдже васи пупкина. Это проект, который дефакто используется в более чем половине всех джавских серверных (а может и клиентских) приложений. Который изначально создавался как легковесная замена JEE, а теперь собственно призван умирающего поциента собой заменить. И эти люди еще спрашивают меня паттерны и объясняют мне, что я плохой архитектор. А сами спринг юзают.
Появление спринга было бы невозможно 20 лет назад ввиду отсутствия интернета и поисковых машин. Типичный алгоритм решения проблемы сводится к "поищу как это сделали менее волосатые собратья в интернете, на крайняк посмотрю исходники". И это еще хорошо, что он неплохо написан, и неплохо документирован. Но господа смотреть исходники для того, чтобы попользовать самый популярный джавский фреймворк - не кажется ли вам это моветоном. Мне хватает простите "исследований" "труда" моих коллег. За глаза.
В общем печалька в том, что программист в наши дни превращается в сисадмина. Работа из разряда почитай документацию и сделай как написано. Найди. Повтори. Не то, чтобы это плохо - мамы всякие нужны. Но просто если бы лично мне нравилось сисадминить, то я бы пошел в сисадмины, а не программеры.

ЗЫ: Как я уже давно начал говорить проект либо развивается, либо умирает. Спрингу нужен рефакторинг. И нехер ссать на тему обратной совместимости. Это норм, что интерфейсы меняются, особенно для проекта в котором нужно рыть исходники, чтобы понять как сделать то и се. Движуха - добро если соблюдается баланс, не дает превращаться коду в болото. Как я, опять таки, давно начал говорить, не понимаешь как это работает - делай рефакторинг. Даже беспричинный рефакторинг хорош потому что дает тебе возможность разобраться как это устроено, особенно если код хорошо покрыт хорошими функциональными тестами.

Такие дела.

среда, 20 июля 2011 г.

Подключение ICEPush в Vaadin

Я не специалист в ICEPush и Vaadin. Но вот недавно возникла необходимость наговнять веб-приложение, которое будет динамически отображать изменение состояния сервера. Server push. Для веб-приложения я выбрал Vaadin ибо не понимаю html и css. Возник вопрос как реализовать Server push. Поиск сказал, что в Vaadin есть add-on icepush. Вроде бы все просто.

Я не буду писать как использовать IcePush - это все есть в примере.

Но возникли трудности. При запуске приложение выводило следующую белиберду:

Widgetset does not contain implementation for org.vaadin.artur.icepush.ICEPush. Check its @ClientWidget mapping, widgetsets GWT module description file and re-compile your widgetset. In case you have downloaded a vaadin add-on package, you might want to refer to add-on instructions. Unrendered UIDL:

org.vaadin.artur.icepush.ICEPush(NO CLIENT IMPLEMENTATION FOUND)


Оказалось, что в icepush используется клиентский код (код на GWT, работающий на стороне браузера) и для работы нуна создать свой widgetset и откомпилировать его. И почему то как это делается не описано в инструкции к icepush (правда описано в инструкции к vaadin)

Тут я и хочу описать шаги, необходимые для выполнения вышеописанного.

1) создаем файл с widgetset нашего приложения. Создается он в директории где лежат java исходники приложения, примерно в том же пакете, где лежит само приложение.

<module>
<!-- WS Compiler: manually edited -->

<!-- Inherit DefaultWidgetSet -->
<!--<inherits name="com.vaadin.terminal.gwt.DefaultWidgetSet">-->

<inherits name="org.vaadin.artur.icepush.IcepushaddonWidgetset">
<!--<inherits name="org.icepush.gwt.ICEpush">-->

<!-- adding support for icepush -->
<!--<script src="icepush.js"></script>-->

</module>



В изначальном руководстве строчки <inherits name="com.vaadin.terminal.gwt.DefaultWidgetSet" />, <inherits name="org.icepush.gwt.ICEpush" /> присутствовали, но поскольку этим модули наследуются в org.vaadin.artur.icepush.IcepushaddonWidgetset, то их можно не указывать.

Строчка <script src="icepush.js"> тоже присутствовала, но при этом выводилась сообщение, что этот файл (icepush.js) не был найден в директории widgetset-а, приходилось копировать его туда руками. Я ее удалил - без нее все работает.

2) Надо откомпилировать widgetset. Если вы используете maven, то надо добавить зависимости в pom.xml, и запустить соответствующий таргет. Я этого не делал и поэтому писать не буду - опишу если понадобится попробовать.
Я компилировал widgetset через ant.

Берем дистрибутив vaadin, достаем оттуда файл WebContent/docs/example-source/build-widgetset.xml, копируем этот файл себе в проект. Изменяем таргеты, которые отвечают за установку разных property (например путь к файлу widgetset). Этот скрипт занимается еще и компиляцией проекта. Поскольку мой проект имеет немного более сложную систему зависимостей, а копировать все в WEB-INF/lib мне неохота, то я тупо выкинул таргет compile-server-side из ant скрипта build-widgetset.xml и указал переменную server-side-destination на уже откомпилированные классы.

Запускаем ант.
ant -f build-widgetset.xml


При этом у меня возникли проблемы. Таска java из таргета compile-widgetset ругалась на то, что кончилась память и предлагала установить параметр -Xmx128M. На самом деле кончалась память в Perm Gen:
    [java]    Compiling 6 permutations
[java] Compiling permutation 0...
[java] Compiling permutation 1...
[java] [ERROR] OutOfMemoryError: Increase heap size or lower gwt.jjs.maxThreads
[java] java.lang.OutOfMemoryError: PermGen space
[java] at sun.misc.Unsafe.defineClass(Native Method)


и необходимо было установить -XX:MaxPermSize=128M. Вот как стало выглядеть
 <java classname="com.google.gwt.dev.Compiler"
failonerror="yes" fork="yes" >
<arg value="-war" />
<arg value="${client-side-destination}" />
<arg value="${widgetset}" />
<jvmarg value="-Xms256M"/>
<jvmarg value="-Xmx256M"/>
<jvmarg value="-XX:PermSize=128M"/>
<jvmarg value="-XX:MaxPermSize=128M"/>
<jvmarg value="-Xss1024k"/>
<jvmarg value="-Djava.awt.headless=true"/>
<classpath>
<path refid="compile.classpath"/>
</classpath>
</java>


Я ставлю сразу ms и mx и PermSize и MaxPermSize потому что так быстрее, а память есть.

В результате компиляции widgetset появилась директория с кучей файлов в директории ${client-side-destination}. Название директории совпадает с названием нашего widgetset. В веб приложении это должно лежать в /VAADIN/widgetsets.

3) Добавляем параметр в сервлет. Теперь наш web.xml выглядит так
<servlet>
<servlet-name>ICEPush for Portlets</servlet-name>
<servlet-class>org.vaadin.artur.icepush.ICEPushServlet</servlet-class>
<init-param>
<param-name>application</param-name>
<param-value>com.jnetx.app.colt.ui.ColtUi</param-value>
</init-param>
<init-param>
<description>ColtUi widgetset</description>
<param-name>widgetset</param-name>
<param-value>com.jnetx.app.colt.ui.ColtUiWidgetSet</param-value>
</init-param>
<!--<param-value>org.vaadin.artur.icepush.IcepushaddonWidgetset</param-value>-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ICEPush for Portlets</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>


После этого работают обновления, инициированные сервером.

PS: Не забудьте добавить pusher в mainWindow.