Вместо того, чтобы помещать BPM движок в центр нашего бизнес-процесса, мы используем его как вспомогательный фреймворк
Любой менеджер, продающий коммерческую BPM, с пеной у рта будет вам доказывать, что BPM обязательно должна ядром вашего бизнеса и IT-архитектуры, и все сервисы и процессы должны строиться вокруг нее. Иначе это пустая трата денег (что собственно верно). Ну а во-вторых, согласно моей практике, в большинство решений, где требуется "только мотор", в итоге очень неплохо обходятся без него. Как я уже сказал, много людей тащат в проект BPM, только потому что им внезапно понадобились асихнронные вызовы с персистенцией.
Основное преимущество в том, что BPMN – это исполняемая документация.
Вот в это я ни за что не поверю. Есть два мира: в одном аналитик рисует красивый оптимистичный BPMN согласно тому, как он видит бизнес задачу, а в другом девелоперы строчат по картинке страшный реальный процесс, учитывая стопицот нюансов и поведений, которые не учел аналитик, и который в итоге и будет работать. Как ни пытались производители BPMS помирить эти два мира и сделать единый репозиторий — не получилось. В итоге уже после первой итерации аналитик говорит: "вот я вам донес идею, а вы там себе скопируйте мою схему и добавьте как вам надо".
После прочтения этой статьи у вас может сложиться впечатление, будто мы отказались от всех преимуществ BPMS и переложили ответственность на самописный код. Но это не так.
Именно так. Более 10 лет разрабатывал под BPM, а ситуация все та же. Сначала вам задвигают Дорогое Красивое Решение, которое предендует на роль швейцарского ножа на все случаи жизни. Уже в процессе внезапно оказывается, что лезвия нихрена не режут, тупые, маленькие, пользоваться им не удобно или по большей части существуют как декорация. В итоге весь цикл разработки — это горожение велосипедов в борьбе с ограничениями платформы, и постепенная миграция критического функционала из BPM на самописку вплоть до полного отказа от этой самой BPM.
Центр любой BPMS – это BPM-движок, и мы используем его по полной. Это удивительный инструмент, который действительно помогает ускорить разработку и повысить качество поставляемых решений.
Ваш движок — это джарник на 100кб, коих на гитхабе полно, и сам по себе не несет абсолютно никакой ценности. Для того, чтобы его можно было использовать, нужна платформа для интеграции типа Spring и какой-нибудь persistence layer. Коммерческие решения поверх этого обвешиваются различного рода порталами и бизнес тулзами на все случаи жизни, однако как всегда жутко неудобоваримыми и ограниченными. У меня есть твердое убеждение, что весь этот обвесок служит по большей части для маркетинга, нежели для реального использования.
Ну и еще, такое наблюдение: 95% пользователей тащат в проект BPM потому что не знают как осуществить персистенцию долгоиграющего процесса или сделать асинхронный вызов. А большинство т.н. "процессов" — это линейные вызовы в лучшем случае с парой ветвлений.
Часто можно услышать совет «пишие комменте ПОЧЕМУ, а не ЧТО». Хотя это, вероятно, охватывает большинство моих комментариев, это не то, как я думаю о том, когда комментировать. Вместо этого я обычно пишу комментарий, когда есть что-то особенно сложное, либо в домене, либо в том, как выполняется реализация.
С философской точки зрения каждая строчка кода содержит техдолг по дальнейшей поддержке. Ценность представляет только конечный функционал. И если можно его реализовать вообще без единой строчки, то все идеально. В противном случае у вас всегда должен быть мотив "ПОЧЕМУ"/"ДЛЯ ЧЕГО" вы ее добавили. Теоретически этот мотив и следует указывать в комментарии. Вопрос "ЧТО" как правило решается осмысленными идентификаторами классов, методов и переменных. Вопрос "КАК" должен быть понятен из самого кода (тоже теоретически).
Одна из веских причин для написания множества небольших методов вместо одного большого заключается в том, что у вас есть больше мест для использования описательных имен, о чем я описал здесь.
Если реализация метода сложная, и нет возможности разбить ее на отдельные функции, я использую "лесенку" при помощи блочных операторов: все детали вычислений загоняю под блок, наверху оставляя только переменные-результаты вычислений.
Есть еще такой момент: зачастую коментарии требуются не конкретному куску кода, а всему реализуемому функционалу. Для этого неплохо подходит файл package-info.java. Однако очень редко вижу, чтобы кто-то его использовал, за исключением самой JDK. А вот адепты TDD сказали бы, что в этом случае коментариями должны быть тесты.
Javadoc — самый бесполезный
Он не бесполезен, а неудобен. Неудобны теги, форматирование (звездочки вначале), html. Более адекватным для этих целей был бы Markdown.
Рассмотрим ситуацию. Есть два кандидата:
20 лет опыта. java 6,7,8; j2ee; jdbc and so on.
Java 1.1-17, Kotlin/Scala/Clojure, Spring/Guice/Micronaut/любой другой DI, J2EE (CDI, JPA, JMS, SOAP, JTA), ApacheMQ/RabbitMQ/WebsphereMQ, паттерны проектирования, архитектура приложений. Прокачанные скиллы и интуиция. Человек, понимающий как внутри устроены инструменты, которыми он пользуется, и способный при необходимости написать с нуля любой из них.
5 лет опыта. java 11; spring jpa; kubernetes; kafka
Толком не знает как работает ни одно из этих "чудес", а тупо копипейстит из туториалов и SO, строгая шаблонные микросервисы. При вопросе про ACID, transaction isolation levels, delivery semantics той же kafka, и даже же про основу — Spring-овский DI, впадает в ступор. В итоге без надлежащего контроля уже с конвеера выходит абсолютный хлам. Модный, но хлам.
Некоторые решения давно устарели.
Не устарели, а вышли из моды. Потому как моду диктуют джуны и мидлы, где основной критерий — чтобы решение соответствовало их уровню понимания темы. Но уровень понимания любого айтишника растет вместе с эволюцией этого самого решения. И когда они вроде бы оба достигли состояния дзена, решение внезапно выходит из моды, и вытесняется очередным примитивным велосипедом, понятным вновь прибывшим в эту отрасль народного хозяйства.
У всех программистов есть свои идеи и своё видение(
У детей тоже есть свое видение мира. Красочное, интересное, но наивное. Но оно никак не поможет построить ракету.
Склад ума === навязывание образа мыслей.
Так кажется неопытным айтишникам, которые не доросли до уровня, при котором аргументы техлида для них становятся понятны. Кроме того есть такая вещь как интуиция — "мне не нравится это решение, и я предвижу кучу скрытых проблем, которые последуют за ним, перечислять и анализировать которые у меня нет желания и времени".
Человек, готовый принять на себя удар в случае неверного решения. Щит команды. С какой целью?
Хотя бы с целью, чтобы тебя в субботу полупьяного из клуба не достал звонок разгневанного клиента, невнятно орущего, что у него все лежит, и он теряет кучу денег ежеминутно (реальный случай). Человека, способного оперативно разобраться с проблемой и предпринять необходимые действия. А также недопустить, чтобы откровенная халтура проникла на прод. Иначе каждый из команды будет объяснять клиенту как "у вас на компьютере все работало" и "все тесты были зелеными".
Начните набирать/обучать активных джунов/мидлов.
И кто, простите, будет их обучать? Онлайн академия с недельными курсами? Или собственными силами, собирая все грабли в одном проекте?
Это точно мне коментарий? У меня ноутбук 14" с Windows и подключен к внешнему монитору 21". Разрешение у мониторов однинаковые (Full HD), однако, как несложно догадаться, разный DPI. Поэтому в настройках скейлинга для экрана ноута ставим 150%, а для внешнего 125%. В итоге буквы и все элементы приложений одинаковый размер на обоих мониторах. При перетаскивании окна с одного монитора на другой меняется метрика приложения, и оно адаптируется под новый scale. Решено на Windows, Маках, Linux/Wayland, и возможно еще куче девайсов.
Мой коментарий заключается в том, что у девайсов должна быть еще одна метрика — угловой размер, на основании которого графическая подсистема сама выбирает параметры скейлинга. В итоге один и тот же шрифт (и все визуальные элементы) имеет одинаковый визуальный размер и на мобильнике, и на ноуте, и на мониторе, и на плазме 52", стоящей в двух метрах, и на экране проектора в зале заседаний.
Дык были же. Вспомним Java Applets, помянем Flash, Silverlight... Поскольку это были проприетарные решения, компании типа Google и Apple не были заинтересованы поддерживать их на своих платформах. Вместо этого решили использовать веб технологии в качестве тонкого клиента. Хотя сам Html изначально не задумывался для создания интерактивных интерфейсов, а именно для статичных страниц.
код который может вызвать запрос на гигабайт через пол-планеты — выглядят одинаково (как в каком-нить олдовом RPC).
А он и должен выглядеть одинаково, поскольку для логики кода здесь нет абсолютно никакой разницы — от suspendable быстрее он не выполнится, и точно также будет ждать, пока завершится асинхронный вызов прежде, чем перейти к другому шагу.
А со временем все больше и больше API будут становиться полностью асинхронными (потому как тренд это нынче, не пишут сейчас чисто блокирующих API)
Мне бы ваш оптимизм, но увы. Еще даже нормального асинхронного JDBC стандарта на этот счет нет (и по ходу не будет). Весь низкоуровневый I/O-слой — это блокирующие API.
Действительно надо понимать где код suspendable а где нет.
Вообще-то нет — это совершенно лишнее знание (да простит меня Роман Елизаров), требуемое конкретной реализацией асинхронности. Асинхронность появилась для того, чтобы обойти ограничение posix thread на масштабируемость путем избегания блокировок. Корутины — это лишь хак компилятора, где suspendable подменяет собой asyncrhonous callback. А любой хак, всегда несет с собой кучу побочки и проблемы интеграцией с уже существующей базой. Навскидку, вам под suspendable придется переписать весь стек до самого низкого уровная I/O и JDBC, многие фреймворки используют текущий контекст ThreadLocal в аспектах (напр. @Transactional), кторый не будет работать с suspendable (но и не выдаст ошибки), сложность дебага и стектрейса, etc. С другой стороны упомянутый мной Loom совершенно прозрачно реализует масштабируесомть для блокируемого кода, не требуя абсолютно никаких модификаций. Поэтому для JVM тут спорный выигрыш.
Тем не менее корутины как механизм хорош на других платформах, где нет suspendable threads, либо нет блокировок (native, JS, Android).
Собственно, ИМХО, сила типизации — это спектр, который как раз и определяется, присутствие насколько сложных желательных (или отсутствие нежелательных) поведений можно гарантировать системой типов языка.
Я бы обобщил — которые могут быть вычислены на этапе компиляции. А система типов — это один из способов для декларации этих поведений, однако не единственный. Теоретически суперумный компилятор может вычислить всю вашу программу и расставить типы автоматически. И многие компиляторы (и IDE) кое-где умеют так делать (вывод типов). А система типов лишь на порядки упрощает эту работу.
Более сильная система типов даёт вам возможность гарантировать больше вещей статически, но не требует этого.
Проблема в том, что как правило именно требует, благодаря чему делая простые вещи сложными в реализации. В Java вы не можете описать класс с динамическим набором полей, как в JavaScript — для этого приходится использовать Map. Еще более сложно иметь клас одновременно со статическими и динамическими полями. Котлине нет типа "contextual nullable" как в Java. Точнее он есть (Any!!), но это внутренний тип компилятора, введенный для совместимости с Java. TypeScript — да, позволяет использовать типы опционально там, где это нужно, имея fallback в JS.
Преимущество TS в том, что вам дают выбрать между строгой типизацией, нестрогой и динамической (всегда есть фоллбэк в голый JS). В Котлине (да и в Java тоже) такой опции нет — везде требуют строгие декларации, причем в котлине они более жесткие (тип dynamic не берем в рассмотрение — он был внедрен как пятое колесо специально для совместимости с JS). Сделано это с благими намерениями, чтобы обязовать пользователя писать "правильный" (по чьему-то мнению) код, однако как всегда там, где модель немного выходит за рамки, жесткие ограничения начинают жутко мешать.
И не очень понял какое отношение имеет binding к UI формам к обсуждаемому вопросу.
Как раз связано с nullable. Есть Entity, поля которой завязаны на UI-форму, и которая заполняется прогрессивно, например с веба. Вконце делается валидация полей (напр. при помощи JSR305), и все сохраняется в storage. Естественно, в Котлине все поля приходится описывать как nullable, и даже required-поля, которые никогда потом не будут null.
class User {
@NotNull
var username : String?
}
А затем уже на этапе использования везде расставлять "!!", либо пустые не-null проверки, что только увеличивает возможность ошибки. Многие скажут, что "правильный" kotlin-way здесь — это на каждую Entity создать еще один объект EntityDTO, в который делать меппинг формы, а затем уже замепить его в сам Entity. Но это сразу тупо в 4 раза увеличивает код практически без увеличения функциональной ценности.
Я реально уже не помню в деталях, раз как-то заставил работать. Общее впечатление — создаешь модель, она валится на сериализации из-за чисто котлиновских фич (конструкторы, nullability, immutable collections, delegates, vals, etc.), и приходится все перелопачивать. Для простых data objects проблем не возникает. Если интересно в деталях, загляните сюда https://github.com/FasterXML/jackson-module-kotlin/issues
Игрался я с вашей TeaVM — вы маньяк каких мало (в хорошем смысле слова). Я в свое время активно юзал GWT, сейчас для энтерпрайз тулзов использую Vaadin. Однако сейчас в большинстве случаев типичный проект — это разные команды и разные кодовые базы для каждой платформы, плюс сервер. Во всей компании все, кто знают котлин, лабают исключительно под андроид, и абсолютно не секут в веб-фронтэнде ни в бэкэнде. Бэкендеры сидян на джаве и пайтоне. И ни один веб-фронтэндер, тоже не знает котлина (и не собирается). Вот такое разделение труда.
Попробую объяснить. Лирическое отступление. Забудем сначала про null и зададимся вопросом что отличает языки со слабой типизацией от языков с сильной типизацией. В первых вывод типа происходит исключительно в рантайме. Во вторых же позволяют декларировать какой-то статичный контракт, подчиняющийся определенным правилам вывода, который может быть вычислим на этапе компиляции. Однако это не совсем не отменяет того, что в программе большинство типов остается вычислимо лишь в рантайме. Попытки внедрить и использовать более сильную систему типов (напр. ScalaZ), позволяющую иметь бОльший контроль на этапе компиляции, сталкиваются с проблемой, что описание типов для предметной области становится в разы сложнее, чем сама программа, и тем не менее все-равно будут появляться места, где тип вычислим лишь в рантайме. Поэтому важно сохранять некий баланс между контролем типов и простотой описания.
Теперь вернемся к нашим баранам. Java по дефолту не имеет способа объявить контракт по nullability, однако его все же можно по желанию дополнить аннотациями Nullable/@Nonnull, либо использованием Optional. Котлин же наоборот обязует для любого типа всегда использовать строгий контракт по поводу nullability без возможности послабления. Почему это плохо? Приведу пару демонстративных кейсов.
Функция, которая конвертирует объект в строку, причем для null-ов она должна возвращать null.
fun toString(a : Any?) : String? {
return a?.toString();
}
Проблема в том, что она всегда обязана возвращать nullable String и обязует каждый раз делать проверку, даже когда поставляемый объект заведомо не null и описан в ситеме типов как не-null. Котлин не позволяет описать контракт "верни мне String? для Any? и String для Any", перегрузить функцию не получится — возникнет конфликт сигнатур.
Очень ленивая инициализация. Для nonnull полей Kotlin требовал сразу указать дефолтное значение. Логично. Но практически сразу же разработчики столкнулись с диким баттхертом при интеграции с различными библиотеками (DI, JUnit, сериализация, etc...), где значение поля вычислялось и заполнялось отложенно. Пришлось включить попятную и добавить хак ввиде lateinit, дабы как-то это сделать юзабельным. Пример: есть JPA Entity с полем id, которое заполняется автоматически при персистенции объекта. Nullable я его не хочу делать, т.к. null там только на этапе конструирования.
@Entity
class MyEntity {
@Id @GeneratedValue
lateinit var id : Long
fun isPersisted() : Boolean {
return this::test.isInitialized
}
}
И вот облом! Это не сработает, потому как при сохранении объекта JPA провайдер попытается прочитать из поля и получит kotlin.UninitializedPropertyAccessException.
Это все примеры того, что nullability, как и множество других свойств зачастую контекстно-зависимые и не могут быть объявлены статичным контрактом.
Ну и предполагается что хорошо организовав типы в проекте, да и саму кодовую базу, вам не придётся регулярно упорно доказывать компилятору, что "да зуб даю, тут не null". Наш опыт показывает, что в ~10-15% случаев, когда программист думает "тут никогда не бывает null", он ошибается :)
Да ладно? Вы никогда со структурами не работали? Не байндили формочки к UI?
NPE самая частовстречаемая, но легко детектируемая и отлаживаемая ошибка. А статичными контрактами далеко не всегда удается вывести nullability. Вместо, чтобы вставлять nullability в контракт, просто поставьте Objects.requireNonNull() или лишний assert там, где это нужно и дело в шляпе.
Как всегда, все приведенные аргументы мелкие и несерьезные: у нас есть фича A, а у вас ее нет, либо она хуже и вообще плохая. Я тоже писал проекты на Kotlin, но до сих пор предпочитаю Java, и вот почему:
Синтаксис. Котлин сложнее и оперирует бОльшим количеством конструкций. Язык и API зачастую создают впечатление перегруженностью сахаром. Да, это позволяет писать более "лаконичный" код (за что и ставят плюс), однако совершенно противоположно действует на читабельность оного. Многабукав в Java совсем не значит, что это труднее читать.
Полиморфность кода. Для большинства задач в Java уже предусмортен джентльменский набор стандартных решений и паттернов проектирования. В Котлине, благодаря его "широким возможностям", количество способов для одной и той же задачи увеличивается сразу в десятки раз. И выбор "правильного" метода лежит на сугубо на индивидуальных эстетических критериях каждого программиста. Кроме того обилие implicit-ов (extension methods, пакетные функции) делает конкретный фрагмент абсолютно нечитаемым без контекста. В итоге в проекте отсутствует всякая унификация кода, если у вас больше 1 девелопера, что называется "кто в лес, кто по дрова". Это ухуджает в разы поддерживаемость проекта.
Экосистема. Чисто котлиновская сейчас очень мелкая, поэтому так или иначе приходится использовать джаву и интегрироваться с ней. Несмотря на то, что много кто сегодня поддерживает Котлин, всегда при интеграции возникают швы и костыли ввиде kotlin.jvm.* и прочих. Не слушайте всех, кто "не испытывают в котлине проблем с java-библиотеками" — они нагло врут, а в голове постоянно держат "в какой джава класс скомпилируется данный кусок кода". Ну или не пишут ничего сложнее микросервиса к базе, хотя и тут будут проблемы с Jackson binding-ом.
Киллер-фичи. Наиболее разрекламированное "чудо" зачастую оказывается бесполезным, а иногда даже вредным. Все сталкивались, что во многих случаях nullability тупо мешает, нежели помогает, портя собой код. Все потому, что nullability в большинстве случаев — это не статическое свойство, а контекстно-зависимое: программист знает, что конкретно здесь оно точно никогда не null, а вот там иногда может быть. Но описать такую конструкцию в Котлине нельзя (а вот в Java это как бы из коробки). Что там еще? Корутины? Очень интрузивное и тяжелое изменение, которое заставляет код выполняться совсем не так, как написано, разрезая сверху до самого основания ваш код на suspendable и не-suspendable. Loom гораздо более элегантен и прозрачен. Желание "улучшить" джаву приводит к проблемам совместимости и соответствующим костылям ввиде all open gradle plugin… Из позитивных фич я бы отметил коллекции (хорошо неинтрузивно переработали и сделали immutable), и properties.
Позиционирование языка. Не понятно целевое назначение. С одной стороны это "улучшенная джава", с другой он претендует на инструмент для multiplatform-разработки и суется в чуждые ему ниши. Однако в каждой из них приходится жестко конкурировать с уже устаканившимися языками: если вы пишите под JVM, для Java вам нужно знать только Java, для Kotlin вам нужно знать Kotlin и Java. Для JS-таргета приходится конкурировать с нативным Typescript, и юзать костыли для интеграции с JS-экосистемой, ну естественно, также приходится знать JS. Для native тоже котлин не в моде — там сейчас Rust. Остается Android, но и тут он теснится Flutter/Dart. Реально же проекты, где необходима мультиплатформенность с единой кодовой базой, в природе не встречаются.
У них была халтура копипейстнутая, а не калькулятор. Накидать прототип и задизайнить несколько скинов — дело одного вечера. А персонально для Джобса разыграть трогательную историю создания, в которую он поверит и проникнется. Просто никто работать не хотел — сам босс зарубил, значит выпилим, и дело в шляпе.
Любой менеджер, продающий коммерческую BPM, с пеной у рта будет вам доказывать, что BPM обязательно должна ядром вашего бизнеса и IT-архитектуры, и все сервисы и процессы должны строиться вокруг нее. Иначе это пустая трата денег (что собственно верно). Ну а во-вторых, согласно моей практике, в большинство решений, где требуется "только мотор", в итоге очень неплохо обходятся без него. Как я уже сказал, много людей тащат в проект BPM, только потому что им внезапно понадобились асихнронные вызовы с персистенцией.
Вот в это я ни за что не поверю. Есть два мира: в одном аналитик рисует красивый оптимистичный BPMN согласно тому, как он видит бизнес задачу, а в другом девелоперы строчат по картинке страшный реальный процесс, учитывая стопицот нюансов и поведений, которые не учел аналитик, и который в итоге и будет работать. Как ни пытались производители BPMS помирить эти два мира и сделать единый репозиторий — не получилось. В итоге уже после первой итерации аналитик говорит: "вот я вам донес идею, а вы там себе скопируйте мою схему и добавьте как вам надо".
Именно так. Более 10 лет разрабатывал под BPM, а ситуация все та же. Сначала вам задвигают Дорогое Красивое Решение, которое предендует на роль швейцарского ножа на все случаи жизни. Уже в процессе внезапно оказывается, что лезвия нихрена не режут, тупые, маленькие, пользоваться им не удобно или по большей части существуют как декорация. В итоге весь цикл разработки — это горожение велосипедов в борьбе с ограничениями платформы, и постепенная миграция критического функционала из BPM на самописку вплоть до полного отказа от этой самой BPM.
Ваш движок — это джарник на 100кб, коих на гитхабе полно, и сам по себе не несет абсолютно никакой ценности. Для того, чтобы его можно было использовать, нужна платформа для интеграции типа Spring и какой-нибудь persistence layer. Коммерческие решения поверх этого обвешиваются различного рода порталами и бизнес тулзами на все случаи жизни, однако как всегда жутко неудобоваримыми и ограниченными. У меня есть твердое убеждение, что весь этот обвесок служит по большей части для маркетинга, нежели для реального использования.
Ну и еще, такое наблюдение: 95% пользователей тащат в проект BPM потому что не знают как осуществить персистенцию долгоиграющего процесса или сделать асинхронный вызов. А большинство т.н. "процессов" — это линейные вызовы в лучшем случае с парой ветвлений.
С философской точки зрения каждая строчка кода содержит техдолг по дальнейшей поддержке. Ценность представляет только конечный функционал. И если можно его реализовать вообще без единой строчки, то все идеально. В противном случае у вас всегда должен быть мотив "ПОЧЕМУ"/"ДЛЯ ЧЕГО" вы ее добавили. Теоретически этот мотив и следует указывать в комментарии. Вопрос "ЧТО" как правило решается осмысленными идентификаторами классов, методов и переменных. Вопрос "КАК" должен быть понятен из самого кода (тоже теоретически).
Если реализация метода сложная, и нет возможности разбить ее на отдельные функции, я использую "лесенку" при помощи блочных операторов: все детали вычислений загоняю под блок, наверху оставляя только переменные-результаты вычислений.
Есть еще такой момент: зачастую коментарии требуются не конкретному куску кода, а всему реализуемому функционалу. Для этого неплохо подходит файл package-info.java. Однако очень редко вижу, чтобы кто-то его использовал, за исключением самой JDK. А вот адепты TDD сказали бы, что в этом случае коментариями должны быть тесты.
Он не бесполезен, а неудобен. Неудобны теги, форматирование (звездочки вначале), html. Более адекватным для этих целей был бы Markdown.
Про дедлок слышали? https://ru.wikipedia.org/wiki/%D0%92%D0%B7%D0%B0%D0%B8%D0%BC%D0%BD%D0%B0%D1%8F_%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0
Стоит модели и логике стать чуть сложнее — и вот вы уже висите в самый неподходящий момент. Если не нравятся тяжелые транзакции, посмотрите Software Transactional Memory.
Потому что в худшем случае это ворованное, а в лучшем — выловленное с punto limpio, куда народ сам несет выкидывать.
Колесо замкнется, когда кому-то в метабраузере снова понадобится метаканвас...
Java 1.1-17, Kotlin/Scala/Clojure, Spring/Guice/Micronaut/любой другой DI, J2EE (CDI, JPA, JMS, SOAP, JTA), ApacheMQ/RabbitMQ/WebsphereMQ, паттерны проектирования, архитектура приложений. Прокачанные скиллы и интуиция. Человек, понимающий как внутри устроены инструменты, которыми он пользуется, и способный при необходимости написать с нуля любой из них.
Толком не знает как работает ни одно из этих "чудес", а тупо копипейстит из туториалов и SO, строгая шаблонные микросервисы. При вопросе про ACID, transaction isolation levels, delivery semantics той же kafka, и даже же про основу — Spring-овский DI, впадает в ступор. В итоге без надлежащего контроля уже с конвеера выходит абсолютный хлам. Модный, но хлам.
Не устарели, а вышли из моды. Потому как моду диктуют джуны и мидлы, где основной критерий — чтобы решение соответствовало их уровню понимания темы. Но уровень понимания любого айтишника растет вместе с эволюцией этого самого решения. И когда они вроде бы оба достигли состояния дзена, решение внезапно выходит из моды, и вытесняется очередным примитивным велосипедом, понятным вновь прибывшим в эту отрасль народного хозяйства.
У детей тоже есть свое видение мира. Красочное, интересное, но наивное. Но оно никак не поможет построить ракету.
Так кажется неопытным айтишникам, которые не доросли до уровня, при котором аргументы техлида для них становятся понятны. Кроме того есть такая вещь как интуиция — "мне не нравится это решение, и я предвижу кучу скрытых проблем, которые последуют за ним, перечислять и анализировать которые у меня нет желания и времени".
Хотя бы с целью, чтобы тебя в субботу полупьяного из клуба не достал звонок разгневанного клиента, невнятно орущего, что у него все лежит, и он теряет кучу денег ежеминутно (реальный случай). Человека, способного оперативно разобраться с проблемой и предпринять необходимые действия. А также недопустить, чтобы откровенная халтура проникла на прод. Иначе каждый из команды будет объяснять клиенту как "у вас на компьютере все работало" и "все тесты были зелеными".
И кто, простите, будет их обучать? Онлайн академия с недельными курсами? Или собственными силами, собирая все грабли в одном проекте?
Это точно мне коментарий? У меня ноутбук 14" с Windows и подключен к внешнему монитору 21". Разрешение у мониторов однинаковые (Full HD), однако, как несложно догадаться, разный DPI. Поэтому в настройках скейлинга для экрана ноута ставим 150%, а для внешнего 125%. В итоге буквы и все элементы приложений одинаковый размер на обоих мониторах. При перетаскивании окна с одного монитора на другой меняется метрика приложения, и оно адаптируется под новый scale. Решено на Windows, Маках, Linux/Wayland, и возможно еще куче девайсов.
Мой коментарий заключается в том, что у девайсов должна быть еще одна метрика — угловой размер, на основании которого графическая подсистема сама выбирает параметры скейлинга. В итоге один и тот же шрифт (и все визуальные элементы) имеет одинаковый визуальный размер и на мобильнике, и на ноуте, и на мониторе, и на плазме 52", стоящей в двух метрах, и на экране проектора в зале заседаний.
Дык были же. Вспомним Java Applets, помянем Flash, Silverlight... Поскольку это были проприетарные решения, компании типа Google и Apple не были заинтересованы поддерживать их на своих платформах. Вместо этого решили использовать веб технологии в качестве тонкого клиента. Хотя сам Html изначально не задумывался для создания интерактивных интерфейсов, а именно для статичных страниц.
А он и должен выглядеть одинаково, поскольку для логики кода здесь нет абсолютно никакой разницы — от suspendable быстрее он не выполнится, и точно также будет ждать, пока завершится асинхронный вызов прежде, чем перейти к другому шагу.
Мне бы ваш оптимизм, но увы. Еще даже нормального асинхронного JDBC стандарта на этот счет нет (и по ходу не будет). Весь низкоуровневый I/O-слой — это блокирующие API.
Вообще-то нет — это совершенно лишнее знание (да простит меня Роман Елизаров), требуемое конкретной реализацией асинхронности. Асинхронность появилась для того, чтобы обойти ограничение posix thread на масштабируемость путем избегания блокировок. Корутины — это лишь хак компилятора, где suspendable подменяет собой asyncrhonous callback. А любой хак, всегда несет с собой кучу побочки и проблемы интеграцией с уже существующей базой. Навскидку, вам под suspendable придется переписать весь стек до самого низкого уровная I/O и JDBC, многие фреймворки используют текущий контекст ThreadLocal в аспектах (напр. @Transactional), кторый не будет работать с suspendable (но и не выдаст ошибки), сложность дебага и стектрейса, etc. С другой стороны упомянутый мной Loom совершенно прозрачно реализует масштабируесомть для блокируемого кода, не требуя абсолютно никаких модификаций. Поэтому для JVM тут спорный выигрыш.
Тем не менее корутины как механизм хорош на других платформах, где нет suspendable threads, либо нет блокировок (native, JS, Android).
Да, но например со стрингом не сработает. Есть неожиданный выход — описать Entity на Java, и все сразу заработает как надо :)
Я бы обобщил — которые могут быть вычислены на этапе компиляции. А система типов — это один из способов для декларации этих поведений, однако не единственный. Теоретически суперумный компилятор может вычислить всю вашу программу и расставить типы автоматически. И многие компиляторы (и IDE) кое-где умеют так делать (вывод типов). А система типов лишь на порядки упрощает эту работу.
Проблема в том, что как правило именно требует, благодаря чему делая простые вещи сложными в реализации. В Java вы не можете описать класс с динамическим набором полей, как в JavaScript — для этого приходится использовать Map. Еще более сложно иметь клас одновременно со статическими и динамическими полями. Котлине нет типа "contextual nullable" как в Java. Точнее он есть (Any!!), но это внутренний тип компилятора, введенный для совместимости с Java. TypeScript — да, позволяет использовать типы опционально там, где это нужно, имея fallback в JS.
Преимущество TS в том, что вам дают выбрать между строгой типизацией, нестрогой и динамической (всегда есть фоллбэк в голый JS). В Котлине (да и в Java тоже) такой опции нет — везде требуют строгие декларации, причем в котлине они более жесткие (тип dynamic не берем в рассмотрение — он был внедрен как пятое колесо специально для совместимости с JS). Сделано это с благими намерениями, чтобы обязовать пользователя писать "правильный" (по чьему-то мнению) код, однако как всегда там, где модель немного выходит за рамки, жесткие ограничения начинают жутко мешать.
Как раз связано с nullable. Есть Entity, поля которой завязаны на UI-форму, и которая заполняется прогрессивно, например с веба. Вконце делается валидация полей (напр. при помощи JSR305), и все сохраняется в storage. Естественно, в Котлине все поля приходится описывать как nullable, и даже required-поля, которые никогда потом не будут null.
А затем уже на этапе использования везде расставлять "!!", либо пустые не-null проверки, что только увеличивает возможность ошибки. Многие скажут, что "правильный" kotlin-way здесь — это на каждую Entity создать еще один объект EntityDTO, в который делать меппинг формы, а затем уже замепить его в сам Entity. Но это сразу тупо в 4 раза увеличивает код практически без увеличения функциональной ценности.
Я реально уже не помню в деталях, раз как-то заставил работать. Общее впечатление — создаешь модель, она валится на сериализации из-за чисто котлиновских фич (конструкторы, nullability, immutable collections, delegates, vals, etc.), и приходится все перелопачивать. Для простых data objects проблем не возникает. Если интересно в деталях, загляните сюда https://github.com/FasterXML/jackson-module-kotlin/issues
Игрался я с вашей TeaVM — вы маньяк каких мало (в хорошем смысле слова). Я в свое время активно юзал GWT, сейчас для энтерпрайз тулзов использую Vaadin. Однако сейчас в большинстве случаев типичный проект — это разные команды и разные кодовые базы для каждой платформы, плюс сервер. Во всей компании все, кто знают котлин, лабают исключительно под андроид, и абсолютно не секут в веб-фронтэнде ни в бэкэнде. Бэкендеры сидян на джаве и пайтоне. И ни один веб-фронтэндер, тоже не знает котлина (и не собирается). Вот такое разделение труда.
Попробую объяснить. Лирическое отступление. Забудем сначала про null и зададимся вопросом что отличает языки со слабой типизацией от языков с сильной типизацией. В первых вывод типа происходит исключительно в рантайме. Во вторых же позволяют декларировать какой-то статичный контракт, подчиняющийся определенным правилам вывода, который может быть вычислим на этапе компиляции. Однако это не совсем не отменяет того, что в программе большинство типов остается вычислимо лишь в рантайме. Попытки внедрить и использовать более сильную систему типов (напр. ScalaZ), позволяющую иметь бОльший контроль на этапе компиляции, сталкиваются с проблемой, что описание типов для предметной области становится в разы сложнее, чем сама программа, и тем не менее все-равно будут появляться места, где тип вычислим лишь в рантайме. Поэтому важно сохранять некий баланс между контролем типов и простотой описания.
Теперь вернемся к нашим баранам. Java по дефолту не имеет способа объявить контракт по nullability, однако его все же можно по желанию дополнить аннотациями Nullable/@Nonnull, либо использованием Optional. Котлин же наоборот обязует для любого типа всегда использовать строгий контракт по поводу nullability без возможности послабления. Почему это плохо? Приведу пару демонстративных кейсов.
Функция, которая конвертирует объект в строку, причем для null-ов она должна возвращать null.
Проблема в том, что она всегда обязана возвращать nullable String и обязует каждый раз делать проверку, даже когда поставляемый объект заведомо не null и описан в ситеме типов как не-null. Котлин не позволяет описать контракт "верни мне String? для Any? и String для Any", перегрузить функцию не получится — возникнет конфликт сигнатур.
Очень ленивая инициализация. Для nonnull полей Kotlin требовал сразу указать дефолтное значение. Логично. Но практически сразу же разработчики столкнулись с диким баттхертом при интеграции с различными библиотеками (DI, JUnit, сериализация, etc...), где значение поля вычислялось и заполнялось отложенно. Пришлось включить попятную и добавить хак ввиде lateinit, дабы как-то это сделать юзабельным. Пример: есть JPA Entity с полем id, которое заполняется автоматически при персистенции объекта. Nullable я его не хочу делать, т.к. null там только на этапе конструирования.
И вот облом! Это не сработает, потому как при сохранении объекта JPA провайдер попытается прочитать из поля и получит kotlin.UninitializedPropertyAccessException.
Это все примеры того, что nullability, как и множество других свойств зачастую контекстно-зависимые и не могут быть объявлены статичным контрактом.
Да ладно? Вы никогда со структурами не работали? Не байндили формочки к UI?
NPE самая частовстречаемая, но легко детектируемая и отлаживаемая ошибка. А статичными контрактами далеко не всегда удается вывести nullability. Вместо, чтобы вставлять nullability в контракт, просто поставьте Objects.requireNonNull() или лишний assert там, где это нужно и дело в шляпе.
Как всегда, все приведенные аргументы мелкие и несерьезные: у нас есть фича A, а у вас ее нет, либо она хуже и вообще плохая. Я тоже писал проекты на Kotlin, но до сих пор предпочитаю Java, и вот почему:
Я имел ввиду именно написать калькулятор, а не продать его проект клиенту...
У них была халтура копипейстнутая, а не калькулятор. Накидать прототип и задизайнить несколько скинов — дело одного вечера. А персонально для Джобса разыграть трогательную историю создания, в которую он поверит и проникнется. Просто никто работать не хотел — сам босс зарубил, значит выпилим, и дело в шляпе.