Обновить
31
Антон Куранов@Throwable

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

13
Подписчики
Отправить сообщение

Ну, тут целой статьи мало будет, если рассматривать все косяки языка и его интергации с браузером. Для меня основным недостатком является динамическая типизация. При нескольких кодерах и растущем функционале код постепенно превращается в натуральное дерьмо, отрефакторить которое будет очень нетривиальной задачей. Как правило количество тупых тестов в JS-проектах зашкаливает, которые тестируют не функционал, а тупо правописание. Для меня основное преимущество статический типизации не в раннем обнаружении ошибок при компиляции, а в поддержке IDE:


  • индикация описок, и ошибочных идентификаторов
  • подстрочник: подсказки при вызове методов
  • элементарный рефакторинг
  • простая навигация по коду (своему и библиотечному), позволяющая отследить всю цепочку вызовов
  • контрактный стиль программирования
  • различные тулзы для статического анализа кода
  • умные хинты и варнинги от IDE
  • кодогенерация и умные темплейты
Да, многие из нас работают в банках, и там всё на GWT. Но, оглядываясь назад на этот долгий-долгий путь, давайте честно признаем: управлять JavaScript из Java — наиболее дурацкая и деструктивная идея, которая когда-либо приходила в голову.

В GWT Java не управляет Javascript-ом. Java управляет DOM-ом, точно также как это делает Kotlin.js, Scala.js, TypeScript, Dart и вообще любой кросс-компилятор в JavaScript. Более того, это то, что должно было мейнстримом по причине ущербности JavaScript-а, но внезапно успело подрасти поколение JS-рунов, которым ущербность языка и динамическая типизация стало норм.
Для сложных клиентских приложений использование GWT очень даже оправдано.
GWT-проект очень нетривиально подготовить для воркбенча (вкратце пускайте вручную com.google.gwt.dev.DevMode.main(args)), но работает сносно и инкрементально компилится достаточно быстро.

Не совсем понимаю чем вторая запись лучше и понятней первой. Если str объявлен как @Nullable, то при возможном NPE тулинг выдаст варнинг — и этого в большинстве случаев достаточно. Кроме того, тулинг достаточно умный, чтобы выводить @Nullable по коду.


Кроме того, в данном случае, как я и говорил, имеет смысл вообще использовать @Nonnull String str = "" вместо null или Optional. И никаких проверок делать не надо.


NPE исключен

Да ладно?


Optional<String> calculate() {
    return null;
}
Optional<String> str = calculate();
...

Если у нас есть сложная операция или композиция, валидным результатом которой может быть "отсутствие результата", то Optional может подходить. Пример: Optional findPerson(query). Использовать же Optional для хранения или передачи состояния — плохая практика. То есть поля объекта Optional или Optional-параметр в сеттере — это сразу плохо (даже Idea вам об этом скажет). Поэтому единственный юзкейс — возврат значения, которого может не быть. Однако Optional в Java — достаточно лимитированная монада. По-сути единственное, что можно с ней сделать — это orElseXXX() (а много логики в map не запихнешь), никакой дальнейшей композиции с ней сделать нельзя (в Java 9 ей добавили свойства стрима и теперь можно делать flatMap()). Кроме того, в большинстве случаев логика требует нечто большее, чем orElse, поэтому все-равно приходится ставить if (maybe.isPresent()). Так что на мой взгляд, не фиг функционально выпендриваться на нефункциональном языке — в Java есть аннотация @Nullable.
Насчет коллекций — формально да, но реально сложно найти пример, где бы необходимо было именно Nullable-коллекция. Пустая коллекция — это и есть отсутствие результата. Какой смысл при этом будет иметь возврат null (или Optional) не совсем ясно.

Пустые объекты не являются подходящим инструментом для этой работы. Если ситуация исключительная, вы должны выбрасывать исключение

Между прочим это один из кейсов негативного влияния checked exceptions. Если бы RemoteInvocationException не был бы задекларирован как checked, программист бы скорей всего не допустил ошибки. Вообще по эксепшнам можно отдельно статью писать. Смысл простой по возможности избегайте checked-exceptions. Всегда врапьте checked-exceptions по возможности в один из стандатрных форм RuntimeException: IllegalArgumentException, IllegalStateException, etc...


Пользуйтесь наиболее специфическими типами данных

