Обновить
41

Пользователь

0,1
Рейтинг
18
Подписчики
Отправить сообщение
Добрый день!

Спасибо за отличную статью — было интересно прочитать про внутреннее устройство DICOM. Сам я с DICOM сталкивался несколько раз — у меня друг работал в фирме, которая делала подобную программу для рендеринга, и несколько раз делал КТ (там тоже был софт для просмотра DICOM). Тогда интересно было почитать про сам формат, но хорошей статьи, которая бы всё объяснила подробным языком, не нашёл.

Собственно, вопросы:
1) А ваша фирма только в Воронеже работает? Есть представительства в других городах?
2) Какой бесплатный DICOM viewer Вы можете посоветовать? Для домашнего использования. А то вот делают снимки и хочется их на компе сохранить, чтобы в случае чего можно посмотреть. Те программы, которые идут с диском заточены под определённую структуру папок, а хочется просто универсальный софт, который открывает DICOM файлы.
3) И какие программы для медицины вы ещё делаете? Я вообще работал в фирме по производству медицинского ПО, но это было ПО для ведения записей и учёта. А вот интересно, из первых рук, какое ещё чисто медицинское ПО создаётся. :)
Для начала — Спасибо за отличные статьи, как по FindBugs так и по Java! :)
Вопрос хоть и гуглится, но хотелось от Вас ответ услышать: А как Вы FindBugs в своих проектах применяете? Какой use case? Перед коммитом всё смотрите или при сборке на build сервере? Как решается проблема старых проектов — когда есть уже большой объём кода и если вводить анализатор кода, то он будет показывать кучу ошибок и будет трудно во всём этом разобраться при дальнейшей разработке проекта? В PVS Studio (анализатор для C++) есть возможность выводить только новые баги. (насколько я понял, сам то я им не пользуюсь).
Сам я когда то давно пробовал пользоваться статическими анализаторами кода, но как-то не пошло — тогда для меня было слишком накладно каждый раз запускать проверку по всему проекту. Сейчас пользуюсь IDEA и все её предупреждения по коду исправляю, благо она это говорит в run time при написании кода. А в FindBugs такое возможно?
Интересный вопрос — вообще наличие метода говорит о том, что можно добавлять. Но если прочитать JavaDoc метода (java.util.Collection#add(E e)) и там ясно написано, что поведение метода зависит от реализации:
Throws:
UnsupportedOperationException — if the add operation is not supported by this collection

Т.к. с одной стороны метод конечно есть, но в JavaDoc чётко написано — что он может не работать. Так что нужно читать JavaDoc.
Это есть в контракте Collection.
А можно ссылочку на этот контракт? А то вообще странно — в самой java.util.Collections есть метод — emptyList(). И наверное не зря же его придумали. Да и используется (сейчас посмотрел в IDEA в нашем проекте) в 14 случаях в JDK и в 170 случаях во внешних либах (Guava, Mockito, Apache Common) и singletoneList используется в 10 случаях в JDK и в 70 в библиотеках. Так что вполне рабочий метод — использовать unmodifiable коллекции. Хотя да, если часто изменять возвращаемые из методов коллекции, то может быть сюрприз, когда это сделать не удастся. Но это уже пользователи методов виноваты :)
По моему, первая ошибка новичка в Java — не читать книги по Java :) Т.к. в них большая часть ошибок разобрана.
Да и судя по опыту, это не только ошибка новичка, но и более опытных Java программистов. :(
Оффтоп: В Java переносят хорошие практики из Guava — в Java 7 Objects появился, в Java 8, по моему, дополнили классы по работе с коллекциями. В общем, не может не радовать :)
Много плюсов за статью, но ни одного комментария о самом инструменте формального анализа! Ведь это отличная вещь с великолепными потенциалом — один раз описываем контракт для метода и не беспокоимся о его содержимом — всё и так будет проверяться :)
А вообще кто-нибудь пользовался подобными вещами? Я так понял, это подобие контрактного программирования. Только более мощное. В 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.
А какое конкретно приложение App ops Вы использовали? А то в Google Play по запросу App ops штук десять приложений находит с этим названием.
Да, поведение разное. Ну это аргументированно тем, что если ошибка произошла (в Java это называется исключением) то и не нужно дальше продолжать работать — типа, это не нормальное поведение, поэтому дальше код выполнять не нужно. А в Go какая философия по этому поводу? Если метод выполнился с ошибкой, то дальше можно работать? Это я почему спрашиваю — часто в try/catch происходит работа с методами, которые могу вернуть ошибки и если каждый раз проверять возвращаемое значение, то будет долго. Например операции ввода/вывода — они практически все могут вернуть ошибку.
Интересно, а как в Go будет написан код, когда подряд идут несколько операций, которые могу вернуть ошибку?
Например:
file1, err := os.Open("test1.txt")
file2, err := os.Open("test2.txt")


Нужно каждый раз проверять что err не null?
С try/catch будет всего один catch блок.
Понятно. А Вы в support IDEA писали? А то странно — в IDEA есть поддержка Vaadin, но при этом с ним не работает GWT плагин.
На счёт своей сборки GWT не понял. А что будет, если в IDEA указать GWT SDK из Vaadin?
Был на прошлой 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 папки в новую временную папку и запускает приложение уже там. Из-за чего скомпилированные в прошлый раз модули не используются и компиляция происходит заново. Но если указать явно папки, то при каждом запуске будут использоваться те же самые папки с уже скомпилированными модулями.

Что бы не компилировать модули в существующую папку приложения, можно при запуске приложения копировать её в другое место и использовать уже там, но при повторном запуске не очищать её. Т.о. существующая папка с приложением останется нетронута.
Интересный способ, должен работать из-за read barrier для volatile. Но судя по stackoverflow.com/questions/10620680/why-volatile-in-java-5-doesnt-synchronize-cached-copies-of-variables-with-main не всегда работает корректно :)
А что бы не было каждый раз обращения к volatile полю в цикле, можно его присвоить не volatile полю и обращаться.

Информация

В рейтинге
2 967-й
Дата рождения
Зарегистрирован
Активность