Много плюсов за статью, но ни одного комментария о самом инструменте формального анализа! Ведь это отличная вещь с великолепными потенциалом — один раз описываем контракт для метода и не беспокоимся о его содержимом — всё и так будет проверяться :)
А вообще кто-нибудь пользовался подобными вещами? Я так понял, это подобие контрактного программирования. Только более мощное. В IDEA есть аннотация Contract, которая позволяет выполнить простые проверки входных и выходных данных — описываем с помощью этой аннотации контракт для метода (что будет при подаче тех или иных значений), а дальше IDE сама проверят, что метод соответствует этому контракту.
Я хоть и плюсик за статью поставил, но она практически ни о чём — что за changeset (по статье можно догадаться, что это такое, но не плохо было бы объяснить, это явно), как похожие функции реализованы в других СУБД, как у вас на проекте используется этот функционал — ничего такого нет. Только краткое описание.
Ну, собственно, вопросы: Вы на других СУБД видели похожие вещи? И как Вы используете у себя changeset на проекте? Так сказать, практическое применение.
У нас, например, для Oracle просто пишем скрипты на изменения — один файл содержит набор изменений в пределах одного коммита — потом при накате на прод эти скрипты группируются и накатываются скопом. Rollback практически не используется.
А кстати, хороший вопрос! Что вы понимаете под тестированием пользовательского интерфейса? Полную имитацию нажатия на кнопочки, галочки, выбор из списка и т.п.? Или проверку логики работы UI? Я в работе использовал и использую два подхода для тестирования UI — и полная имитация пользователя (например, с помощью того же пресловутого Selenium'а) и тестирование логики UI (MVP в этом оооочень сильно помогает). Так вот, тестирование только логики, на мой взгляд вполне оправдано — при это покрывается очень большая часть функционала. А нетестируемая часть пишется насколько простой, чтобы в ней можно было совершать минимум ошибок. Я тут даже статью написал по этому поводу habrahabr.ru/post/246285/
P.S. Вообще это мысли не мои — в офф. доках GWT пишут про MVP и Мартин Фаулер это говорил.
Ну для меня математика проста — я пользуюсь IDEA, она покрывает процентов 70 моих потребностей на работе — тут и Java, Groovy, Python, Gradle, возможность подключаться к СУБД, редактирование xml, xslt. И при всём этом она обошлась мне в этом году долларов за 60 (случайно при продлении лицензии попал на скидку в 40%). В прошлом году она для меня стоила $200. И тут JRebel, который (конкретно в моём случае) может только чуть чуть ускорить деплой изменений при разработке. Это, в процентном соотношении, не более 2% всей моей работы. И при этом есть бесплатные альтернативы. Да, не такие мощные, как jRebel, но часть его функций могут покрыть. И при этом стоит он $365, а это в 6 раз дороже моего основного инструмента для работы. В общем, для меня нет ни малейшего повода его покупать.
P.S. Спасибо за коммент.
Отличная статья, интересно было почитать!
Для разработки я использовал DCEVM (вот статья habrahabr.ru/post/236075/ ) Для прода не подойдёт, т.к. там JVM подменяется, но для локального использования самое то — бесплатен и хорошо работает.
Про jRebel согласен — стоит очень дорого. Я даже не представлю такого use-case для себя, чтобы он окупился.
P.S. Спасибо за выкладывание classloader'а на GitHub!
Кстати, вопрос немного в сторону — я только что узнал про type annotations, которые упоминались в статье ( docs.oracle.com/javase/tutorial/java/annotations/type_annotations.html ) Судя по докам, эти аннотации позволяют проще писать nullable анализ. Правильно? Ну, в смысле, одно из возможностей их использования.
И вообще, кто нибудь работал с ними?
У нас тоже аннотации используются — отличная вещь, позволила найти/не допустить несколько ошибок. Плюс это такой зачаток программирования по контракту — когда определяешь метод сразу же аннотируешь возвращаемое значение и входные параметры. И потом проще его писать — не думаешь о том — будет тут null или нет, т.к. всё указано аннотациями плюс IDE проверяет. Ну и использовать этот метод проще — всё помечено аннотациями. Даже бывало укажешь аннотации для метода, а потом смотришь его использование, а там IDE показывает не нужный код — фактически метод возвращает не null, а в местах использования метода проверялось на null и этот код можно сразу удалить :)
Ещё пару замечаний по этим аннотациям и IDEA — у нас на разных проектах разные аннотации использовались в качестве NotNull И Nullable и получается, как только импортируешь проект, нужно не забыть указать эти аннотации в IDEA в качестве аннотаций NotNull и Nullable. Что хоть и не долго но не приятно и иногда забываешь. В общем, для проекта с gradle я сделал такую штуку:
/*
Установить настройки проекта для IDEA. Используется отдельная задача, т.к. задача idea в gradle не поддерживает настройки
проекта, который оформлен в виде директорий (так с 14 IDEA работает). Поэтому нужно править xml файл настроек проекта
отдельно.
*/
task setupProject << {
//xml файл настроек IDEA
File miscXmlFile = new File("./.idea/misc.xml")
// Если файла нет, то выходим. Нужно, чтобы не было ошибок в Jenkins, когда не создаются IDEA конфигурации.
if (!miscXmlFile.exists()) {
return;
}
XmlParser xmlParser = new XmlParser()
Node miscXml = xmlParser.parse(miscXmlFile)
// Указываем настройки NotNull и Nullable аннотаций для проекта.
Node nullableNotNullManagerNode = miscXml.component.find { it.@name == "NullableNotNullManager" } as Node
if (nullableNotNullManagerNode) {
miscXml.remove(nullableNotNullManagerNode)
}
miscXml.append(xmlParser.parseText('''
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="com.my_company.npe.Nullable"/>
<option name="myDefaultNotNull" value="com.my_company.npe.NotNull"/>
<option name="myNullables">
<value>
<list size="5">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable"/>
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable"/>
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable"/>
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable"/>
<item index="4" class="java.lang.String" itemvalue="com.my_company.npe.Nullable"/>
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="5">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull"/>
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull"/>
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull"/>
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull"/>
<item index="4" class="java.lang.String" itemvalue="com.my_company.npe.NotNull"/>
</list>
</value>
</option>
</component>'''
))
XmlNodePrinter nodePrinter = new XmlNodePrinter(new PrintWriter(new FileWriter(miscXmlFile)));
nodePrinter.preserveWhitespace = true
nodePrinter.print(miscXml)
}
Эта задача позволяет автоматически указывать свои аннотации для проекта. Можно добавить её в задачу «idea», чтобы эти аннотации автоматически конфигурировались при загрузки проекта в IDEA. Пока так не стал делать, т.к. тестировал. При выполнении задачи переоткрывать проект не нужно — IDEA сама подхватит изменения. Плюс я тут вручную xml правлю, т.к. у меня не получить на таком низком уровне работать с конфигами IDEA в gradle.
Да, поведение разное. Ну это аргументированно тем, что если ошибка произошла (в Java это называется исключением) то и не нужно дальше продолжать работать — типа, это не нормальное поведение, поэтому дальше код выполнять не нужно. А в Go какая философия по этому поводу? Если метод выполнился с ошибкой, то дальше можно работать? Это я почему спрашиваю — часто в try/catch происходит работа с методами, которые могу вернуть ошибки и если каждый раз проверять возвращаемое значение, то будет долго. Например операции ввода/вывода — они практически все могут вернуть ошибку.
Был на прошлой Java конференции на выступлении Вашей компании — интересно рассказывали о единой платформе — и Web (с GWT и Vaadin) и Desktop (с Swing). :)
А теперь по статье — а Вы GWT какой версии используете? До 2.7 SuperDevMode не удобный — нужно перекомпиливать весь проект при малейшем изменении, а это долго. В 2.7 появилась инкрементальные компиляция, которая кардинально меняет дело. Но до 2.7, на мой взгляд удобнее пользоваться DevMode. Или Вам не часто нужно менять GWT Client код с перекомпиляцией всего?
И IDEA у Вас какой версии? В IDEA 14 (реклама!) отличная поддержка GWT — в GWT плагине используется github.com/branflake2267/superdevmode-launcher-legacy (насколько я понял) который позволяет запускать code server вместе с web сервером (как обычный DevMode) плюс не нужно явно перекомпилировать код с помощью закладок в браузере. Далее, IDEA поддерживает source map и, если запустить, браузер с IDEA плагином (я работал в Chrome) то можно отлаживать Java код в IDE (как в DevMode). Свои ограничения там конечно же есть (по сравнению в DevMode и Java), но, на мой взгляд, работает лучше чем в браузере.
Собственно, напишу, что узнал:
Альтернативный запуск SuperDevMode
По мимо использования стандартного DevMode можно использовать реализацию DevMode с поддержкой SuperDevMode без запуска отдельно code server и servlet container’а. Скачать её можно здесь: github.com/branflake2267/superdevmode-launcher-legacy
Благодаря этой реализации так же ненужно явно вызывать компиляцию GWT через закладки в браузере – компиляция будет происходить автоматически (вроде как, перепроверить – проверено в IDEA, но возможно это преимущество GWT плагина IDEA).
Ремарка по поводу GWT 2.7
В GWT 2.7 добавили инкрементальную компиляцию, которая включена по умолчанию и позволяет не перекомпилировать весь проект. Т.ч. в идеале «горячий» старт в SuperDevMode будет таким-же или даже меньше чем в DevMode. Нужно только прописать –noprecompile и указать –workDir и –launcherDir (чтобы использовались конкретные папки, которые не сотрутся после перезапуска сервера) чтобы повторно не компилировать код при перезапуске сервера.
«Холодный» старт остаётся таким же долгим – происходит полная GWT компиляция.
Замечания о IDEA 14
В IDEA 14 доработали поддержку SuperDevMode – запуск SuperDevMode происходит также, как и просто DevMode, без необходимости запускать отдельно code server и servlet container и не нужно использовать закладки браузера для явного запуска компиляции – компиляция будет происходить при обновлении страницы.
Для того что бы компиляция не происходила каждый раз при перезапуске приложения, нужно в настройках запускаемой конфигурации явно указать папки workDir и war в поле Dev Mode parameters. Папка workDir – любая существующая папка, папка war – папка с web приложением, в которую будут компилироваться модули GWT. Пример:
-workDir D:\project\osbb_gradle\osbb_web\code_server_work_dir -war D:\project\osbb_gradle\osbb_web\src\main\webapp
Также нужно добавить памяти VM (VM options):
-Xmx1024m
Явно указывать папки workDir и war нужно потому что по умолчанию IDEA при каждом запуске копирует содержимое webapp папки в новую временную папку и запускает приложение уже там. Из-за чего скомпилированные в прошлый раз модули не используются и компиляция происходит заново. Но если указать явно папки, то при каждом запуске будут использоваться те же самые папки с уже скомпилированными модулями.
Что бы не компилировать модули в существующую папку приложения, можно при запуске приложения копировать её в другое место и использовать уже там, но при повторном запуске не очищать её. Т.о. существующая папка с приложением останется нетронута.
Использовали MyBatis на несколько больших проектов. Только хорошие впечатления.
Из того что не указал автор — возможность создание TypeHandler'ов. Простой пример — в Java есть Enum со списком значений и нужно его замапить на значения из колонки. Создаётся TypeHandler — класс, который отвечает за преобразования этого объекта из Java в СУБД и наоборот, прописывается в маппинге запроса и всё. Дальше при выполнении запроса получает типизированные объекты. Мы использовали TypeHandler'ы для структур, списка структур, Enum'ов (шаблонный TypeHandler).
Также маппинги можно прописывать в интерфейсе (не скажу что это всегда удобно, но по крайней мере есть возможность не использовать xml).
Так же для IDEA есть отличный плагин по работе с MyBatis — plugins.jetbrains.com/plugin/7293. Я пробовал разные плагины для MyBatis, но этот оказался самый лучший. Из плюсов — подсветка синтаксиса в xml, autocomlite в xml, автопроверка соответствия интерфейса xml маппингу и наоборот, связывание методов интерфейса с маппингом (можно просто перейти в реализацию метода из интерфейса в xml — как к реализации метода интерфейса в классе). Также если настроить подключение к СУБД в IDEA, работает autocomplite по SQL запросам в xml (Например, если у нас в СУБД есть таблица students то если пишем в xml маппинге SELECT * FROM st и нажимаем Ctrl+Space IDEA подскажет, что можно выбрать таблицу students)
P.S. Работали с СУБД Oracle. В основном был вызов хранимых процедур и функций. Но были и select, и update.
Ну для Arduino проблема с дебагером — не проблема — там всё равно дебажить ни как нельзя :-D
Ребята из VisualMicro сделали свой костыль для дебага, но там у них не тру дебаг.
Да, Вы знаете, Open project тоже работает :) Import делал по аналогии с IDEA — если проект не IDEA проект (т.е. не содержит в себе папку .idea) то его нужно импортировать. Тут так же поступил — это CMake проект без папки .idea и по этому его импортировал.
Уточню — я говорю про методы в CMakeLists.txt файле. Честно говоря не знаю, как они правильно называются, т.к. я больше по Java :)
Я имею ввиду, когда в CMakeLists.txt есть строчка
То нельзя по Ctrl+click или Ctrl+B перейти на декларацию метода, пишет — «Cannot find declaration to go to».
Файлы входят в проект с точки зрения CLion, они не серые, в отличие от некоторых других файлов (т.е. есть с чем сравнить).
Если этого примера не достаточно, то можно скачать проект github.com/TimReset/arduino-cmake и посмотреть самим.
А вообще кто-нибудь пользовался подобными вещами? Я так понял, это подобие контрактного программирования. Только более мощное. В IDEA есть аннотация Contract, которая позволяет выполнить простые проверки входных и выходных данных — описываем с помощью этой аннотации контракт для метода (что будет при подаче тех или иных значений), а дальше IDE сама проверят, что метод соответствует этому контракту.
Ну, собственно, вопросы: Вы на других СУБД видели похожие вещи? И как Вы используете у себя changeset на проекте? Так сказать, практическое применение.
У нас, например, для Oracle просто пишем скрипты на изменения — один файл содержит набор изменений в пределах одного коммита — потом при накате на прод эти скрипты группируются и накатываются скопом. Rollback практически не используется.
P.S. Вообще это мысли не мои — в офф. доках GWT пишут про MVP и Мартин Фаулер это говорил.
P.S. Спасибо за коммент.
Для разработки я использовал DCEVM (вот статья habrahabr.ru/post/236075/ ) Для прода не подойдёт, т.к. там JVM подменяется, но для локального использования самое то — бесплатен и хорошо работает.
Про jRebel согласен — стоит очень дорого. Я даже не представлю такого use-case для себя, чтобы он окупился.
P.S. Спасибо за выкладывание classloader'а на GitHub!
И вообще, кто нибудь работал с ними?
Ещё пару замечаний по этим аннотациям и IDEA — у нас на разных проектах разные аннотации использовались в качестве NotNull И Nullable и получается, как только импортируешь проект, нужно не забыть указать эти аннотации в IDEA в качестве аннотаций NotNull и Nullable. Что хоть и не долго но не приятно и иногда забываешь. В общем, для проекта с gradle я сделал такую штуку:
Эта задача позволяет автоматически указывать свои аннотации для проекта. Можно добавить её в задачу «idea», чтобы эти аннотации автоматически конфигурировались при загрузки проекта в IDEA. Пока так не стал делать, т.к. тестировал. При выполнении задачи переоткрывать проект не нужно — IDEA сама подхватит изменения. Плюс я тут вручную xml правлю, т.к. у меня не получить на таком низком уровне работать с конфигами IDEA в gradle.
Например:
Нужно каждый раз проверять что err не null?
С try/catch будет всего один catch блок.
А теперь по статье — а Вы GWT какой версии используете? До 2.7 SuperDevMode не удобный — нужно перекомпиливать весь проект при малейшем изменении, а это долго. В 2.7 появилась инкрементальные компиляция, которая кардинально меняет дело. Но до 2.7, на мой взгляд удобнее пользоваться DevMode. Или Вам не часто нужно менять GWT Client код с перекомпиляцией всего?
И IDEA у Вас какой версии? В IDEA 14 (реклама!) отличная поддержка GWT — в GWT плагине используется github.com/branflake2267/superdevmode-launcher-legacy (насколько я понял) который позволяет запускать code server вместе с web сервером (как обычный DevMode) плюс не нужно явно перекомпилировать код с помощью закладок в браузере. Далее, IDEA поддерживает source map и, если запустить, браузер с IDEA плагином (я работал в Chrome) то можно отлаживать Java код в IDE (как в DevMode). Свои ограничения там конечно же есть (по сравнению в DevMode и Java), но, на мой взгляд, работает лучше чем в браузере.
Собственно, напишу, что узнал:
Альтернативный запуск SuperDevMode
По мимо использования стандартного DevMode можно использовать реализацию DevMode с поддержкой SuperDevMode без запуска отдельно code server и servlet container’а. Скачать её можно здесь:
github.com/branflake2267/superdevmode-launcher-legacy
Благодаря этой реализации так же ненужно явно вызывать компиляцию GWT через закладки в браузере – компиляция будет происходить автоматически (вроде как, перепроверить – проверено в IDEA, но возможно это преимущество GWT плагина IDEA).
Ремарка по поводу GWT 2.7
В GWT 2.7 добавили инкрементальную компиляцию, которая включена по умолчанию и позволяет не перекомпилировать весь проект. Т.ч. в идеале «горячий» старт в SuperDevMode будет таким-же или даже меньше чем в DevMode. Нужно только прописать –noprecompile и указать –workDir и –launcherDir (чтобы использовались конкретные папки, которые не сотрутся после перезапуска сервера) чтобы повторно не компилировать код при перезапуске сервера.
«Холодный» старт остаётся таким же долгим – происходит полная GWT компиляция.
Замечания о IDEA 14
В IDEA 14 доработали поддержку SuperDevMode – запуск SuperDevMode происходит также, как и просто DevMode, без необходимости запускать отдельно code server и servlet container и не нужно использовать закладки браузера для явного запуска компиляции – компиляция будет происходить при обновлении страницы.
Для того что бы компиляция не происходила каждый раз при перезапуске приложения, нужно в настройках запускаемой конфигурации явно указать папки workDir и war в поле Dev Mode parameters. Папка workDir – любая существующая папка, папка war – папка с web приложением, в которую будут компилироваться модули GWT. Пример:
-workDir D:\project\osbb_gradle\osbb_web\code_server_work_dir -war D:\project\osbb_gradle\osbb_web\src\main\webapp
Также нужно добавить памяти VM (VM options):
-Xmx1024m
Явно указывать папки workDir и war нужно потому что по умолчанию IDEA при каждом запуске копирует содержимое webapp папки в новую временную папку и запускает приложение уже там. Из-за чего скомпилированные в прошлый раз модули не используются и компиляция происходит заново. Но если указать явно папки, то при каждом запуске будут использоваться те же самые папки с уже скомпилированными модулями.
Что бы не компилировать модули в существующую папку приложения, можно при запуске приложения копировать её в другое место и использовать уже там, но при повторном запуске не очищать её. Т.о. существующая папка с приложением останется нетронута.
А что бы не было каждый раз обращения к volatile полю в цикле, можно его присвоить не volatile полю и обращаться.
Из того что не указал автор — возможность создание TypeHandler'ов. Простой пример — в Java есть Enum со списком значений и нужно его замапить на значения из колонки. Создаётся TypeHandler — класс, который отвечает за преобразования этого объекта из Java в СУБД и наоборот, прописывается в маппинге запроса и всё. Дальше при выполнении запроса получает типизированные объекты. Мы использовали TypeHandler'ы для структур, списка структур, Enum'ов (шаблонный TypeHandler).
Также маппинги можно прописывать в интерфейсе (не скажу что это всегда удобно, но по крайней мере есть возможность не использовать xml).
Так же для IDEA есть отличный плагин по работе с MyBatis — plugins.jetbrains.com/plugin/7293. Я пробовал разные плагины для MyBatis, но этот оказался самый лучший. Из плюсов — подсветка синтаксиса в xml, autocomlite в xml, автопроверка соответствия интерфейса xml маппингу и наоборот, связывание методов интерфейса с маппингом (можно просто перейти в реализацию метода из интерфейса в xml — как к реализации метода интерфейса в классе). Также если настроить подключение к СУБД в IDEA, работает autocomplite по SQL запросам в xml (Например, если у нас в СУБД есть таблица students то если пишем в xml маппинге SELECT * FROM st и нажимаем Ctrl+Space IDEA подскажет, что можно выбрать таблицу students)
P.S. Работали с СУБД Oracle. В основном был вызов хранимых процедур и функций. Но были и select, и update.
Ребята из VisualMicro сделали свой костыль для дебага, но там у них не тру дебаг.
Я имею ввиду, когда в CMakeLists.txt есть строчка
И в другом файле есть декларация этого метода:
То нельзя по Ctrl+click или Ctrl+B перейти на декларацию метода, пишет — «Cannot find declaration to go to».
Файлы входят в проект с точки зрения CLion, они не серые, в отличие от некоторых других файлов (т.е. есть с чем сравнить).
Если этого примера не достаточно, то можно скачать проект github.com/TimReset/arduino-cmake и посмотреть самим.