Более того, в некоторых случаях имеет смысл использовать класс-враппер над типом, вместо самого типа. Например, вместо String phoneNumber лучше сделать враппер-класс PhoneNumber с единственным полем String value. Для перечислимых типов по возможности используйте enums.


Используйте Optional вместо Null

Сомнительная рекомендация. Optional к Java прикрутили сбоку совсем недавно с приходом элементов функционального программирования, и его использование не должно выходить за рамки функционального "однострочника". Кроме того большинство библиотек и спецификация Java Beans не предусматривает использование Optional вообще. Для null-checking уже давно имеются @Nullable аннотации, которые являются лучшей альтернативой, нежели Optional. Благо тулинг их понимает из коробки. Если же хотите писать в труЪ функциональном стиле с монадами Try и Option, используйте замечательную библиотеку http://www.vavr.io/


Добавлю от себя еще некоторые правила:


  • По возможности используйте immutable-объекты. Их состояние детерминировано в любой момент.
  • Насчет пустых объектов: они всегда являются лучшей альтернативой, нежели nullable. Особенно важно для коллекций: возвращайте Collections.emptyList() вместо null. Для String использование по дефолту пустой строки "" вместо null избавить от кучи ненужных проверок.
  • Для collection-полей неплохой практикой будет возвращать в геттере Stream вместо Collection.
BPM-движок — это в первую очередь не просто конечный автомат, а все-таки движок, который может «проигрывать» схему, нарисованную бизнес-аналитиком в BPMN. И это действительно полезно, когда использовать BPM правильно, а не как «волшебную таблетку» для своего бизнеса.

Этот движок занимает 70кб джарник, их полно в инете. Плюс средства разработки — BPMN-редактор, где человек с ограниченными интеллектуальными возможностями, гордо называющий себя бизнес-аналитиком, сможет почувствовать себя разработчиком, расставляя на диаграмме ящики и стрелки при помощи мышки, концептуально называя все это бизнес-процессом. А дальше требуется нехилая бригада чертей, которые заставят все это хоть как-то шевелиться — заполнить каждый ящик реальной логикой, используя предоставляемую провайдером "платформу", которая по-сути есть фоллбэк в какой-нибудь фреймворк (Spring, JEE, JBI, SCA, etc) или язык программирования, но только с сильно ограниченными возможностями.


За работу чертей никто никогда не волнуется, поэтому их средства разработки — как правило неудобоваримое глючное говно. Все визуальные "ништяки", демонстрируемые на поверпоинтах в реале оказываются либо ненужными, либо неудобными, либо вообще противоречащие основным концептам программирования. Отдельным вопросом стоит интеграция средств разработки аналитика и программиста и и их колаборативной разработки. Все хотели, чтобы когда аналист что-то меняет, у разработчика автоматически апдейтится проект, и он видит изменения. Реально же почти всегда есть два проекта — красивая схемка и реальный процесс.


Однажды запустив процесс, начинается свистопляска с его поддержкой и версионированием. Причем, версии могут меняться как у самого процесса, так и у внешних сервисов и структур данных. До сих пор ни одна BPM так и не решила по-нормальному этот вопрос, потому что нормального решения просто нет. Нормальное решение — это при выкатывании новой версии апдейтнуть состояния всех запущенных процессов. Но поскольку у нас не простенькая state machine, а BPMN, выполняемая пропиетарным движком, то нифига не получится.

Если бы космический корабль!
Когда клиенту нужно наладить доставку продуктов из пункта А в пункт Б, где хватило бы мотоцикла с коляской или для особо продвинутых — электромобиля на солнечных батареях, тебе продают железную дорогу, позиционируя как наилучшее и самое перспективное решение на рынке грузоперевозок. Комплект включает в себя: рельсы, шпалы, паровоз (1шт.), лицензию на использование, толстую инструкцию по монтажу, экспресс-курсы для клиента на роль путейцев, машинистов, кочегаров, вагоновожатых и станционных диспетчеров.


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


Весь монтаж и использование делается исключительно силами свежеобученных "специалистов" клиента под зорким присмотром провайдера, который следит за соблюдением концептуальности монтажа (best practices) и правильным использованием "средств разработки" — лопаты, лома и кувалды. Обязательная "поддержка" паровоза производится провайдером за периодическую плату, которая состоит в оперативном объяснении клиенту, в чем была его вина в случае взрыва котла или схода поезда с рельс: неправильная эксплуатация локомотива или некачественный монтаж путей.
Любые претензии к провайдеру не принимаются во внимание. Низкая скорость доставки или паровоз не едет в горку — покупайте второй паровоз и используйте в сцепке! Поэтому большинство клиентов на особо сложных участках колеи использует своих лошадей для "подтаскивания" локомотива (а иногда и поездную бригаду), т.к. на второй паровоз денег запланировано не было. Доходит даже до случая, когда поезд с локомотивом на всем участке приводится в движение исключительно лошадьми, но это уже крайность.


