среда, 26 августа 2015 г.

Shell executable jar


So, Java is rich on surpises, one can find some funny features in some pretty boring places. For instance, as boring as jar files.

Let's say, I 've got a jar which I run as usual:
java -jar my-fancy-app.jar
For this to work I need to add MainClass into manifest file, there is nothing to see there, except that jar files like this are called "executable" for some strange reason.

Then, if my program does something useful than it probably make use of some third-party libraries. And since I don't feel happy about annoying my users, I'd like to ship that libraries together with my application. Most common aproach is to use so-called "uber-jar" which contains third-party jars compiled into it. There is a maven plugin that can do so (sure, there is!), it installs it's own MainClass that installs it's own classloader and than yields for my MainClass. That classloader can load classes from jars inside the jar and is pretty much like one can find in the java tutorial from oracle.com.

While uber-jar is very convinient way for deploying an application, there are useful and important proprietary third-party libraries which have licences that don't allow me to bundle them inside my jar. And since one does not simply run java with both -jar and -cp options, I need a better solution. And there it is. I'd even say, sure there they are.

вторник, 25 августа 2015 г.

Как сделать jar, который может сам себя выполнить


Java богата сюрпризами, некоторые моменты откровенно радуют, некоторые забавляют. В целом, осваиваюсь, начинает нравиться. Обнаружил интересное, например, в том, как работает запускалка jar-файлов.

Типичное использование:
java -jar my-fancy-app.jar
Для того, чтобы это работало, нужно при сборке jar-файла указать исполняемый класс (MainClass), это всем известно, абитуриентов не принимают на первый курс, если они этого не знают.

Все программы, которые умеют делать что-то полезное, используют какие-то библиотеки, написанные другими людьми и заранее упакованные в другие -jar-файлы. Чтобы моё приложение могло их подцепить, мне нужно добавить их в classpath. Но когда я запускаю -jar, я не могу указать дополнительно другой classpath. Я не склонен винить кого-либо в этом ограничении, вопрос "почему" не настолько сильно меня беспокоит. Больше интересно, что делать.

Популярное решение: "uber-jar". Говорят, раньше у maven был плагин, который так назывался (сейчас для этого используется плагин shade). Он архивирует jar'ы зависимостей внутрь jar'а моего приложения и прописывает свой MainClass, который устанавливает свой classloader, а потом возвращает управление моей программе. Classloader загружает библиотеки из вложенных jar-файлов и не сильно отличается от того, который описан в одном из первых уроков по java на сайте оракла. Раньше, говорят, был плагин, который вообще jar'ы зависимостей распаковывал прямо в мой jar, ему даже classloader подменять не надо было.

Это решение может не работать в ситуации, когда одна из зависимостей имеет злобную лицензию, не позволяющую паковать её в свой jar. Поскольку указать дополнительный classpath при использовании ключа -jar нельзя, остаётся два варианта: поставить эту библиотеку в систему (типа $JAVA_HOME/lib/) либо не использовать ключ -jar. Как это не использовать?

понедельник, 10 августа 2015 г.

Чем старше становишься, тем сложнее становятся простые вещи

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

Я старательно пытаюсь вернуть то мироощущение, когда я не знал про эти грабли. Это очень круто: знать, как решать проблемы, с которыми ты уже сталкивался, знать, сколько проблем тебя ждёт, но продолжать, как в детстве, верить, что любое дело — простое, надо только за него взяться. Если посмотреть вокруг, то люди с таким отношением к делам есть, и у них неплохо получается. Вот буду брать с них пример.

воскресенье, 2 августа 2015 г.

Возвращение

Что же, я решил вернуться к своему слегка заброшенному блогу. Пару лет назад у меня начались события, которые серьёзно отвлекли меня от написания заметок. Потом была просто обычная жизнь, в которой я уже отвык от ведения блога. Сейчас мне кажется, что пора продолжить.

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

А эта заметка сделана просто для того, чтобы зафиксировать намерение писать по одному блогпосту в неделю. Я прекрасно понимаю, что стоит одну неделю пропустить — и привычка пропадёт, поэтому нужно будет сильно постараться. Это как бросать курить, только наоборот :-)

В общем, всем привет.

вторник, 6 августа 2013 г.

Гейзенбаг и Шрёдинбаг

Вот они и встретились.

У нас в проекте есть модуль А и модуль В. Они разрешаются лицензионными ключами. Каждый модуль может работать независимо от наличия другого модуля, но нужно, чтобы был активен хотя бы один, иначе программе можно вообще не запускаться. Всю жизнь у всех пользователей использовались оба модуля, а тут вдруг (практически, ВНЕЗАПНО), тестировщику понадобился только один из двух модулей. И ему, кстати, повезло ещё и с тем, что понадобился именно второй модуль. Повезло — потому что если убрать ключ на модуль А, то модуль В не включается, и потому что тестировщикам такие случайности очень нравятся. Оказалось, что модули инициализировались тупо по порядку:

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

Кстати, про коммунальные услуги

Тут один популярный блогер раскритиковал моего любимого Собянина за то, что в Москве грязно. Высказывался в резких выражениях, можно было даже предположить, что это единственная вообще проблема, которая его волнует. Но мы-то знаем, что это не так: не решена проблема с парковками, с пробками, с турникетами в общественном транспорте (когда уже?!) — это только то, что касается пешего и езжего транспорта, и то не всё. Но как минимум за уборку территорий я вступлюсь: на выборах 4 марта всем москвичам давали ещё второй бюллетень, так вот, возле кого галочки поставили — к тем и идите жаловаться. Уборка территории принципиально относится к самым местным руководителям, которые только возможны в федеративном устройстве нашего государства. Жаловаться на лужи тому, кто решает совершенно другого уровня задачи — всё равно, что жаловаться президенту на то, что до́ма окна прохудились. Привыкли, что в Питере сосульки Матвиенко лично лазерами пуляла, панимаишь.

воскресенье, 18 марта 2012 г.

Про важность статического анализа

Есть ряд багов, которые нельзя поймать ни тестами, ни тестировщиками. Потому что формально установить наличие ошибки по выхлопу нельзя. Собственно, настоящие, красивые, баги появляются именно так, а не так, как мы уже привыкли: те "баги", которые мы видим каждый день — это либо дефекты выбранного алгоритма, либо его "забытые" тёмные закоулки (необработанные ошибки, нереализованные ветвления, неосвобождённая память и т.п.). А эти ошибки можно найти только анализируя код. И даже если это будет не тот "настоящий, красивый баг", которым можно восхищаться годами, постоянно переоткрывая его в багзилле, но тоже может быть интересно.

Вот простой пример:
sub very_bin_integer($) {
    my $length = int(shift) or die "Illegal length";
    my $ret = '';
    for ( 1 .. $length )
    {
        my $n = 0;
        while ( not $n ) {   
            $n = int(rand(9));
        };
        $ret .= $n;
    }
    return $ret;
}
Даже обработка некорректного ввода есть. Кто напишет корректный юнит-тест на эту ошибку — может рассчитывать на пирожок.