Требуется чуток изменить маршрут — нет проблем. Только стоит спроектировать, пригласить инженеров, геодезистов, проектировщиков, подготовить местность, дождаться свободного окна, вызвать путейцев, поставить стрелочные переводы и проложить новый путь. В компании с правильной методологией работы со всем этим не должно быть никаких проблем.


Звучит шизофренично, но это краткое иносказательное описание моего более-чем-десятилетнего опыта работы с BPM.

Зачем BPM бизнесу? BPM — это концепция управления бизнесом через бизнес-процессы.

Просто в такой форме бизнесу наглядно и доходчиво объясняют концепцию конечного автомата и срубают за это деньги.


У нас для вас две новости: хорошая и так себе. Хорошая: BPM уже существует. Так себе: мало кто знает, что с этим делать.

Это я все периодически слышу более чем 10 лет. Уж извините за упоминания, "работал" (хотя тут больше подходит глагол, обозначающий действие сексуального характера) со стеком IBM Websphere, с Oracle SOA Suite, немного ковырял JBoss SOA platform и небольшие BPM вроде Activiti и Bonita — все клянутся, что это вазелин для вашего бизнеса и без него никак. В итоге практически нигде эти решения не работают по-нормальному по ряду причин концептуального, технического и политического характера. А возни и расходов с ними на порядок больше.


Среди использующих Pega компаний — лондонский аэропорт Хитроу, MasterCard, City Bank, Morgan Chase и многие другие.

А это вообще ни разу не показатель качества платформы. Чем мажорней компания, тем больше люди, принимающие стратегические решения, оторваны от технической области.


В банках кейс, как правило, включает в себя все действия с момента обращения клиента (например, запрос на получение кредита, опротестование операции по карте) до полного решения данного вопроса (к примеру, выдача кредита)

Это то, что продают на презентации продукта. Первый пример процесса в tutorials ко всем BPM — это Loan Broker. И как правило на этом все заканчивается.


Работая в действительно нетривиальных и сложных проектах, разработчики могут использовать и прокачивать свои навыки: Java SE, Java EE,

Согласно моему плачевному опыту, основную часть работы все-равно приходится делать именно в "этих самых навыках": Java SE, Java EE, и пр. И в определенный момент сама БПМ начинает уже мешать, а потом сильно мешать. И в итоге принимается решение переписать весь модуль на Java без участия БПМ.


На самом деле, Pega сама по себе — будущее автоматизированных систем управления (АСУ) и корпоративных информационных систем (КИС).

Это будущее уже на горизонте лет этак 15, еще когда BPM скромно называли Workflow. Но все никак не наступит. Так что определенная ниша у подобных решений будет всегда, но далеко не в каждом доме. А связывать свое будущее с программированием мышью, клепанием бесконечных формочек и меппингу данных — удовольствие на любителя.

С нулевыми зависимостями — это тоже миф. Обычно ВАР содержит еще тонны артефактов и велосипедов, не предоставляемых JEE API.
Ну и традиционный троллинг: раньше чтобы протестировать простой бинчик, нужно было сбилдить весь проект, запаковать его в ВАР/ЕАР, запустить контейнер, задеплоить артефакт, и вызвать нужный метод через какой-нибудь remote api (EJB, JAX-WS, JAX-RS), посмотреть ошибку в логах сервера, попытаться понять с каким фрагментом кода она связана, закорректировать код и повторить операцию. В JEE8 есть какие-нибудь улушения на этот счет?

Просто, делая приложение под WebSphere, вы уже будете иметь проблемы :) Не покупайтесь на обещанные "стандарты": конфигурация каждого контейнера делается отдельно, мэппинг ресурсов JNDI у всех разный, помимо стандартных дескрипторов для каждого контейнера приходится вставлять свой пропиетарный дескриптор, кроме я не умомянул пропиетарные "расширения" стандарта. Ну и как всегда, стандарты стандартами, а у каждого контейнера внезапно всплывают свои "нежданчики".


P.S. Как там с тестингом у микропрофайла? До сих пор юзается костыль Arquillian?

Не знаю насколько релевантно: есть библиотека, которая позволяет пускать агента из уже с запущенного кода без нужды указывать -javaagent:
https://github.com/electronicarts/ea-agent-loader
Запуск агента производится через определенный OpenJDK-шный JMX — весь инструментарий для рантайм инжиниринга вналичии. Я так пускаю EclipseLink JPA с динамическим weaving-ом в рантайме.

В системах, где нужны привилегии суперпользователя, обычно имеется iptables:
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to a.b.c.d:8080

Как вы думаете, в современной автомобильной промышленности при каких обстоятельствах автоконцерн вкладывается в разработку своего собственного стеклоподъемника, а не возьмет готовый, хороший и стандартный агрегат?

Тут две причины.
Во-первых, автомобильный стеклопакет делает всегда одну и ту же вещь на всех марках автомобилей. Тогда как требования в IT настолько меняются от случая к случаю, что требуют сделать открытие окна сверху вниз, сбоку, наружу или внутрь, либо сразу во всех направлениях, или продолбить в окне персональную форточку для сигареты заказчика. Тут уже смотришь, что проще: мучиться, приспосабливая стандартный стеклопакет, либо плюнуть и сделать свой под конкретный случай.


А во-вторых, сейчас мало фреймворков, которые предлагают только "стеклопакет". Обычно в комплекте идет своя электрошина, комплект акумуляторных батарей со специфическим вольтажем, блок управления с джентльменским набором кнопок, и собственный генератор. Изгововитель заявляет небывалую гибкость ввиде интеграции с любым типом ДВС. Вот и думай — когда тебе нужен только стеклопакет, стоит ли тащить еще все это добро в свое решение?

Я думал, Вы забросили этот проект. Ан-нет, уже даже достаточно юзабельная версия! На выходных попробую. Из пожеланий: добавить автоматический генератор врапперов к JS-библиотекам из TypeScript на DefinetlyTyped.

Клиент-сайд состоит из двух частей: фреймворка и библиотеки виджетов. В качестве фреймворка довольно давно использую GWT + GQuery + RestyGWT. Доволен. Из печалек: медленная компиляция и неудобный дебаг в superdevmode. В качестве библиотеки виджетов можно использовать GWTBootstrap, GWT-Material, gwt-polymer-elements, любую CSS-based библиотеку, или даже интегрировать практически любой bullshit.js.


Про упомянутый Vaadin: да, подтормаживает (постоянная синхронизация состояния виджетов с сервером), спорно годится для интернет-проектов, но для энтерпрайзных админок и дэшбоардов — самое то. При помощи GWT можно использовать весь widgetset Vaadin-a на клиентской стороне без использования серверной части, что значительно разгоняет UI. Кроме того, есть полностью js-ный Vaadin Elements. Из печалек: из пресловутый Vaading Grid тормозит гораздо больше на клиенте, чем на сервере.


P.S. Хочу попробовать подергать Kotlin.js. Кстати, если уж о котлине заговорили, то вот фреймворк со схожим функционалом: https://github.com/Kotlin/ktor

Напрашивающийся первый вопрос: почему в компании сделали неочевидный выбор в пользу Scala

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


С одной стороны фильтр вхождения в язык достаточно высок и сразу отсеивает большую часть любителей и непрофессионалов. То есть программист на скале — это "мозги" с уже достаточно высоким профессиональным уровнем, большим багажом знаний и способностью к самостоятельному обучению. С другой стороны действуют факторы, позволяющие осуществлять жесткий контроль и экономию средств на работниках, потому как:
1) рынок трудоустройства на скале черезвычайно ограничен (куда вы еще денетесь с подводной лодки?)
2) большинство людей со знанием скалы приходит без требуемого опыта (а где еще им его накопить?), что используется как аргумент при приеме на работу
3) акцент в основном делается на молодых людей, которым еще предстоит "набраться опыта", для которых работа в компании позиционируется как "неплохой шанс" с заявкой на светлое будущее.
Плюс одновременно можно не беспокоиться об утечке кадров, решений и экспириенса из компании. Получается тройной профит!


А то, что там что-то про "удобней для решаемых задач" — это даже не серьезно обсуждать. Во-первых, это мало кого волнует, кроме самих разрабов (которые никогда ничего не решают), во-вторых удобство — это всегда очень субъективно и спорно, в-третьих процессинг — это достаточно простая область, чтобы была реальная необходимость использовать абстрактные семантические конструкции, которые предоставляет Скала.

Масса причин, начиная от распределения темной материи в солнечной системе и заканчивая анизотропностью самого пространства. Фантазия безгранична!

Потому что основа функционального программирования — это stateless-операции над аргументами функции. Когда мы добавляем внешний изменяемый state в качестве, например, базы данных, то теряется идемпотентность функций, и результат композиции становится непредсказуемым. Чтобы жестко зафиксировать последовательный порядок применений функций, требуется использовать специальную монаду IO, с которой программирование фактически становится императивным. Кроме того, результат вычисления функции — это уже не просто Response, а еще и измененный State. То есть красивая идеальная схема HttpResponse = WebApplication(HttpRequest) уже не работает, и проблема здесь будет не в getCustomerFromDatabase(), а в updateCustomerInDatabase().
Поэтому для data-driven приложений функциональное программирование не лучший выбор.

Checked исключения — это вариант возвращаемого значения с приятным бонусом в виде неявного завершения блока кода, вместо проверок возвращаемого методом кода (результата) — ловишь исключение.

И кто вам мешает делать то же самое с unckecked? Разница лишь в том, что вас не обязуют это делать непосредственно в вызывающем методе. Если хотите, unchecked эксепшны — это вариант возвращаемого значения с неявным завершением блока, добавляемый для всех методов по умолчанию. Но основное назначение эксепшнов — это именно раннее завершение блока, а вот как раз бонус — это возвращаемое значение. Кроме того, когда требуется именно возврат определенного осмысленного значения, лучше использовать монады типа Optional или Try — для эксепшнов осмысленное значение редко выходит за рамки типа эксепшна и сообщения со стектрейсом.


А насчет заворачивания исключений многократно могу лишь сказать так: руки кривые и излишнее проектирование.

То есть архитектурный леер должен выставлять наружу делати реализации? :) Для самостоятельного осмысления требуется расставить эксепшны в throws:


interface ConfigReader {
  Properties readConfig() throws ???;
}
class SQLConfigReader implements ConfigReader {
  Properties readConfig() throws SQLException;
}
class FileConfigReader implements ConfigReader {
  Properties readConfig() throws IOException;
}
class URLConfigReader implements ConfigReader {
  Properties readConfig() throws MalFormedURLException, IOException;
}

Не каждый уровень бизнес-логики вообще требует какой-либо работы с исключениями.

Справедливо. Однако Java Api просто пронизан checked-исключениями. То есть либо перехватывайте и обрабатывайте, либо перехватывайте и врапьте, либо извольте отписаться в throws. И если уж затронули тему Java Api, то почему MalformedURLException и ParseException checked, а NumberFormatException unchecked, хотя все они возникают при парсинге текста.


Вот чего не хватает в Java, так это возможности сказать, что любые исключения в этом методе считать unchecked — как раз избавится от ручного управления списком throws.

И это будет последним костылем перед тем, как полностью перейти к unchecked.


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

class MyService {
  void init(ConfigReader configReader) {
    // configReader -- это интерфейс.
    // В какой конкретный класс смотреть компилятору,
    // чтобы определить, какие исключения тут могут быть выкинуты?
    configReader.readConfig();
  }
}

Throws приходится пробрасывать через весь стек методов. При движении снизу вверх количество эксепшнов в throws будет только расти. Ну и как правило верхним уровням абсолютно пофиг что за ошибка там возникла — у него как правило стоит один универсальный обработчик на все типы эксепшнов.


Есть расхожий паттерн о том, что эксепшны низких уровней нужно заворачивать в собственные более внятные: например при чтении конфигурации SQLException или IOException завернуть в свой ConfigurationException. Это плохо, потому как затрудняет абстракциям верхнего уровня получить внятный доступ к причине (в каком из цепочки getCause() он лежит?). В случае же, когда этого не требуется и абстракции верхнего уровня абсолютно пофиг на тип эксепшна, нет никакого смысла в заворачивании.


Checked должны быть эксепшны, связанные с бизнес-логикой: валидацией данных, некорректным состоянием, etc. Эксепшны, связанные с ресурсами должны быть только unchecked, и это ошибка дизайна Java API.

Информация

В рейтинге
Не участвует
Откуда
Madrid, Испания
Зарегистрирован
Активность