Как стать автором
Обновить

Комментарии 519

Пробуем Aurelia в одном проекте. Проблема с плагинами, точнее плохой поддержкой typescript определений для плагинов. Документация самой аурелии не все описывает, сейчас уже не вспомню, но проходилось гуглить.
Вроде и статья более-менее объективная, и разложено хорошо, но блин, сложно серьезно воспринимать человека, который $inject руками прописывает.

А что с этим не так? Видимо strictDI включен.

Adds Angular 1.x DI annotations to ES5/ES6

Здесь рассматривается Angular 2/4. Но, опять же, это вкусовщина. Кому-то нравится использовать стандартный синтаксис без взяких дополнительных приблуд, которые так же нужно изучать (каждому приходящему новому разработчику). По-моему это нормально. Меньше зависимостей — меньше проблем для большого проекта.
Код автора — от AngularJS
Считаю это как раз хорошим паттерном, пусть и error prone, но зато чище со стороны TypeScript'а. И больше инкапсуляции.
Если же сравнивать со всякими ng-min и ng-annotate — в крупных проектах всегда есть места где они работают неверно и приводят к трудно-диагностируемым проблемам. Давно отказался от подобного.
Поддерживаю, приписывать $inject руками это хорошая практика, в отличие от использования всяких ng-annotate подобных поделок. Еще лучше прописывать в $inject импортированные имена (по карйней мере для своих/внутренних сущностей), исключает необходимость копипастить название сущностей.
А как автоматом $inject в таком случае прописывается habrahabr.ru/company/ncloudtech/blog/321584/#comment_10243970?

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

я тут с пол года назад думал про эти default и понял, что они не нужны. Import в javascript вообще спроектирован отвратительно, даже не трогая default, например, вот хочу я что-то заимпортировать из какого-то модуля, я пишу import, скобочки, и вот тут в скобочках я должен написать, что хочу, но при этом ни одна IDE мне не подскажет, что есть в модуле потому-что путь к модулю ещё просто не написан. Я должен либо наугад вспоминать, что там импортируется, либо пропускать скобочки, писать from 'путь', а дальше альтом перемещаться назад, а потом снова вперёд. Мелочь конечно, но когда она повторяется 30 раз за день, это начинает напрягать. Понятно, что можно сделать простейший сниппет решающий проблему, но всё же я считаю, что язык должен позволять полностью последовательное написание кода с автодополнением без необходимости прыгать туда-сюда. Например, в dart так:


import 'dart:ui' show Offset, PointerDeviceKind;

Default тоже ужасен, например, есть у меня в модуле export default class EventEmitter ..., и теперь даже если я написал путь к модулю, IDE опять же не предлагает мне EventEmitter потому-что якобы я должен придумать это имя. Но зачем? В 99.9% придуманное имя совпадает с импортируемым. В тоже время если бы default не было, то автодополнение нормально сработало бы по первым Ev (скобочки написать не проблема или добавить их в сниппет).
Ещё часто бывает, что неочевидно был default при экспорте или нет, приходится либо пробовать методом тыка (и иногда ошибаться), либо открывать код модуля.


В общем, я попробовал полностью отказаться от default и половина проблем исчезли, остальные добил сниппетом и парочкой плагинов для vscode. Так что, возможно, невозможность использовать экспорты по умолчанию — это плюс ангулара :)

Честно говоря никогда руками не пишу import руками, всегда делаю автоимпорт через Alt+Enter. IDE — Idea/WebStorm, в более свежих версиях стало очень удобно работать. Последний vscode не тыкал давно, но расстраивает, что там подобного нет.

Для TS в VSCode есть плагин для автоимпорта, вполне себе

Есть и встроенный в TS Server auto-import

default export по хорошему вообще нужно забанить в jslint/tslint.

Аргументируйте

Так выше ж уже привели аргументы. ИМХО дефолтные импорты/экспорты — худшее, что могло случиться с модульной системой JS.

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


Может они плохи для редакс-приложений, где куча всего экспортится и нету основного импорта, но для подхода один файл — один класс они вполне ничего.


Все проблемы с ИДЕ, которые еще есть — должны решаться, я думаю, в самих ИДЕ.


Хотя я согласен, что они — не идеальные, но называть их худшим, что могло случиться, что их нужно забанить по-умолчанию и так далее — это уже слишком, мне кажется.

Полностью согласен, пользуюсь исключительно автоимпортом. Однако он не может сопоставить имя импорта (которого еще нет) имени файла, потому как не понятно, что от куда должно импортироваться.

Не совсем понял вас, объясните, пожалуйста

Ну вот есть файл foo.js с содержимым вида


export default {
  foo: 'bar'
}

А в другом мы пишем… а что мы пишем? Не понятно. Только руками в начале файла — import Foo from 'foo';


Было бы export const Foo = ..., то при упоминании Foo в коде, IDE/editor подсказали бы что к чему

const foo = 1
export default foo

Но так еще хуже =)

es6-модули это вообще классный пример как в tc39 работа идет — хотели как лучше, получилось как обычно

Попробуйте расширение TypeScript Hero для vscode. Он избавит вас от необходимости вручную писать импорты в большинстве случаев. Или TypeScript Importer, но у него меньше функционал.
Но несмотря на подобную поддержку со стороны IDE у меня тоже есть претензия к языку, правда в моем случае именно к Type Script. Поскольку тип у него идет после имени переменной (что, видимо, типично для языков с необязательной типизацией), то часто по сути приходится одно и то же слово набирать два раза. Первый раз с маленькой буквы для имени переменной, и второй раз с большой — для имени типа. Например, myFunc(control: Control) {}. Для vscode не нашел расширений, решающих эту проблему.

Спасибо за хорошую статью, очень полезный опыт!


По моему мнению, с Angular2 так вышло, потому что его разработчики не пытались завоевать пользователей, что все пользователи AngularJS придут к ним сами.


В то время как Vue и другим фреймворкам приходится бороться за пользователя, и когда они это делают, их API становятся проще и удобнее, а документация — понятнее.

Мы у себя после некоторых раздумий начали использовать UniGUI.
Плюсы:
Фактически связанный фронтэнд + бекэнд в одном приложении.
Ультра-быстрый дизайн форм и написания приложения.
Удобная отладка с нормальной средой.
Хороший саппорт, оперативно исправляют вопросы и, вообще, помогают.
Вылизанная, безглючная, либа фронт-энда и связка с ней (ExtJS).
Множество примеров.
Почти сотня десктоп компонент + около 50ти мобильных.
Постоянное развитие библиотеки.
Рекомендую.

К слову — Идера (текущий владелец Delphi), купила Sencha, изготовителя ExtJS, либо будут свою обвязку её делать, либо купять UniGUI. Радует движение в сторону веба.

Вы забыли упомянуть, что UniGUI стоит от 400 до 900 долларов, в то время как все UI-библиотеки из статьи — опенсорсные и бесплатные

Да, они стоят от двух недель до месяца зарплаты среднего программиста JS, зато существенно и постоянно экономят время и деньги после покупки, которые всё равно будут уплачены.
Для начала — оно не полностью опенсорсное.
А покупка сенчей сейчас кажется скорее минусом, нежели плюсом. Считаю, что времена тотального господства ExtJS в enterprise сегменте медленно подходят к концу, а последняя версия библиотеки — монструозный атавизм (ведь по-прежнему все свое — классы, разметка, билд системы и т.д). И да, я много работал с ним и знаком с их прекраснейшими и супер-функциональными компонентами.
Покупка конкретно для UniGUI не ухудшает его положение. Как сказал Фаршад (основной разработчик либы) OEM соглашение подписано на годы вперед и с лицензиями проблем нет и не будет.
монструозный атавизм (ведь по-прежнему все свое — классы, разметка, билд системы и т.д)

Своя система классов, на порядок более богатая, существенно более вменяемая, чем ES6, а главное, работающая — это, безусловно, атавизм. Нынче в моде псевдо-недофичи, которые бабушки из TC39 писями на воде виляют, приговаривают: то ли примем, то ли нет, транспилятор на обед, вот те grunt, а вот webpack, не сойти б с ума никак.


И да, я много работал с ним и знаком с их прекраснейшими и супер-функциональными компонентами.

Наверное, недостаточно знакомы. Я вот сколько ни смотрю на все эти ангуляры и реакты, так грустно становится, туфта на постном масле. :( Виджеты если и есть, то до того убогие, аж оторопь берёт. На grids без кровавых слёз не взглянешь. В Clarity Dataview чуть потыкал, с десяток багов нашёл. Они вообще тестируют эти поделки хоть как-нибудь?


Вот не флейма ради, а просвещенья для, где вы берёте годный grid с поддержкой редактирования данных, валидации ввода и data binding для Vue или Angular?

А ES6 классы не работают? Вообще очень печально, если вы не можете понять чем хороши все эти новые недо-фичи в сравнении с весьма спорными и давно устаревшими подходами в Ext.
Про усталость JavaScript'а написано многое, но это не делает webpack менее крутым.

Ну хотите верьте, хотите нет — работал с Ext не один год. Безусловно такой библиотеки контролов нет и не будет ни для одной из описанных библиотек/фреймворков.
Ну так зато они не стоят *тысяч долларов*, а бесплатны и опенсорсны.

А полноценные гриды в серьезных компаниях чаще пишутся либо самостоятельно. Нам в нашем проект Clarity хватило.
Странно, что всегда разговор заходит о 'тысячах долларов'. Как будто программисты бесплатные :) Программисты, на длительном промежутке времени, стоят сильно дороже инструментов разработки. Ну если только у вас не рабы за еду работают, конечно :)
Попал? Минусующим — работаете за еду? :)
Кармадрочерам: больше минусов, больше!!! :)

UniGUI это не инструмент разработки, а UI-библиотека. Подписываясь на ее покупку, вы отдаете себя на милость выпускающей компании.


Если потом понадобится какая-то фича или новый компонент, вам придется ждать, пока компания ее заимплементирует.


При использовании Angular или другого фронтенд фреймворка все под вашем контролем, какие хотите компоненты, такие и пишите, или готовые можно взять, если найдутся подходящие.


Да и на рынке труда найти ангулярщика в команду намного проще, чем UniGUI-шника.

То есть — в случае Унигуя мы отдаёмся на милость, а в случае ангуляра — нет? С логикой как-то сложно.

Angular не дает вам никаких компонентов. Съехать с ангуляра на другой фреймворк намного проще. Шансов поменять UniGUI на что-нибудь другое без переписывания с нуля вообще никаких.

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

«Шансов поменять UniGUI на что-нибудь другое без переписывания с нуля вообще никаких.»

Формы поменять только. В коде изменения минимальны. Мы как раз — наоборот — с вин-гуя переписали порядка 50ти форм на уни-гуй. Месяца 1.5 где-то работы.

Кажется, вы живете совсем в другой вселенной. Где веб-приложения пишутся не на веб-технологиях, а на их эмуляции через javascript.


Это, безусловно, очень интересно, но не для людей, комфортно чувствующих себя в Javascript.


Предлагаю на этом дискуссию и закончить.

Эмуляция веб-технологии через javascript — сильно, очень сильно :)
Нужно понимать простую вещь: веб технологии бывают разные. Очень разные.
Ладно, закончим так закончим.

да, опечатался. Имелось в виду


Где веб-приложения пишутся не на нативных веб-технологиях, а эмуляции декстопных API через javascript.
А ES6 классы не работают?

Кое-как работают, там, где они есть. В IE11 есть? Ой, нет. А что умеют? Ой, почти ничего не умеют. Mixins умеют? Нет. Overrides умеют? Нет. Hooks умеют? Нет. Dependency resolution умеют? Нет. Господи, ну хоть статические свойства классов-то умеют? Неа, всё ручками. Пилите, Шура, пилите...


Вообще очень печально, если вы не можете понять чем хороши все эти новые недо-фичи в сравнении с весьма спорными и давно устаревшими подходами в Ext.

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


но это не делает webpack менее крутым.

Чем конкретно крут webpack? По пунктам, если не трудно; бонусные баллы за объективное сравнение с другими решениями. Подозреваю, что дальше "webpack крут, потому что его Angular же использует!" вы не уйдёте.


Ну хотите верьте, хотите нет — работал с Ext не один год. Безусловно такой библиотеки контролов нет и не будет ни для одной из описанных библиотек/фреймворков.

Да чего ж не верить? Верю. Печально, что кроме библиотеки виджетов вы ничего не заметили или не оценили.


Ну так зато они не стоят тысяч долларов, а бесплатны и опенсорсны.

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


А полноценные гриды в серьезных компаниях чаще пишутся либо самостоятельно. Нам в нашем проект Clarity хватило.

У нас с вами очень разные понятия о полноценности таких интересных компонентов, как grids. И об уровне допустимого качества, очевидно, тоже. И даже, рискну предположить, "сёрьезность" компаний мы воспринимаем весьма по-разному; хотя, на мой взгляд, тут дело скорее в задачах, нежели в компаниях.


Я бы мог много разных примеров из опыта привести, скажем про одного несолидного немецкого производителя люксовых авто, которому приспичило запихнуть навигацию/просмотр/редактирование базы из ~9 млрд парт-номеров запчастей в один TreeGrid. С "бесконечной" прокруткой, страничной подкачкой по запросу и прочими весёлыми штуками. Ну, вот дураки там сидят, не осилили сами-то запилить.


Или про один забавный и крайне несолидный НИИ в Швейцарии, который там коллайдеры всякие гоняет туда-сюда, а данных-то с них 100500 терабайт или что-то такое. Визуализировать надо, для обработки и анализа. Тоже идиоты, ха-ха, да плёвое ж дело самим-то налабать.


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


Мог бы рассказать, но зачем? У вас уже всё солидно, Clarity хватает со всеми багами, значит всем остальным тоже должно хватать.

В IE11 есть? Ой, нет.

При чем тут IE?


Mixins умеют? Нет.

Миксины много кто не умеет. Да и можно достичь подобия через анонимные классы и HOF


Overrides умеют? Нет.

Все умеют


Hooks умеют? Нет.

Какие еще хуки?


Dependency resolution умеют? Нет.

Какой еще resolution в динамическом языке?


Господи, ну хоть статические свойства классов-то умеют? Неа, всё ручками.

Все умеют

При чем тут IE?

Вообще ни при чём, кроме того, что многие организации до сих пор Windows 7 используют и IE11. И модернизироваться не собираются. А некоторые даже за поддержку Windows XP и IE8 платят, дураки несолидные.


Ну, вам-то там в воображаемом мире конечно недосуг во все такие мелочи вникать. У вас там бабочки порхают, единороги прыгают, и все юзеры только пальчиками в айфоны последней модели тыкают.


Миксины много кто не умеет. Да и можно достичь подобия через анонимные классы и HOF

Мне всё равно, кто что не умеет. Я отвечал на вопрос: а чем таким плохая, негодная, архаичная классовая система Ext JS может быть лучше модной, годной, молодёжной ES6. Спрашивали? Отвечаем.


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


Все умеют

Условные тоже, и декларативно? Приведите примеры, если не сложно.


Какие еще хуки?

Да простые, типа таких: onBeforeClassCreated, onClassExtended, etc. Чем они могут оказаться полезны, объяснить или сами догадаетесь?


Какой еще resolution в динамическом языке?

Да вот такой, простой. Класс Foo зависит от класса Bar, и использует Qux. При загрузке класс Foo не создаётся, пока не загрузятся Bar и Qux, со всеми своими зависимостями.


И в динамическом языке, ага. Работает уже лет 8 как. И инструментарием поддерживается для сборки. А вы дальше там простыни import-ов ручками пишите, удачи.


Все умеют

Статические свойства классов. Вы давайте, приводите примеры в ES6, не стесняйтесь. Я-то свои слова подкрепить могу в любой момент, зря что ли этот кусок перелопачивал и тестами закрывал. :P

Забавно, у вас так бомбит, что вы скатываетесь в обыкновенное плоское хамство. Вы такой тут опытный эксперт, а все кругом плебеи, голова не жмет? :)
Я вам тут ничего не продаю и ничего доказывать не собираюсь, научитесь для начала манерам, а потом будем (пытаться) строить диалог.
Если же все-таки нужно, гуглите, не стесняйтесь — объяснить как это делается или сами догадаетесь?: Р

Забавно, у вас так бомбит, что вы скатываетесь в обыкновенное плоское хамство.

Да зачем же скатываетесь, и не выкатывался даже. Это разве не общепринятый в местных пенатах тон? :)


Вы такой тут опытный эксперт, а все кругом плебеи, голова не жмет? :)

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


Я вам тут ничего не продаю и ничего доказывать не собираюсь

Взаимно. На том и закончим беседу, если не возражаете. :) Про гугля не переживайте, разберусь как-нибудь. :)

Какое отношение IE имеет к ES6 классам?


Кстати, держите миксины:


function fooMixin(base) {
    return class Foo extends base {
        // ...
    }
}

class Baz extends fooMixin(Bar) {
    // ...
}
Какое отношение IE имеет к ES6 классам?

Простое: они в IE не работают и никогда не будут. А используется этот браузер ещё много где, и использоваться будет ой как долго. Ну, вот реальность жизни такая. Если вы хотите писать ES6 код, то вам придётся использовать инструментарий для переваривания этого кода в ES5.


Классовая система Ext JS появилась задолго до ES6, и работает во всех браузерах. Работает хорошо, протестирована неплохо и сюрпризов не преподносит уже давно.


А вот теперь внимание, вопрос: если всё равно нужно использовать какой-то инструментарий, и он уже есть свой, то имеет ли смысл кидаться впопыхах заменять его на чей-то чужой, просто ради "совместимости с будущим"?


Вот товарищ выше утверждает, что очевидно надо. Потому что журавль в небе очевидно лучше синицы в руках, это же JavaScript ZOMG.


Кстати, держите миксины:

Спасибо за пример, выглядит забавно. Наследуем от функции, которая возвращает функцию-конструктор.


Теперь ответный пример:


Ext.define('FooMixin', {
    extend: 'Ext.Mixin',
    mixinConfig: {
        id: 'foo'
    },
    ...
});

Ext.define('BarMixin', {
    extend: 'Ext.Mixin',
    mixinConfig: {
        id: 'bar'
    },
    ...
});

Ext.define('Baz', {
    extends: 'Quux',
    mixins: [
        'foo',
        'bar',
        ...
    ],
    ...
});

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


Но это ещё полбеды, я могу про overrides рассказать и как оно с mixins сочетается. Или как можно в mixin вклиниваться до/после метода в основном классе, и для этого не нужно бодаться с контекстом и замыканиями. Или про то, как можно вклиниться в процесс создания класса и декорировать его по необходимости. Или про то, как родительский класс может делать всякие хитрые штуки с наследником. Или ещё что-нибудь интересное, там много.


Но вот беда, вся эта полезность ужасно архаична, сомнительна и немодна. Зато работает хорошо. Пичалька.

ExtJS уже перестал требовать обмазываться километровыми JSDoc-ами со всех сторон? Я и сам писал раньше свою классовую модель с умными примесями, которые позволяли примешивать конфликтующие примеси, но требовали выбирать реализацию при использовании. Но преимущества TS — решают.


Вы описываете, безусловно, приятные мелочи, но..


  1. Это именно мелочи. Ну то есть и без них не чувствуешь себя калекой.
  2. Это не стандарт. Даже плохой стандарт лучше его отсутствия. Выражается это в богатстве инструментария, простоте изучения, переноса кода между проектами пр.
ExtJS уже перестал требовать обмазываться километровыми JSDoc-ами со всех сторон?

Нет, не перестал и вряд ли перестанет. Любая сложная система требует изучения и использования документации, это как бы данность. Когда-нибудь пробовали писать нативное Win32 приложение? DVD с MSDN под руками держать не приходилось? Или томик Advanced Unix Programming вместе с батареей манов, если вы с другой стороны баррикад?


Интуитивно! Изучать не надо! Оно всё само! — кричали возбуждённые пионеры от JavaScript, обкурившиеся передовых псевдо-технологий. Няшная картинка, аж слеза наворачивается.


Я и сам писал раньше свою классовую модель с умными примесями,

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


Это именно мелочи. Ну то есть и без них не чувствуешь себя калекой.

Конечно мелочи, ерунда какая. Всего-то полмиллиона строк кода в фреймворке надо будет переписать и протестировать, чтобы перестать чувствовать себя калекой.


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

Вот именно такие аргументы вы и излагайте вашим клиентам, когда решите сломать поддержку старого API чуть более, чем полностью, ради абстрактных будущих стандартов, которые ещё и не везде работают.


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

Любая сложная система требует изучения и использования документации, это как бы данность.

Сравните:


/**
 * @param {string} bar
 * @param {Function} fn
 * @return {Function}
 */
function makeMoreFunctions(bar, fn) {
    /**
     * @param {Object} baz
     * @return {string}
     */
    return function(baz) {
        fn();
        /**
         * @return {string}
         */
        return function() {
            return bar;
        };
    };
}

function makeMoreFunctions( bar : string , fn : ()=> void ) {
    return ( baz : {} )=> {
        fn();
        return () => bar;
    };
}

Всего-то полмиллиона строк кода в фреймворке надо будет переписать и протестировать

Горбатого могила исправит. И горбатость ExtJS далеко не в классовой модели. Более вменяемая архитектура потребовала бы в 10 раз меньше кода для того же объёма функционала.

Сравните:

Обожаю смотреть, когда сперва обсирают, скажем, Perl за слишком высокую плотность и нечитабельность кода, а потом с умным видом то же самое делают в JavaScript. Пусть даже и разные люди. Браво, автор! Жжи ещё!


Более вменяемая архитектура потребовала бы в 10 раз меньше кода для того же объёма функционала.

Товарищ, верь: взойдёт звезда
над питерским болото-лесом,
и на могиле Экстжееса
напишут $mol-а письмена.


Ларри, сцуко, прав был на 110%: laziness, impatience and hubris.

> Perl за слишком высокую плотность и нечитабельность кода, а потом с умным видом то же самое делают в JavaScript.

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

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


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

> Почему-то вам даже не приходит в голову, что кому-то может представляться всё с точностью до наоборот.

Речь об объективных, измеряемых факторах, а не о том, что кому-то представляется.

Какие критерии и методики измерения вы использовали для определения полезности той или иной плотности кода? Поделитесь, будьте добры.


Особенно интересно про снижение количества синтаксического мусора и и семантической нагрузки в коде, при повышении плотности.

> Особенно интересно про снижение количества синтаксического мусора и и семантической нагрузки в коде, при повышении плотности.

Если токен не несет никакой полезной ф-и (таковыми, например, часто являются скобки) — его можно убрать, плотность повысится, мусора станет меньше.

Если есть конструкция, которая инкапсулирует в себе несущественные детали поведения — кода становится меньше, плотность возрастает, а семантическая нагрузка падает. Пример: замена классического цикла for на map. В данном случае из кода пропадает информация о о счетчике, и о логике построения коллекции. По-этому collection.map(x => ...) вместо for — это хорошее, годное упрощение.
Речь об объективных, измеряемых факторах

Если токен не несет никакой полезной ф-и (таковыми, например, часто являются скобки) — его можно убрать, плотность повысится, мусора станет меньше.

Ещё раз: поделитесь методикой измерений и результатами исследований. Можно ссылками на чужие научные работы, тоже хорошо. Пока я вижу только голословные утверждения, основанные на чьём-то мнении.


По-этому collection.map(x => ...) вместо for — это хорошее, годное упрощение.

Цикл for() и операция map() семантически не эквивалентны, скорее даже ортогональны: процедурный подход против функционального. Цикл for() можно прервать заранее, можно изменять значение счётчика внутри цикла, и т.д. Несущественной деталью поведения эта разница может являться только в тривиальных случаях, которые и так особой смысловой нагрузки не несут.


И да, не надо пытаться продать мне функциональный подход. Я функциональщину нежно полюбляю и использую там, где она подходит, уже давным-давно.

> Ещё раз: поделитесь методикой измерений и результатами исследований.

Разобрать текст на токены и посчитать их количество.

> Цикл for() и операция map() семантически не эквивалентны, скорее даже ортогональны: процедурный подход против функционального. Цикл for() можно прервать заранее, можно изменять значение счётчика внутри цикла, и т.д.

Мы говорим о семантике конкретного кода, который заменяется на конкретный код, а не о семантике конструкций в общем. Если вы написали for с итерацией по списку, который дает тот же результат исполнения, что и map — то семантика двух вариантов кода эквивалентна, и for содержит несущественные для выполнения детали. Если в же у вас там какая-то особенная логика внутри — то, конечно, семантика неэквивалентна и поменять одно на другое нельзя — будет просто разный результат исполнения.

> И да, не надо пытаться продать мне функциональный подход.

Я вам ничего не продаю.
Разобрать текст на токены и посчитать их количество.

Методика озвучена, давайте теперь результаты исследований. Желательно опубликованные в научных изданиях, но и предпечатные манускрипты тоже подойдут. Ну, или хотя бы черновики из подготовки к печати. Тема очень интересная, готов сделать скидку.


Мы говорим о семантике конкретного кода, который заменяется на конкретный код, а не о семантике конструкций в общем.

Цитирую:


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

Сперва вы делаете магические пассы руками и рассуждаете о семантической нагрузке конструкций в общем, потом оказывается, что речь уже идёт о конкретных примерах кода. Так всё же, А или Б сидели на трубе?


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


Религиозные войны обычно с того и начинаются, что кто-то пытается продать другим людям своих личных тараканов под видом абсолютной истины. Не трогайте моих тараканов, а я не трону ваших.

> Методика озвучена, давайте теперь результаты исследований.

Исследований чего?

> Сперва вы делаете магические пассы руками и рассуждаете о семантической нагрузке конструкций в общем

Нет, не рассуждаю. Вы как-то неверно поняли. Или я плохо сформулировал. Естественно, всегда оценивать надо конкретный код, то есть конструкцию в данном контексте, а не в общем, саму по себе.

Дело даже не столько в том, что код с JSDoc занимает в 5 раз больше места, сколько в том, что JSDoc не обладает описательной мощностью. Чего только стоит @return {Function}. Фактически JSDoc — это кривая статическая типизация для динамического языка. Сейчас есть более вменяемые инструменты статической типизации в виде Flow и TypeScript. Это не значит, что нужно всё бросать и срочно переписывать миллион строк говнокода (да-да, мне приходилось погружаться в это чудо с головой). Но эта вот технологическая устарелось уже даже не на сегодняшний, а на вчерашний день, — причина по которой толковые разработчики не горят желанием выбирать его для будущих проектов.


Вы бы не сарказмировали, а почитали/посмотрели этот доклад, хотя бы: Объектное Реактивное Программирование
Там описывается техника, реально позволяющая писать в 10 раз меньше кода, чем в том же ExtJS. Реактивное Программирование даёт хороший буст к производительности программиста и уменьшению багоёмкости производимого им кода.

@returns {function(string): boolean}


JSDoc довольно выразителен, зря вы на него так. Flow более вменяем, конечно, но для него нет ни одного инструмента для генерации документации.
По вашей же ссылке в самом начале:
You can use any Google Closure Compiler type expression, as well as several other formats that are specific to JSDoc.

И далее посмотрите Function Type и Function Return Type в списке аннотаций Closure Compiler.

JSDoc3 много в себе содержит того, чего нет в официальной документации. И подобная запись замечательно парсится самим jsdoc, можете попробовать сгенерить AST через опцию -X.

Более того, WebStorm и PyCharm замечательно использует jsdoc для генерации документации на лету по хоткеям Ctrl+Q, позволяя перемещаться между типами (если это не примитивные типы, а где-то в другом месте проекта объявленные через typedef).

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

Это называется "не поддерживается", а не "не работает". И, вообще-то, давно уже существуют способы обойти это ограничение.


Вот скажите, а у ваших веб-приложений бакэнды есть? И если есть — на чем они написаны?


Если на PHP или каком-нибудь Perl — то вопросов больше нет. А если на других языках программирования — то возникает вопрос, почему необходимость компиляции исходников для бакэнда — это давно уже считается нормальным, а то же самое для фронтэнда — ужас-ужас.


Что лучше читается?

К чему привык — то и читается лучше, это не показатель. Но вот поддержка со стороны IDE у классов ES6 — лучше.

Это называется "не поддерживается", а не "не работает".

Цитируя любимого домовёнка: а всё одно, всё едино! Если не поддерживается, то по определению не работает. И не будет.


И, вообще-то, давно уже существуют способы обойти это ограничение.

Конечно существуют. Один из них мы как раз и используем, а именно, собственную систему классов, написанную на чистом JavaScript и обратно совместимую вплоть до чёрти куда.


Вот скажите, а у ваших веб-приложений бакэнды есть? И если есть — на чем они написаны?

Есть и на всём, что угодно. Есть на Java и Scala и C#, и на ColdFusion и на PHP, и на всех скриптовых языках, и даже на Go мимо пролетало.


У каждого клиента свои предпочтения по тараканам в голове, я стараюсь не судить людей. /s


Если на PHP или каком-нибудь Perl — то вопросов больше нет.

Ой как я люблю вот такие вот обобщения. Какой-нибудь там PHP или Perl, или там Python или Ruby, несолидные такие штуки, негодные. Круто как, одним махом — эх! Половину индустрии под одну гребёнку и в мусор. Размах!


А если на других языках программирования — то возникает вопрос, почему необходимость компиляции исходников для бакэнда — это давно уже считается нормальным, а то же самое для фронтэнда — ужас-ужас.

Про считается нормальным — это вы вон тем, вышесметённым в мусор расскажите. А потом вас догонят извращенцы, которые на серверной стороне JavaScript пользуют, им тоже расскажите. Потом и я могу свои пять копеек вставить, если желание не отпадёт.


К чему привык — то и читается лучше, это не показатель. Но вот поддержка со стороны IDE у классов ES6 — лучше.

А у меня в носу козявки больше, бе-бе-бе. Аргумент примерно такого же плана.


Лично мне IDE вообще до одного места. Я бОльшую часть времени всё равно у браузера в отладчике живу, ну и в консоль одним глазом посматриваю.

Перестаньте читать между строк то, чего там не написано.


PHP я упомянул как пример интерпретируемого языка, которому не нужна стадия компиляции.

Перестаньте читать между строк то, чего там не написано.

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


PHP я упомянул как пример интерпретируемого языка, которому не нужна стадия компиляции.

Про PHP я не в курсе, не эксперт. Когда-то пришлось несколько месяцев ковырять исходники vBulletin, обе руки отвалились креститься наотмашь — закодировался, завязал и больше не пробовал, тьфу*3.


А вот как минимум про Perl и Python вы глубоко ошибаетесь: это языки динамические, но стадию компиляции они проходят ещё как. Ruby тоже, если мне склероз не изменяет.

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

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

Спасибо за спонтанный сеанс психоанализа, премного благодарен. Куда чек прислать? :)

> Лично мне IDE вообще до одного места. Я бОльшую часть времени всё равно у браузера в отладчике живу, ну и в консоль одним глазом посматриваю.

Получается, в ваши основные задачи написание кода не входит. Может, в этом причина несогласия?
Получается, в ваши основные задачи написание кода не входит. Может, в этом причина несогласия?

Почему же, ещё как входит. Просто как-то так получилось, что на меня обычно падают задачи архитектурного плана, которые требуют переворошить половину кода. Все люди разные, кому-то нравится блестящие виджеты полировать, а мне вот по душе выжать соки из набора тестов и сделать, чтобы прогон pull request занимал не час, а полчаса. Или отбить в тряпочку все компоненты, чтобы поймать утечки памяти и заткнуть дырки, чтобы больше не текло. Или добавить поддержку accessibility там, где оно в принципе не росло.


Такие интересные штуки часто требуют глубокой хирургии, когда кода пишешь мало, а тестов дофига много, и потом гоняешь-гоняешь-гоняешь вдоль и поперёк, чтобы не дай бог что не сломалось. Можно на месяц-другой занырнуть и морщить лоб, а потом ещё в кучку всё это собирать. И основная работа идёт именно в браузерах, а IDE тут никаким боком не поможет.


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


Хотя вот иногда и без IDE трудно. Приблуда, которая тесты через WebDriver гоняет, написана на Java, и надо и её тоже переворошить, чтобы результаты стабильнее возвращались. Глаза в кучу...

Лично мне IDE вообще до одного места. Я бОльшую часть времени всё равно у браузера в отладчике живу, ну и в консоль одним глазом посматриваю.

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

Категорически согласен. Уже несколько лет не приходилось серьезно пользоваться отладчиком.

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


  • Несовместимое с другими версиями поведение обработчиков onreadystatechange элементов <script> в IE10
  • Нестандартное поведение querySelector на XML объектах в Chrome, и проблемы с selectSingleNode на оных же в IE8-9
  • Нестандартное поведение элемента <input type="file"> в IE/Edge
  • Проблемы с фокусированием элементов <input type="text"> и <textarea> в IE всех версий
  • Проблемы с flexbox в IE11 и определённых версиях Safari
  • Нестандартное поведение клавиатурных событий в определённых версиях мобильного Safari
  • Проблемы с некорректной обработкой атрибута aria-owns в Firefox
  • Проблемы с некорректным фокусированием родительских элементов на mousedown в Firefox же
  • Проблемы с некорректной обработкой табуляции на <input type="radio"> в нём же, болезном
  • Несопоставимо с жизнью медленная обработка синхронного setTimeout/clearTimeout в Chrome
  • Периодически ломающиеся обработчики различных событий в нём же
  • И так далее, и тому подобное, список в пять локтей длиной

Я достал блокнотик, высунул от усердия язык и с нетерпением жажду потока ценных указаний.

В случае специфических проблем с производительностью без профилировщика обычно, конечно же, никуда, но вот для чего вам в вышеприведенных примерах отладчик нужен — ума не приложу. Конкретно с вашими примерами я не встречался, но вещи, связанные с особенностями конкретного браузера, конечно, вызывали иногда проблемы. Но никогда не приходилось использовать для решения этих проблем отладчик. Собственно, я вообще не использую отладчик. Зато использую ИДЕ :)
В случае специфических проблем с производительностью без профилировщика обычно, конечно же, никуда, но вот для чего вам в вышеприведенных примерах отладчик нужен — ума не приложу.

Понюхал старик Ромуальдыч свою портянку и аж заколдобился… Ну вот, что я могу вам на это сказать? Видимо, вы какой-то особенный гигант мысли, способный по полутора симптомам и двум строчкам кода вникнуть, решить и пойти дальше. Завидую и преклоняюсь, преклоняюсь и завидую.


У меня вот, бывает, дни уходят, да какие дни — недели иногда. Как в том случае, когда невинная вроде на вид JavaScript конструкция роняла процесс IE7 с segmentation fault. Там тоже в отладчике пришлось пожить, только уже в Visual Studio. Да и ничего, потужился малость и нашёл баг в mshtml.dll, и способ обхода тоже.


Конкретно с вашими примерами я не встречался, но вещи, связанные с особенностями конкретного браузера, конечно, вызывали иногда проблемы. Но никогда не приходилось использовать для решения этих проблем отладчик. Собственно, я вообще не использую отладчик. Зато использую ИДЕ :)

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

> Видимо, вы какой-то особенный

Да нет, не использовать отладчик — вполне обычная практика.

> В случае клиентов Sencha это как раз я и ещё несколько таких же болезных.

Ну у вас же есть исходники? Зачем тогда отладчик? Обычно, почти всегда гораздо быстрее просмотреть код, чтобы найти ошибку, чем дебажить. Другое дело, если код откровенно плох.
Да нет, не использовать отладчик — вполне обычная практика.

Не использовать отладчик в браузере или не использовать отладчик вообще? В первом случае практика обычная в вашем случае и не применимая в моём; второй случай был бы слишком прискорбным, чтобы о нём думать.


Ну у вас же есть исходники? Зачем тогда отладчик?

Исходники чего, браузеров? Я уже который раз пытаюсь объяснить, что большая часть моего времени уходит на борьбу с браузерами и их различнейшими косяками. Одна и та же HTML/CSS разметка может вести себя по-разному в IE, Safari и Firefox. Один и тот же JavaScript код может вести себя по-разному в Chrome и Edge.


В какие исходники вы будете смотреть, когда из-за невинного вроде бы изменения конфигурации тестовой системы у вас начинают наглухо зависать тесты в IE11?


Обычно, почти всегда гораздо быстрее просмотреть код, чтобы найти ошибку, чем дебажить. Другое дело, если код откровенно плох.

При прокрутке строк в компоненте Tree с определённой конфигурацией, если прокручивать примерно по 10 строк, то на 20 или 30 строке случается "прыжок" обратно на 10 строк, после чего прокрутка срабатывает нормально.


Это описание из реального тикета, который меня попросили посмотреть сегодня. Читайте код, пронзайте силой мысли. Отладчик не использовать. Удачной охоты, время пошло.

> Не использовать отладчик в браузере или не использовать отладчик вообще?

Никто не говорит о неиспользовании в принципе, это уже будет какое-то религиозное убеждение. Речь о том, что реальная потребность в его использовании возникает крайней редко.

> Исходники чего, браузеров?

Так вы про отладку чего, самого браузера, в опкодах? Я-то думал вы про js, уточняйте тогда хоть.
Речь о том, что реальная потребность в его использовании возникает крайней редко.

Вы мне про Фому, я вам про Ерёму. У вас такая потребность возникает редко, у меня часто. Просто примите как данность, ладно?


Так вы про отладку чего, самого браузера, в опкодах? Я-то думал вы про js, уточняйте тогда хоть.

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


Я никак не могу взять в толк, каким образом мне помогла бы IDE и каким образом я могу обойтись без отладчика в браузере, если проблема специфична для браузера.


Впрочем, мы уже по десятому кругу повторяем одно и то же. Мне уже времени жалко, давайте что-нибудь более интересное обсуждать.

> Я никак не могу взять в толк, каким образом мне помогла бы IDE и каким образом я могу обойтись без отладчика в браузере, если проблема специфична для браузера.

А я никак не могу понять, чем вам поможет отладчик. Именно в том случае, если проблема специфична для браузера.
А я никак не могу понять, чем вам поможет отладчик. Именно в том случае, если проблема специфична для браузера.

Гм. Отладчик JavaScript в браузере чем поможет? Ну не знаю, пошагово инструкции пройти или там переменные посмотреть. Прерывание поставить, посмотреть что происходит и откуда что приходит. В DOM заглянуть. Обычная отладка, в общем.


Что именно тут может быть непонятным?

> Что именно тут может быть непонятным?

Как это поможет вам понять в чем проблема, если код выполняться будет одинаково? Проблема ведь не в отлаживаемом коде будет.

Иногда код исполняется одинаково, иногда нет. Чаще всего проблемы не в исполнении JavaScript кода как такового, а в других частях браузера: DOM объектах, XML объектах, обработчиках событий, и т.д. Все эти объекты нативные, спецификацией JavaScript не закрыты и отданы на откуп производителям браузеров, иногда возникает разница в поведении. Ну, и баги тоже бывают, куда без них. Отладчик JavaScript как раз и помогает увидеть, как определённые вещи делаются в определённом браузере, и сравнить поведение с другими.


Одна из основных задач фреймворка — обеспечение одинаковой работы пользовательского кода во всех поддерживаемых браузерах. Не могу сказать, что мы справляемся с этой задачей на 100%, но стремимся, поэтому так или иначе нужно все эти проблемы обходить в JavaScript и CSS, других вариантов нет.

Читайте код, пронзайте силой мысли. Отладчик не использовать. Удачной охоты, время пошло.

Код-то отдайте :-)


PS на всякий случай поясняю — это шутка, в незнакомом проекте я за такой поиск бага не возьмусь. Вот в знакомом — другое дело.

Спасибо что пояснили, а то я уже полез за ссылками. :)


Впрочем, код и правда весь доступен для просмотра, вместе с тестами и прочей обвязкой, так что если будет интерес покопать весьма нетривиальные проблемы, заходите. ;)

К счастью с IE давно не работаю, но все проблемы, которые вы описали выглядят как «один раз разобрался, написал абстракцию и забыл до конца жизни».

Несопоставимо с жизнью медленная обработка синхронного setTimeout/clearTimeout в Chrome

А вот про это поподробнее, пожалуйста.
К счастью с IE давно не работаю, но все проблемы, которые вы описали выглядят как «один раз разобрался, написал абстракцию и забыл до конца жизни».

Отлично, по первому пункту возражений не возникло. А теперь маленький ньюанс: надо всего лишь разобраться и написать абстракцию. Пол-дела сделано, осталось уговорить Рокфеллера. (с)


Или вы думаете, что по всем этим проблемам где-то многотомная документация написана?


Несопоставимо с жизнью медленная обработка синхронного setTimeout/clearTimeout в Chrome
А вот про это поподробнее, пожалуйста.

Это был такой забавный косяк в нашей реализации Jasmine, вылезший во время очередного раунда профилировки: перед входом в функцию-тело it() ставили таймер на случай, если что-то пойдёт не так, после выхода из функции таймер сбрасывали и шли дальше по очереди. В 99%+ случаев функция отрабатывала синхронно и таймер не пригождался; Chrome, как выяснилось, такой подход не любит и пара setTimeout/clearTimeout сжирала заметную долю собственного времени Jasmine. После того, как я переписал этот кусок, очередь стала пробегать на ~50% быстрее — но только в Chrome, в других браузерах эффект был далеко не так выражен.


Специально даю контекст, чтобы было понятно: проблема весьма специфична и встречается только в случаях, когда вы делаете миллионы вызовов пары setTimeout/clearTimeout в пределах одного цикла событий.

Я хотел бы заметить, что отладчик и профилировщик — слегка разные вещи.

Или вы думаете, что по всем этим проблемам где-то многотомная документация написана?

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

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

Выше я сказал правду — мне уже несколько лет не приходилось серьезно залипать в отладчике. Так, гляну иногда, какие именно данные пришли или куда стек ошибки ведет, но обычно IDE за меня все решает. Раньше, когда хуже понимал код — пользовался отладчиком чаще. Еще раньше, когда еще хуже понимал код — вообще алертами отлаживал. Правда, firebug тогда еще не появился))

А теперь маленький ньюанс: надо всего лишь разобраться и написать абстракцию.

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

Я бОльшую часть времени всё равно у браузера в отладчике живу


Я вот сейчас игру на Юнити пишу, так отладчик даже не настраивал — в нем еще ни разу не было необходимости
Но не забывайте, что пользователи Сенчи уже не столкнутся с этими проблемами, а следовательно им помощь IDE — крайне уместна.

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


Ну вот, просто ради мысленного эксперимента допустите, что у нас с вами совершенно разные задачи?


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

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


Я вот сейчас игру на Юнити пишу, так отладчик даже не настраивал — в нем еще ни разу не было необходимости

Это больше говорит о низком качестве вашего QA. Либо о высоком качестве QA этого самого Unity, чем бы оно ни было.

Ну вот, просто ради мысленного эксперимента допустите, что у нас с вами совершенно разные задачи?

Ваша проблема в том, что вы потеряли контекст. Изначально была речь о том, что интерфейс фреймворка был бы значительно удобнее для конечных пользователей, если бы использовались ес6-классы. Вам, конечно, может и все-равно, вы ведь в отладчике работаете, а пользователи — в IDE. Грустно, что вы так далеки от своих пользователей.

Тем более, я повыше уже признал, что, возможно, лично вы, как разработчик фреймворка, сидите в отладчике значительно чаще, чем любой другой жс-разработчик. Но я все-равно не верю, что вы сидите там БОЛЬШУЮ часть времени.

Это больше говорит о низком качестве вашего QA. Либо о высоком качестве QA этого самого Unity, чем бы оно ни было.

Жаль, что вам не приходит в голову идея, что я просто могу писать хороший код.

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

Увы, лично я давно не видел серьезной разницы между браузерами. Даже когда писал канвас-фреймворк — так, пару костылей для Оперы старой вставил, да еще пару для других браузеров, а дальше оно все работало одинаково.

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

Может, конечно, дело в том, что мы не поддерживаем IE.
Изначально была речь о том, что интерфейс фреймворка был бы значительно удобнее для конечных пользователей, если бы использовались ес6-классы.

Согласен, но эта идея была построена на неверной посылке: подразумевалось, что ES6 классы имеют поддержку IDE, а классы Ext JS её не имеют. Это не совсем так, существуют плагины Sencha для популярных IDE. Не могу сказать, насколько они хороши или плохи, т.к. сам ими не пользуюсь.


Вам, конечно, может и все-равно, вы ведь в отладчике работаете, а пользователи — в IDE. Грустно, что вы так далеки от своих пользователей.

К сожалению, это факт — работа разработчика фреймворка мало пересекается с работой собственно пользователей этого фреймворка. Я пытаюсь этот разрыв сокращать, периодически работая над какими-то персональными проектами на базе Ext JS; dogfooding очень помогает лучше понять болевые точки пользователей. :)


Про IDE я в курсе, большинство моих коллег тоже ими пользуются — если не ошибаюсь, в основном JetBrains. Но они тоже больше заняты разработкой нового кода, чем поддержкой/улучшением существующего.


Но я все-равно не верю, что вы сидите там БОЛЬШУЮ часть времени.

Я не считаю, сколько времени трачу на написание кода и сколько на отладку/поиск проблем, но по ощущениям отладка и правда занимает бОльшую часть времени. По крайней мере последнюю пару лет, раньше я действительно больше занимался разработкой и меньше улучшениями.


Жаль, что вам не приходит в голову идея, что я просто могу писать хороший код.

Как человеку, съевшему три собаки на отладке и тестировании кода, такая мысль прийти мне в голову не может в принципе. :)


Хорошего кода не бывает, бывает код приемлемый по качеству.


Может, конечно, дело в том, что мы не поддерживаем IE.

И в этом тоже, но скорее дело в специфике ваших приложений. Если вам не нужно работать с клавиатурой, фокусом и соблюдать требования по доступности, то это снимает изрядную долю проблем. Наш фреймворк должен всё это обеспечивать, и ситуация усложняется многократно.

Посмотрел бы я на вас на работу с WebGL, канвасами и воркерами без отладки :)
Я как бы много лет работал с ВебГЛ, канвасами и прочим. Конечно, иногда приходилось пользоваться отладчиком, но явно не «бОльшую часть времени всё равно у браузера в отладчике живу».

Тем более, чем больше работал — тем меньше необходимости в отладчике было
Вы хотите сказать, что без отладки сядете, и запилите без отладки что-то наподобие такого (UniGUI + WebGL)?
image
image
image
image
Вы хотите сказать, что без отладки сядете, и запилите без отладки что-то наподобие такого (UniGUI + WebGL)?

Иногда приходилось бы пользоваться отладчиком, конечно. Но редко. И уж явно не «большую часть времени».

Я, обычно, очень хорошо представляю в голове поток своей программы, особенно хорошо типизированной. Зачем в таком случае постоянно висеть в отладчике?
Скажу лишь, что в данном случае большинство проблем описанных вами как раз решаются использованием TypeScript. И будут классы, хоть в IE8.

Ваша преданность делу Microsoft достойна уважения, но предположительные причины оной восхитительно сомнительны и чрезмерной весомостью не располагают. Засим позвольте откланяться и не задерживать вас более от дел солидных своей непредусмотрительно бессмысленной светскою беседой.

Вам бы книги писать.


А по делу, то вам IE поддерживать надо, то не надо? Или инструмент расово неверный и религия не позволяет?

Писать бы, да времени нет. Вот работать надо, а я тут всякую фигню строчу. :)


А по делу, IE нам поддерживать надо и поддерживаем. Даже распоследняя версия фреймворка работает в IE8 и тесты проходят (большей частью). Потому что клиенты требуют, а кто платит $$, тот и прав.


А вот TypeScript нам нафиг не упал по многим разным причинам, в т.ч. по причине наличия своей системы классов, с блекджеком и всем прочим. И я пытаюсь донести простую мысль, что не надо пытаться чесать всех под одну гребёнку и уповать на панацею от абсолютно всех болячек имени доброго и бескорыстного доктора Майкрософта.


Просто ради понимания моей перспективы, представьте что всё наборот, я работаю в Microsoft и жить не могу без TypeScript. Теперь продайте мне ES6 + Flow.

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


А вот вы пишите, TS не упал. И я знаю, что вы таки знаете толк в велосипедах :) не пробовали типизацию внедрять какую-нибудь? все-таки на динамике библиотечный код так себе пишется...

Как-то вы так лихо перескочили с фразы "большинство проблем решаются с помощью TS" на "всем TS, я создал, кто не в TS, тот лох".

Ага, ну давайте в риторику тоже поиграем. :) С самого начала:


  1. Товарищ MooooM размашисто, сплеча обзывает небезызвестный фреймворк "монструозным архаизмом". Годный революционный тон, что характерно, без какой-либо аргументации (даёшь отмечание столетия!)
  2. Я выступаю и слегка язвительно парирую тем, что монструозный атавизм, на минуточку, работает и таки вполне неплохо себя чувствует. И давно уж.
  3. Товарищ MooooM невинно изумляется крамольной мысли о том, что кому-то может не хватать блистательных возможностей сиятельного ES6.
  4. Я на пальцах объясняю, что таки нет, не хватает, и таки да, вот по пунктам.
  5. Товарищ MooooM делает разворот на 180 и начинает уповать уже на TypeScript, хотя и несколько менее размашисто, чем в п.1.
  6. Я позволяю себе вежливо усомниться в весомости аргументов в пользу оного TypeScript, из которых я до сих пор слышал только дифирамбы Майкрософту и титанам мысли, решившим уже за нас, сирых и убогих, ну просто все-все-все проблемы, только нужно расписаться вот здесь. Да, кровью, а вы не в курсе что ли?

Так что нет уж, пардоньте. Это не я прыгаю. :) Я просто пытаюсь отбиваться от товарищей, назойливо тыкающих в лицо разными Авторитетными Решениями.


TS вполне себе годный инструмент (хоть это и MS) и со своими задачами справляется ну просто на ура.

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


Никто никому ничего не продает и уж тем более не гонит на святую сенчу :)

Да богов побойтесь, Сенча ни разу не святая и Ext JS полный говна кусок. Никакого другого мнения вы от меня никогда не услышите. :)


Тут только это, маленький ньюанс… (с) Всё остальное ещё хуже. Я проверял. :(


А вот вы пишите, TS не упал. И я знаю, что вы таки знаете толк в велосипедах :) не пробовали типизацию внедрять какую-нибудь? все-таки на динамике библиотечный код так себе пишется...

Не совсем понимаю спектр вопроса. Лично я пробовал, или команда Ext JS? Лично я начинал когда-то с нацистско-типизированного Паскаля, проходил огонь C и медные трубы C++, так что с идеалами статической типизации в некотором роде знаком. Правда, потом открыл для себя свет исуса прелести полностью динамической типизации, переметнулся на тёмную сторону и взад больше не смотрел. Остальные товарищи по команде тоже пороху нюхали изрядно; начальник наш вообще эксперт по Java, большой поклонник C# и адепт Microsoft по самое не балуйся.


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


Да чего далеко за примерами ходить, ребята из соседнего отдела уже года три как периодически порываются выкинуть нафиг YUI compressor и заменить его на хвалёный Google Closure compiler. Баги лезут как зелёные черти после пол-литры, аж в глазах рябит. Это мы как бы только о минификации/оптимизации ES5 говорим, да? ES6-то тоже поддерживать надо, но как это сделать, чтобы не сломать весь мир — это как раз и есть вопрос на миллион.

Я extjs в последний раз видел в третьей версии (и с тех пор больше видеть не хочу :-), но по тому, что помню, es201x + flow вполне беспроблемно туда ложится.

Я вам ничего продавать не собираюсь, просто ради исторической справедливости отмечу, что Ext JS 3 и Ext JS 6.5 (последний) — это вещи настолько разные, что похожи только названием.


Поэтому ваши впечатления, хоть и вполне заслуженные, от нынешнего состояния дел весьма оторваны.

где вы берёте годный grid с поддержкой редактирования данных, валидации ввода и data binding

Есть мнение, что грид не должен всего этого уметь. Берёте грид, помещаете в него поля ввода и всё.

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

Ну если готовое из коробки работает ровно как вам нужно — это замечательно. Но зачастую требования немного другие и допиливание такого "швейцарского ножа" под себя сравнимо по трудоёмкости с написание велосипеда.

Но зачастую требования немного другие и допиливание такого «швейцарского ножа» под себя сравнимо по трудоёмкости с написание велосипеда.

Вот! В том числе поэтому бывает сильно дешевле и быстрее купить платное и пинать саппорт (что мы с унигуем и делаем :) ) Чем возится самим с допиливанием с нуля хоть до какого-то рабочего состояния.
Есть мнение, что грид не должен всего этого уметь. Берёте грид, помещаете в него поля ввода и всё.

При всём заочном уважении, есть мнение, что мсье не знает, о чём говорит. От слова "чуть более, чем полностью". И всё.

Мисье, представьте себе, тоже разрабатывал. Так более аргументированно вы не можете ответить?

Могу, конечно. Зачем? Ваш категоричный тон и авторитетные пассы руками два сообщения назад говорят о том, что вы очевидно уверены в своём глубочайшем знании предмета и полной непогрешимости. Т.е. слушать и обмениваться опытом не горите желанием.


А членами меряться мне недосуг, извините.


Хотя если я всё же ошибся и вам действительно интересно, то могу объяснить, почему нельзя просто взять и поместить поля ввода в grid, и всё. С подробностями и путями решения проблем.

Мне, разумеется, интересно. Иначе бы не спрашивал. Моя уверенность строится не на самомнении или религии, а на анализе различных архитектур. Собственно, несколько ключевых особенностей $mol взято напрямую у ExtJS, но при этом решены основные родовые травмы подобных фреймворков. Поэтому, я думаю, $mol мог бы вам понравиться, когда нарастит побольше мяса из стандартных компонент.

Ох, господи. Ну хорошо, давайте меряться тогда уж.


Моя уверенность строится не на самомнении или религии, а на анализе различных архитектур.

А моя уверенность строится на многолетнем опыте разработки той самой Ext JS, включая практически всю поддержку accessibility: управление фокусированием, поддержку клавиатурной навигации, ARIA, экранных читалок и дисплеев Брайля, и проч. Во всех компонентах, в т.ч. grids, trees, и всём остальном. Фактически в двух разных фреймворках, которые нынче сливаются в один. Которые для поддержки этой accessibility мне пришлось очень глубоко переделывать, иначе ни черта не работало, т.к. изначально всё проектировалось для тыкания мышками или пальчиками.


И суммируя этот многолетний опыт каждодневного бития башкой в бетонную стену, я вам говорю: нельзя просто взять и поместить поля ввода в grid, и всё.


Достаточно? Дальше уже давайте конструктивно.


Так вот, начнём с design pattern. Мы с вами уважаем стандарты, поэтому возьмём за основу WAI-ARIA 1.1 Grid, даже конкретно вот эту секцию: Keyboard interaction, раздел про редактирование данных. Суммируя по-быстрому, нам нужно, чтобы:


  • Enter или F2 на ячейке включало редактирование
  • Enter в режиме редактирования подтверждал изменения
  • Esc в режиме редактирования отменял изменения
  • Tab и Shift-tab перепрыгивали к следующему/предыдущему полю редактирования, не покидая режим редактирования и сохраняя изменения при покидании ячейки

Если вы просто добавите поля ввода в ячейки grid, при этом не озаботившись обработкой событий и состояний, то grid не будет в курсе ни о начале редактирования, ни о конце. Навигация с помощью Tab тоже будет работать только до конца строки с ячейками, и только если не дай бог где-то на странице не случился элемент с tabIndex > 0. Если случился, то пиши пропало — фокус улетел и состояние сломано. Если даже ничего не пропало, то по стандарту рекомендуется заворачивать навигацию с последней ячейки последней строки на первую ячейку первой строки.


Всё это требует от grid быть в курсе, что такое редактирование данных в нём же, и даже более того: активно управлять процессом.


Далее можно упомянуть такие дружественные к разработчику штуки, как возможность определять тип виджета для редактирования ячейки (text input, text area, combo, etc), и картинка усложняется. Далее мы можем вспомнить о том, что данные нужно не просто редактировать в памяти, а ещё неплохо было бы оповещать какие-нибудь сторонние объекты о том, что редактирование записи состоялось. Для этого как минимум нужно понимать, когда у нас редактирование смещается с одной строки на другую, а ещё лучше, иметь возможность организовать транзакционный подход с атомарным подтверждением или отменой изменений. Это тоже чуточку выходит за рамки понимания отдельного поля ввода, даже очень умного. Далее мы можем вспомнить о случаях, когда набор данных не влазит в экран и нужна прокрутка по горизонтали или, ещё хуже, по вертикали с динамической подкачкой данных с сервера. И чтобы табуляция по полям редактирования работала и в этом случае тоже. И что юзеры имеют привычку начать редактировать ячейку, а потом кликнуть мышкой в другую часть страницы и фокус улетает, а это надо отрабатывать без потерь.


И это даже без учёта специфичных браузерных приколов, типа отсутствия нормальных фокусных событий в Firefox (до недавнего времени) или идиотской отработки mousedown на scrollbar в IE. И тем более без учёта возможности использовать в качестве редактора какого-нибудь HtmlEditor на базе iframe, а там с фокусными событиями отдельный многоцветный коленкор. Или вот какой-нибудь клиент решит засунуть в grid что-нибудь типа <input type="file"> и вы с ним на%@#тесь и напляшетесь в IE/Edge, потому что оно на голову больное. Или ещё 100500 таких же козырных, но вполне оправданных случаев (потому что клиенты $$ платят).


Вот берёте все эти конфликтующие требования, смешиваете, помещаете в горшочек и поливаете-удобряете несколько лет, а на выходе как раз получается что-нибудь типа Ext JS grid. С фичами, плагинами, блекджеком и шлюхами. Безумно сложно, но работает и даже вполне быстро для своих возможностей и уровня совместимости со всем, что движется.


Поэтому, я думаю, $mol мог бы вам понравиться, когда нарастит побольше мяса из стандартных компонент.

Безумству храбрых… Но вам всё же проще будет, браузеры с тех пор чуточку попрямее стали. :)

Вот, vintage, берётся, в том числе это всё, за 600$ зеленых повторить на $mol :)

Я помню, когда сам был пионером, мы в таких случаях говорили: флаг тебе в руки и барабан на шею. :)


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


Собственно, именно так и получилось с Ext JS. Автор библиотеки дорастил её до версии 3, продал инвесторам за кучу денег. Инвесторы наняли зайчиков, те наобещали с три короба с высокой сцены и поскакали лабать версию 4. До основанья всё разрушили, а затем внезапно выяснилось, что свой, новый, мир построить в сроки не удаётся. Потому что, как известно, п##деть это не мешки ворочать.


А дальше история: Ext JS 4.0 вышла печальным говна куском, а зайчикам надоело морщить лоб и они ускакали на более зелёные полянки, срывать аплодисменты восторженных фанатов.


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

А моя уверенность строится на многолетнем опыте разработки той самой Ext JS

А кроме него что пробовали?


Фактически в двух разных фреймворках, которые нынче сливаются в один.

Это что за фреймворки?


Которые для поддержки этой accessibility мне пришлось очень глубоко переделывать

Эх, вашу бы самоотдачу, да нормальному фреймворку..


Мы с вами уважаем стандарты, поэтому возьмём за основу WAI-ARIA 1.1 Grid, даже конкретно вот эту секцию: Keyboard interaction

Только полезные. Конкретно этот я не считаю полезным, ибо слишком ограничивает возможные решения одним конкретным. Давайте попробуем сами запроектировать поведение...


Enter или F2 на ячейке включало редактирование
Enter в режиме редактирования подтверждал изменения
Esc в режиме редактирования отменял изменения

Я бы сделал, что при фокусе сразу включается редактирование.


Tab и Shift-tab перепрыгивали к следующему/предыдущему полю редактирования, не покидая режим редактирования и сохраняя изменения при покидании ячейки

Это стандартное поведение, работающее и вне гридов. Хотя оно и не очень удобное. Мне нравится подход Оперы, где ctrl+стрелка переносят фокус на ближайший контрол в соответствующем направлении.


Далее можно упомянуть такие дружественные к разработчику штуки, как возможность определять тип виджета для редактирования ячейки (text input, text area, combo, etc)

Какие виджеты помечтил — такие и будут. Может хоть несколько виджетов в одну ячейку помечтить и всё будет работать, так как логика эта не будет привязаня ко гриду.


неплохо было бы оповещать какие-нибудь сторонние объекты о том, что редактирование записи состоялось.

Для этого есть реактивное программирование, которое в ExtJS не завезли.


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

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


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

Обычный ленивый рендеринг, реализованный в гриде.


отсутствия нормальных фокусных событий в Firefox

Да там небольшой воркэраунд с useCapture нужен и всё.


идиотской отработки mousedown на scrollbar в IE.

Речь про перенос фокуса? Ну это не страшно.


И тем более без учёта возможности использовать в качестве редактора какого-нибудь HtmlEditor на базе iframe

Да нафиг оно такое надо :-) У нас будет нормальный встраиваемый богатый редактор.


Или вот какой-нибудь клиент решит засунуть в grid что-нибудь типа и вы с ним на%@#тесь и напляшетесь в IE/Edge, потому что оно на голову больное.

Что там с ним не так?


Вот берёте все эти конфликтующие требования, смешиваете, помещаете в горшочек и поливаете-удобряете несколько лет

Единоразовая задача на не более чем месяц.


а на выходе как раз получается что-нибудь типа Ext JS grid.

Нет, на выходе получится набор из нескольких кирпичиков, из которых можно складывать куда более сложные интерфейсы, чем "стандартная таблица".

А кроме него что пробовали?

Мы тут с вами в испанскую инквизицию играем, я посмотрю? Нет, $mol не пробовал.


Эх, вашу бы самоотдачу, да нормальному фреймворку..

Это легко. Контора возьмёт $350 в час или около того, но вы обращайтесь напрямую, сделаю небольшую скидку. :)


Мы с вами уважаем стандарты
Только полезные.

Как удобно! Чёрт, а я-то, старый дурак, и не догадался! Столько времени впустую потратил!


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

Попробуйте :-) Там много оригинальных решений, которые можно было бы стащить в ExtJS. А то и вообще так понравится, что подкините Сенче идею запилить ExtTS1 на новых шустрых, компактных и гибких рельсах. Сейчас $mol разрабатывают полтора землекопа в свободное от остальных задач время. Вливание хотя бы миллиона на маркетинг и наращивание функционала было бы очень кстати.

Молодой человек, вы всё ещё здесь? Не тратьте своё драгоценное время на обсуждение монструозных атавизмов, лучше взгляните в окно — там выстроилась очередь из инвесторов, все жаждут занести свои неправедно нажитые доллары к вам в маркетинг и функционал.


Если поторопитесь, то ещё успеете на вечернюю электричку в Долину; когда приедете, заходите в гости, я вам грамоту вручу. У меня тут специально заготовлена, для Героев Стартапа Второй Степени. Первая пока закончилась, но это всё равно для тех, кто уже на IPO вышел — через недельку обещали дослать тираж, даже с вашими темпами не должны опоздать.

Может вы найдёте более полезный способ самоутверждения, чем хамство незнакомым вам людям?

Вопрос разрабатывавшему: вы, если что, возьметесь запилить за 600 бакинских на ангуляре аналог унигуевских дбгридов, дб деревьев и чартов (хотя бы)? Нужен фронт + бэк. Язык бэка на выбор.

На Ангуляре — нет. А на $mol — вполне. Как раз за вчера сделал кроссплатформенное приложение, которое берёт OLAP куб, строит по ним табличку/графики с возможностью фильтрации по размерностям из этого куба.

Ок, буду иметь в виду, мало ли :)

Когда я только пришел во фронтенд, я начинал на проекте с ExtJS. C ним все гладко и прекрасно ровно до того момента, пока устраивают дефолтные настройки. Если хочется какого-то нестандартного поведения, для которого у разработчиков не предусмотрен готовый флаг, то придется перелопатить очень много кода, чтобы найти что где переопределяется.


То же самое и со стилями. Как только потребуется перекрасить стандартные синие окошки во что-либо другое, начинается ад. Об этом я даже в 2011 году написал статью.


После того, как я познакомился с Grunt, Webpack и современным фронтенд-стеком в целом, обратно меня уже никакими рассказами про "на порядок более богатые" классы не заманить.

Если хочется какого-то нестандартного поведения, для которого у разработчиков не предусмотрен готовый флаг, то придется перелопатить очень много кода, чтобы найти что где переопределяется.

Но ведь, что интересно, удавалось же? Я помню, как примерно в те же года пытался разобраться в Dojo. Вот уж где спагетти было жестокое. После него Ext JS 4 при всей своей лютой, бешеной глючности казался всё же глотком свежего воздуха.


Об этом я даже в 2011 году написал статью.

С тех пор чуток воды утекло. Вы считаете нормальным сравнивать фреймворк 6-летней давности с современными решениями?


После того, как я познакомился с Grunt, Webpack и современным фронтенд-стеком в целом, обратно меня уже никакими рассказами про "на порядок более богатые" классы не заманить.

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


Сейчас как раз пытаюсь потихоньку выбрать, на чём делать новый личный проект. Ext JS использовать очень не хочется по личным причинам, но всё остальное даже рядом не валялось. Хоть всё бросай и начинай свой фреймворк, с блекджеком и прочими штуками...

Но ведь, что интересно, удавалось же?

Манкипатчингом можно и в JS заниматься, но я не считаю это поводом для гордости. В современных UI-либах (в крайнем проекте использовал react-toolbox) просто нет необходимости где-то там патчить.


С тех пор чуток воды утекло. Вы считаете нормальным сравнивать фреймворк 6-летней давности с современными решениями?

Я слежу периодически за обновлениями компании Sencha. Вот у них и React-компоненты появились, тренд понятно куда ведет.


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

Это Sencha CMD хороший инструмент? Вы серьезно?

Манкипатчингом можно и в JS заниматься, но я не считаю это поводом для гордости.

Я не monkey patching имел в виду, а читабельность кода. Когда что-то не получается или не знаешь, как сделать, весьма ценно бывает залезть в исходники фреймворка и посмотреть, как сделано то или это. Частенько и находишь, какую настройку подвинтить.


Ext JS далеко не идеален, но даже в 2011 читался существенно лучше, чем многие конкуренты по цеху. А с тех пор чуть-чуть улучшился. :)


В современных UI-либах (в крайнем проекте использовал react-toolbox) просто нет необходимости где-то там патчить.

Багов в них тоже нет, чтобы не было необходимости патчить?


Я слежу периодически за обновлениями компании Sencha. Вот у них и React-компоненты появились, тренд понятно куда ведет.

Это как раз попытка выехать на тренде и заработать денег.


Это Sencha CMD хороший инструмент? Вы серьезно?

Я Ext JS имел в виду. Сам не большой фанат Cmd, но этот инструмент тоже легко недооценить. С первого взгляда это кривая и архаичная поделка для склеивания JavaScript файлов, но на самом деле Cmd умеет очень много разных интересных штук. Например, запускать тестовые сессии через WebDriver, с параллелизацией, очерёдностью, сбором статистики, свистелкам и перделками. ~500,000 юнит-тестов за полчаса, и так на каждый pull request. Просто для справки. :)

Я не monkey patching имел в виду, а читабельность кода.

Так или иначе, но возможность переопределить метод у Ext.panel.Panel чтобы show делал совсем не show называется манкипатчингом, каким бы читаемым он не был.


Багов в них тоже нет, чтобы не было необходимости патчить?

Можно прислать pull-request с фиксом и получить новый релиз в течение 1-2 недель, а не ждать релиза ExtJS раз в квартал. Кстати, а как правильно обновлять версии ExtJS? Из npm его не скачать, в package.json не прописать.


но на самом деле Cmd умеет очень много разных интересных штук

ничего такого, что нельзя сделать на классическом стеке с Webpack, Mocha, Jest и т.п.


Но Sencha Cmd нельзя поставить командой npm install sencha-cmd, что сразу ставит на нем жирный минус.

Так или иначе, но возможность переопределить метод у Ext.panel.Panel чтобы show делал совсем не show называется манкипатчингом, каким бы читаемым он не был.

Переопределение существующих классов это monkey patching, не спорю. Но вместо этого вы можете создать свой класс Foo.panel.Panel, унаследовать его от Ext.panel.Panel и переопределить метод show в своём классе. А это уже классическое ООП.


Можно прислать pull-request с фиксом и получить новый релиз в течение 1-2 недель,

Правда? https://github.com/angular/angular: 1,699 issues, 249 pull requests. Дальше смотреть лениво.


Кстати, а как правильно обновлять версии ExtJS?

Cmd и это тоже за вас умеет.


ничего такого, что нельзя сделать на классическом стеке с Webpack, Mocha, Jest и т.п.

Мне очень интересно было бы посмотреть на этот классический стек, который из коробки умеет масштабироваться до полумиллиона юнит-тестов за один прогон. Что-то (многолетний опыт?) мне подсказывает, что не всё тут так радужно, как вам кажется.


Скажем, Mocha я глубоко не копал, а вот Jasmine пришлось переписать практически с нуля. Дважды. Первый раз, чтобы убить титанически мохнатых багов, которые Pivotal фиксить отказались, а второй раз, чтобы стало бегать в разы быстрее. Это к вопросу о качестве модно-хайповых решений.


Но Sencha Cmd нельзя поставить командой npm install sencha-cmd, что сразу ставит на нем жирный минус.

Конечно, всё должно быть модно-молодёжное на npm и Node.js. Если не на Node.js, то автоматически хлам и говно.


Внимание, вопрос: когда завтра появится какой-нибудь "Node killer" и вся ваша инфраструктура в одночасье превратится в хламчинскую тыкву, вы тут же бросите всё и ломанётесь переделывать ради бытия в тренде? А что? Все побежали и я побежал! ©

Кстати, а как правильно обновлять версии ExtJS?
Cmd и это тоже за вас умеет.

А откуда он качает новую версию? В любом случае получается какой-то велосипед вместо NPM.


а вот Jasmine пришлось переписать практически с нуля. Дважды. Первый раз, чтобы убить титанически мохнатых багов, которые Pivotal фиксить отказались

Ссылки сможете показать? Очень интересно посмотреть, без сарказма.


Конечно, всё должно быть модно-молодёжное на npm и Node.js. Если не на Node.js, то автоматически хлам и говно.

Если вы пишете на Javascript, то писать сборку не на Node.js будет странно. То же самое и с NPM, стандартный репозиторий пакетов, логично использовать именно его, а не свой велосипед.


Внимание, вопрос: когда завтра появится какой-нибудь "Node killer"

Node.js это рантайм. Он по определению подчиняется стандартам языка. Поэтому гипотетический Node killer будет более-менее совместим с текущей экосистемой.

А откуда он качает новую версию?

Из репозитория Sencha, конечно.


В любом случае получается какой-то велосипед вместо NPM.

Безусловно. Как вы представляете себе распространение коммерческих продуктов через NPM?


Ссылки сможете показать? Очень интересно посмотреть, без сарказма.

Если интересно и без сарказма, то могу не только показать, но и многое рассказать. Мы на базе Jasmine сделали мощнейший QA инструмент, и кроме собственно юнит- и интеграционных тестов проверяем код на утечки памяти, таймеров, Ajax запросов и т.д. Гайки зажимаем, насколько можем дотянуться. Давно уже подумываю статью про это дело написать, но со временем совсем швах.


К сожалению, в публичной версии Ext JS этой сборки Jasmine пока нет, но есть в коммерческой. Пробную версию Ext JS можно взять здесь: https://www.sencha.com/products/extjs/evaluate/. Можете ввести какой-нибудь левый, но работающий, e-mail адрес, и потом скачать по ссылке. А дальше открывайте ext/test/lib/jasmine.js.


Если вы пишете на Javascript, то писать сборку не на Node.js будет странно.

Абсолютно ничего странного, если вы пишете на JavaScript только клиентскую сторону. А с серверной стороны у вас могут быть какие угодно инструменты, и Node/NPM как раз будут казаться ортогональными и неестественными.


Поэтому гипотетический Node killer будет более-менее совместим с текущей экосистемой.

Это до тех пор, пока какой-нибудь очередной амбициозный пионер не решит заделаться потрясателем ослов основ. А случается это с завидной регулярностью; как говорят буддисты, единственное постоянство — это изменения.

Вы говорите, что нашли баги, которые Pivotal фиксить отказались. А ссылки на баг-репорт с ответом про won't fix показать можете?

Вот один, самый зверский. Если мне память не изменяет, то проблема была в некорректной отработке выхода из waitsFor по таймауту, что приводило к неисполнению блоков afterEach. Ну, и понятным последствиям для всех последующих тестов.


Там ещё много чего было, но смысла открывать PR уже не было.

Конечно смысла не было. Надо на Jasmine 2 обновляться, а не пинать труп 1й версии.


Насколько я понял, у вас какая-то странная жутко энтерпрайзная система с очень большим и старым проектом. 20000 тестов это большая цифра, интересно, как это вообще разрабатывается, и сколько человек это делают.


Может быть, ExtJS там и неплохо смотрится, таких больших проектов я не видел, к счастью

Конечно смысла не было. Надо на Jasmine 2 обновляться, а не пинать труп 1й версии.

Ваш безграничный оптимизм меня умиляет. Ради мысленного эксперимента попробуйте представить себе масштаб изменений при переходе с псевдо-синхронного API на полностью асинхронное без гарантий выполнения блоков. Теперь шагните чуть дальше и попробуйте представить масштаб трудозатрат на такие изменения. Потом умножьте на 3, потому что проблемы обязательно вылезут.


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


Если найдёте, поделитесь пожалуйста. Я не нашёл. Проще было переписать Jasmine, чтобы добавить поддержку их нового API, не теряя старого. Ну и багов вычистить заодно.


Насколько я понял, у вас какая-то странная жутко энтерпрайзная система с очень большим и старым проектом.

Наш проект это Ext JS. :) Большой, старый. Сам фреймворк ещё ничего по сравнению с приложениями, которые на нём построены.


20000 тестов это большая цифра, интересно, как это вообще разрабатывается, и сколько человек это делают.

20k тестов было 3 года назад, текущая цифра ~66,500. Всё это добро прогоняется в 10+ браузерах, что даёт в сумме ~500,000 тестов за каждый прогон PR; в ночных сборках больше. Разрабатывается руками и головой, ничего принципиально нового. В основной команде 10 человек, включая меня.


Может быть, ExtJS там и неплохо смотрится, таких больших проектов я не видел, к счастью

Самый большой, что я видел своими глазами, состоит из примерно ~5,000,000 строк и компилируется в скрипт примерно 30 mb объёмом. Ничего, работает даже в IE8.


Ребята из services хвастались, что бывает и больше.

Если вы работаете над самим ExtJS то ваша позиция становится понятнее.


Полистал официальный сайт, нашел примеры: http://examples.sencha.com/extjs/6.5.1/examples
А где можно посмотреть их исходники? Вдруг 6я версия действительно стала лучше.

Если вы работаете над самим ExtJS то ваша позиция становится понятнее.

А вот мне не очень понятно, почему моя позиция становится понятнее. Если бы я работал не над фреймворком, а над странной жутко энтерпрайзной системой, что именно изменилось бы? Переписывать 20 тысяч тестов на несовместимое API внезапно стало бы проще? Вопросы обратной совместимости и нежелания отдельных вендоров поддерживать свои продукты стали бы менее острыми?


Любой софт стоит денег, а бесплатный ещё бОльших. Linux is free if your time costs nothing. ©


А где можно посмотреть их исходники?

Исходники всех примеров идут вместе с фреймворком, так же как исходники юнит тестов, Jasmine с обвязкой, и т.д. Я выше давал ссылку на страницу, где можно скачать пробную версию. К сожалению, более прямых ссылок у меня нет.

Меньше слушайте школоту, вы делаете отличные вещи!!!
Исходники всех примеров идут вместе с фреймворком, так же как исходники юнит тестов, Jasmine с обвязкой, и т.д

Можно сколько угодно пинать NPM модность и молодежность, но это реально удобный способ получения библиотек и кода.


Если бы ExtJS (GPL версия) была бы доступна в NPM, а примеры кода — на Github, то куча вопросов бы сразу отпала. Я бы ответил себе на них самостоятельно. А так — ExtJS выглядит типичная энтерпрайз система, с намеренно завышенным порогом вхождения, чтобы непосвященные не догадались, что здесь вообще происходит. Желание копаться в бесконечных ссылках на официальном сайте пропадает окончательно.

Можно сколько угодно пинать NPM модность и молодежность, но это реально удобный способ получения библиотек и кода.

Это удобный вам способ. Java разработчики смотрят на вас недоумённо, у них есть Maven и кому нужно что-то ещё? C# разработчики смотрят на вас исподлобья, у них есть NuGet Gallery. У Python есть PyPI, у Perl есть CPAN, у Ruby есть RubyForge, и так далее ad nauseam.


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


А так — ExtJS выглядит типичная энтерпрайз система,

Ext JS и есть типично энтерпрайз система, никаких сюрпризов.


с намеренно завышенным порогом вхождения, чтобы непосвященные не догадались, что здесь вообще происходит.

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


Именно для этого существуют демо на сайте, в которых показывают код и разметку, zip-файлы с фреймворком, которые можно распаковать и поиграться, инструменты, генерирующие скелет приложения, и т.д.


Другое дело, что всем не угодишь и сложный продукт невозможно сделать простым для всех. Тут надо соблюдать баланс между необходимой простотой вхождения и достаточной демонстрацией возможностей, чтобы заинтересовать потенциального покупателя. Ресурсы тоже небесконечные, зачем тратить время и деньги компании на капризных непокупателей, которые попинают шины и уйдут, т.к. покупать и не собирались?


На эту тему вспоминается забавный диалог, который я видел в каком-то бложике. Автор решил попробовать IBM Informix IDS, скачал пробную версию, набил шишек и обиженно насупился: мол, кроваво-энтерпрайзная система стоимостью $60k за лицензию, а нормальный инсталлятор сделать не могут! Какие-то ещё конфиги надо создавать да переменные среды настраивать, ерунда какая!


На что был интересный комментарий в духе: если компания рассматривает покупку софта стоимостью $60,000 за лицензию, то наверное они могут себе позволить почитать README?


Желание копаться в бесконечных ссылках на официальном сайте пропадает окончательно.

Я думал, вам интересно посмотреть детали нашей реализации Jasmine? Ради этого можно и покопаться, а пользоваться Ext JS я вас не призывал и не буду. Если вам надо строить сложные Line of Business приложения для web, то вы сами к нам придёте, а для других задач есть другие инструменты.

Спасибо. Я уже посмотрел ваш профиль на гитхабе и понял, что вы работаете в Sencha.
Что объясняет все написанное далее в ветке дискуссии.

Мне кажется, вы сейчас неправильные выводы сделали, поместив меня в коробочку "фанат Ext JS, потому что работает в Sencha".


Нет, не фанат, я работаю в Sencha не за идею, а за хорошие деньги. И защищал не Ext JS, а прагматичный подход к выбору инструментария для разработки: если отбросить хайп и шелуху, а смотреть на выгоду и затраты от использования той или иной системы, то картинка перестаёт быть простой и чёрно-белой. ES6 хорошо, доморощенная классовая система плохо. Так? С моей точки зрения, не совсем и не всегда. Тем более, что никто не отказывался поддерживать ES6, но сделать это, не сломав многомиллионный существующий код, не так-то просто.

Вопрос: после покупки Сенчи что-то изменилось? Может слышали про какие-то планы Идеры?

Извините, публично комментировать не могу.

Ок, не вопрос.
Ну вот видите. И вы способны вести спокойную, аргументированную беседу без хамства.

На самом деле, если так заострять внимание на классах ES6 — в моем опыте не было случаев когда их функционала не хватало. При всей любви к ООП — не все его фичи так уж востребованны, тем более на фронтенде.

Чем Ext действительно всегда был лучше других — богатая библиотека очень мощных компонентов, такой же нет и не будет ни у одного фреймворка. Но в реальности, даже самым навороченным CRM оттуда кроме основных гридов/деревьев и форм особо ничего больше и не нужно. А купить можно только все целиком. И дорого.

Про тулсет уже писали. Не считаю Sencha CMD хорошей вещью, по той простой причине, что как и все в ExtJS она сделала только для ExtJS.

Собственно тут и есть основной его недостаток — все самописное. Собственные классы были киллер-фичей в далекие времена бесплатного ExtJS 3. Сейчас же большая часть подобных ExtJS решений доступны в вебе и так. ES6 в Хроме есть даже нативно.

И TypeScript — да это превосходный (хоть и не идеальный) язык. Он не раз спасал нашу команду от ночей поиска странных ошибок. Он значительно снизил количество необходимых юнит тестов. И да, там есть классы, со статическими полями и тд.

Спорить о том, что ExtJS делает больше — бессмысленно, это очевидно так. В реальности же, при написании приложения на ExtJS вы пишете ExtJS, а не JS.
Все постоянно ругают Angular за то что вы должны его изучать, чтобы разрабатывать на нем (вс Реакт где вы пишете JS). Но в этом плане ExtJS — это вообще практически свой язык.

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

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

Ну и конечно привязка к исключительно платным компонентам и невозможность их опенсорсно поддерживать, лично в нашем случае, делает невозможным использование ExtJS.
Ну вот видите. И вы способны вести спокойную, аргументированную беседу без хамства.

Конечно же могу. Да и вы тоже, как выяснилось, можете приводить аргументы вместо размахивания лозунгами.


На самом деле, если так заострять внимание на классах ES6 — в моем опыте не было случаев когда их функционала не хватало. При всей любви к ООП — не все его фичи так уж востребованны, тем более на фронтенде.

Классы ES6 это, в сущности, тонкая обёртка над существующим прототипным ООП в JavaScript. Классовая система Ext JS это реализация классического ООП а-ля Java на базе прототипного, со многими расширениями и дополнениями. Если прототипное ООП вам по душе и вы его понимаете, то вполне возможно, что классы ES6 будут вам достаточны. Если же ваш опыт уходит корнями в более классические системы, то ES6 будет вызывать скорее недоумение своей бедностью и отсутствием даже базовых вещей. Вам, как адепту TypeScript, такая дихотомия должна быть понятна.


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

Далеко не только компонентов. Механизмы обработки данных, data binding, MVC/MVVM, транспортные механизмы, RPC, и т.д.


Но в реальности, даже самым навороченным CRM оттуда кроме основных гридов/деревьев и форм особо ничего больше и не нужно. А купить можно только все целиком. И дорого.

В вашей реальности, может быть — это просто означает, что у вас нет задач, для которых Ext JS подходит лучше всего. В реальности наших клиентов всё чуточку наоборот. Насчёт дороговизны я даже спорить не буду, $1k за разработчика это дорого? Даже не смешно.


Про тулсет уже писали. Не считаю Sencha CMD хорошей вещью, по той простой причине, что как и все в ExtJS она сделала только для ExtJS.

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


Собственно тут и есть основной его недостаток — все самописное.

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


Собственные классы были киллер-фичей в далекие времена бесплатного ExtJS 3. Сейчас же большая часть подобных ExtJS решений доступны в вебе и так.

Подобных, но не эквивалентных. И всё это разбросано по кучке разных мелких решений, которые вам надо будет собирать в кучу. Вы когда-нибудь пытались оценивать время, которое нужно для управления всем этим зоопарком?


ES6 в Хроме есть даже нативно.

В Chrome есть. В Safari есть с последней версии, которая ещё далеко не у всех. В IE11 нет, а этот браузер является стандартом для гигантского количества организаций по всему миру, и будет ещё долго. У нас есть очень крупные клиенты, которые до сих пор используют IE7. И да, платят кучу денег за исправление проблем в Ext JS 4.x, которая поддерживает IE6+.


И TypeScript — да это превосходный (хоть и не идеальный) язык. Он не раз спасал нашу команду от ночей поиска странных ошибок. Он значительно снизил количество необходимых юнит тестов. И да, там есть классы, со статическими полями и тд.

Про юнит-тесты вы меня уже второй раз улыбаете. Извините, но если статическая типизация помогает избавиться от части юнит-тестов, то вы пишете неправильные тесты.


TypeScript это вещь в себе, и слишком всеобъемлющая. Либо вы всё делаете в TypeScript, либо у вас будет постоянная острая боль в нижней части спины. Мы как вендор не можем себе позволить стать причиной этой самой боли у наших клиентов.


Ещё раз, с другого угла: Angular могли себе позволить делать что угодно и перешли на TypeScript, потому что им наплевать на пользователей фреймворка. С высокой колокольни. Команде Angular зарплату платит Google, а не пользователи. Google с их ресурсами вообще всё равно, взлетит Angular или утонет, с их точки зрения это мелочь в складке кармана.


У нас ситуация обратная: Ext JS это коммерческий продукт, и при этом основной продукт компании. Мы не можем делать резкие телодвижения, т.к. это приведёт к потере денег. Когда появился TypeScript, мы проводили опросы среди клиентов, и интерес оказался низким. На этом история закончилась.


Спорить о том, что ExtJS делает больше — бессмысленно, это очевидно так. В реальности же, при написании приложения на ExtJS вы пишете ExtJS, а не JS.
Все постоянно ругают Angular за то что вы должны его изучать, чтобы разрабатывать на нем (вс Реакт где вы пишете JS). Но в этом плане ExtJS — это вообще практически свой язык.

Извините, но тут я категорически не согласен. Да, у Ext JS есть своя классовая система, и именно она является основанием для всего остального. С ней вполне легко работать, и долгого изучения она не требует. В остальном же весь код это чистый ES5 JavaScript. У нас даже поддержки транспиляторов до недавних пор не было, за отсутствием необходимости. Никаких DSL у нас нет и не было, кроме шаблонизатора конечно же.


Другое дело, что разработка на Ext JS со стороны может выглядеть, как использование своего собственного языка — просто потому, что основная разработка сводится к соединению и конфигурированию компонентов. Ну так именно это и является достоинством: коробка с кучей кубиков, которые вы складываете, как вам надо.


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

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


Под портативностью кода вы имеете в виду запуск на других платформах? Cordova и Electron поддерживаются из коробки. Про Rollup не в курсе, дискутировать не могу.


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

Насчёт стилизации позволю себе не согласиться — куча тем, в т.ч. страшно модная Material, чем вас не устраивает? Плюс практически все темы можно конфигурировать как угодно, всё на SASS.


По поводу мобильной разработки тоже дискутировать не буду, мне эта тема мало интересна.


Ну и конечно привязка к исключительно платным компонентам и невозможность их опенсорсно поддерживать, лично в нашем случае, делает невозможным использование ExtJS.

В вашем случае невозможность использования Ext JS проистекает из отсутствия задач, которые этот фреймворк решает. Я не собираюсь вам его продавать, даже наоборот, порекомендую не связываться, т.к. шишек набьёте, а толку будет мало.


Про open source поддержку вы меня опять улыбаете. Знаете, почему у нас её нет? Потому что качество патчей откровенно дерьмовое, а время на просмотр и оценку тратить нужно гигантское.

Если прототипное ООП вам по душе и вы его понимаете, то вполне возможно, что классы ES6 будут вам достаточны

Расскажите мне, пожалуйста, чем отличаются для программиста классические классы и прототипные? Вот в ТайпСкрипте — обертка над прототипа, а в Джаве — классические. Какая разница для программиста?

Я недостаточно хорошо знаю TypeScript и Java, чтобы сравнивать их напрямую. Насколько я понимаю, TypeScript реализует систему классов, более классическую и близкую к Java (точнее, к C#), чем ES6 и тем более до-ES6 JavaScript.


Вполне допускаю, что программисту, привыкшему к классическому ООП, TypeScript может прийтись по душе. В этом и есть основной смысл TypeScript, разве не так?


Другое дело, что TypeScript требует погружения по самую маковку и других вариантов нет. Если вам этот вариант нравится, вперёд. Многих он не устраивает по разным причинам, а использовать классовую систему TypeScript без самого TypeScript несколько затруднительно.


Что касается разницы классического ООП и прототипного, то тут уж я не буду читать вам лекцию, извините. Такие азы должны сами понимать.

ТС на самом деле ближе к Джаве, чем к ДоДиез, но еще он ближе к Го (правда, Он сильнее похож на Го, чем на Джаву)


Я разбираюсь в азах и даже немного больше и тем не менее интересно чем для программиста оно все будет отличаться? Статическая против утиной типизации? Наличием модификаторов доступа? Возможностью изменять прототип?


Первых два реализуются и в жсдок с ес6, а последний используется крайне редко. Вы вот говорите, что в ЕксЖС классах ближе к классическому. Чем ближе? И чем они отличаются для программиста кроме внутренней механики?

Вы вот говорите, что в ЕксЖС классах ближе к классическому. Чем ближе? И чем они отличаются для программиста кроме внутренней механики?

Использованием. Сравним с до-ES6 прототипным ООП: классы Ext JS можно наследовать, расширять с помощью интерфейсов (mixins), изменять с помощью overrides, у них есть конструктор и деструктор, статические свойства и методы класса, наследуемые статические свойства и методы, поддержка singletons, система конфигурирования с агрегированием наследованной конфигурации, интроспекцией и автоматическими getter/setter/applier/updater, возможности вклиниться в процесс создания класса на различных этапах через hooks, и ещё многие другие возможности, которые я навскидку просто не вспомню.


Отслеживание и загрузку зависимостей обеспечивает динамический загрузчик, который работает из коробки как в dev, так и в prod режимах. Зависимости отслеживаются не только явные (прописанные в коде), но и неявные (используемые) тоже, при использовании сборщика. Инструментарий дошёл уже до того, что в последних версиях зависимости прописывать явно уже нет необходимости, всё само определяется. Это несколько удобнее для прикладника, чем поддержка простыней import {}, даже если они генерируются автоматически.


Экземпляры объектов можно создавать как через стандартный оператор new, так и с помощью различных вспомогательных методов, с динамической подгрузкой. Это даёт возможность не зашивать названия классов в коде, а использовать объекты JSON с конфигурацией виджетов и чего угодно, которые скармливаются методу-конструктору и на выходе получается полное дерево UI виджетов со своими ViewModel и ViewConstructor, подписанными на нужные события и пр.


Грамотно спроектированное приложение может состоять из набора абстрактных классов, реализующих бизнес-логику, и набора конфигураций для создания UI на базе этой логики. Незаменимо для крупных приложений, где нужно разрабатывать много экранов и этой задачей могут заниматься юниоры или даже дизайнеры, используя визуальные инструменты типа Sencha Architect.


Экземпляры объектов тоже можно патчить через override(), бывает полезно для решения определённых задач. В методах можно вызывать родительский метод просто через this.callParent() и это поддерживается и в mixins, и в overrides, и вообще везде. Т.е. вам как прикладнику не нужно думать о том, что именно за метод будет вызван и из какого класса, mixin, или override.


Честно говоря, я уже устал писать, а перечислил только малую часть того, что умеет фреймворк и что может пригодиться прикладным программистам именно для разработки приложений. Ещё раз повторюсь: эта классовая система была создана задолго до ES6, где-то в 2010 или 2011, и кода на её основе написано очень много. Теперь попробуйте сравнить все эти возможности с ES6, стандартизованным в 2015, и вам станет грустно. Мне грустно.

Ну вы мне перечислили скорее фичи ЕксЖС в сравнении с ЕС5, а не разницу в прототипном и классическом подходах.

Я в своей классовой системе тоже делал миксины и callParent, а потом полностью отказался от миксинов, т.к. смысла в них особо не нашел — они портили архитектуру, осложняли отладку и оказалось лучше заменить их на делегаю, а callParent оказался ужасно портящим стек трейс и слишком медленным (реально, слегка иная реализация убрала 15% оверхед).

Да, в ес6 большинства названных фич еще нету, но вот уже в ес7, куда можно скомпилировать с бабеля уже есть практически все и даже больше.

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

Но, мне кажется, вы должны понимать, что это придется сделать в среднесрочной перспективе. У вас есть план на эту тему?
Ну вы мне перечислили скорее фичи ЕксЖС в сравнении с ЕС5, а не разницу в прототипном и классическом подходах.

Я перечислил фичи классовой системы Ext JS, которые напрочь отсутствуют в ES5 и которые как раз и являются отличием от прототипного ООП, вообще не имевшего понятия классов в ES5.


Я в своей классовой системе тоже делал миксины и callParent, а потом полностью отказался от миксинов,

У нас mixins используются в основном для кросс-использования между Classic и Modern toolkits. Которые по факту два отдельных фреймворка, бывшие Ext JS и Sencha Touch соответственно. Совершенно разные жизненные циклы компонентов и разные подходы к манипуляции DOM, но многие части кода достаточно похожи, чтобы использовать там и здесь. Поэтому без mixins никуда.


а callParent оказался ужасно портящим стек трейс и слишком медленным (реально, слегка иная реализация убрала 15% оверхед).

Для нас это не проблема, т.к. callParent используется только в dev режиме. В боевой сборке всё это подменяется на прямые вызовы методов в нужных объектах, так что никаких дополнительных расходов нет.


Да, в ес6 большинства названных фич еще нету, но вот уже в ес7, куда можно скомпилировать с бабеля уже есть практически все и даже больше.

Сравните: у нас всё это есть и уже давно, в ES7 только-только появляется и не всё, и когда оно будет в реальных браузерах… Кто знает. Закладываться на чужой транспилятор как основной инструмент обеспечения совместимости очень стрёмно, если говорить честно, особенно для коммерческой организации.


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

Отлично, спасибо огромное. :) Получается, что я достиг своей цели и показал, что "монструозные атавизмы" имеют под собой веские основания.


Но, мне кажется, вы должны понимать, что это придется сделать в среднесрочной перспективе. У вас есть план на эту тему?

Есть. Точнее, был. Новые владельцы компании уволили всю инженерную команду, кроме пары человек, и что будет дальше, непонятно. Скорее всего, ничего хорошего.


Всё вышенаписанное можно считать бесполезной грустью и ностальгией. ;(

и ещё многие другие возможности, которые я навскидку просто не вспомню.

Вы перечислили гораздо больше возможностей, чем есть в "классическом ооп", где никаких примесей, АОП и динамической подгрузки нет. ES6 — вполне "классический ооп".


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

Вот, кстати, у нас в $mol как раз именно так. Только никакой динамической подгрузки классов нет в принципе, ибо загрузить сразу бандл оказывается быстрее, чем делать каскадные запросы за зависимостями.


Это даёт возможность не зашивать названия классов в коде, а использовать объекты JSON с конфигурацией виджетов и чего угодно, которые скармливаются методу-конструктору и на выходе получается полное дерево UI виджетов

Вот эта херня, кстати, дико вымораживает, что в ExtJS, что в SAPUI5. Тебе нужен экземпляр определённого класса, а приходится в json указывать какую-то левую строковую константу, которую ещё найти надо.


В методах можно вызывать родительский метод просто через this.callParent()

Надо ли говорить, что подобный хак сказывается на производительности не лучшим образом? Уж лучше нативный super.myMethod()

Вы перечислили гораздо больше возможностей, чем есть в "классическом ооп", где никаких примесей, АОП и динамической подгрузки нет.

Смотря какую реализацию брать за классическую. Mixins подобны интерфейсам, они есть уже давно в Java и C#, да везде на самом деле. Monkey patching активно используется, скажем, в Ruby. Динамическая загрузка пакетов/классов есть много где.


Только никакой динамической подгрузки классов нет в принципе, ибо загрузить сразу бандл оказывается быстрее, чем делать каскадные запросы за зависимостями.

Это пока у вас бандлы не перевалят за мегабайт. В Ext JS на сей момент уже 2100+ классов, полная сборка classic toolkit весит 10 мб, modern toolkit уже 4 мб.


Тебе нужен экземпляр определённого класса, а приходится в json указывать какую-то левую строковую константу, которую ещё найти надо.

Про SAPUI5 не скажу, а в Ext JS можно вместо xtype использовать xclass и указывать именно тот класс, который вам и нужен. Работает точно так же динамически.


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

Никак не сказывается. В боевой сборке все вызовы callParent заменяются на прямые вызовы методов на нужных объектах, вызовы Ext.define() заменяются на более прямолинейный и быстрые механизмы и т.д. Очень удобно иметь динамический callParent() при разработке, но в боевой сборке это всё уже не нужно.


Уж лучше нативный super.myMethod()

Там, где он есть нативно, лучше. А там, где нет? Всё равно эмулировать так или иначе.

Mixins подобны интерфейсам

Интерфейсы не тянут с собой реализацию. Примести — это множественное наследование. А его стараются избегать при разработке языков.


Это пока у вас бандлы не перевалят за мегабайт.

Не перевалят. У нас очень компактный код и мы не пихаем в бандл лишнего.


можно вместо xtype использовать xclass и указывать именно тот класс, который вам и нужен.

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


В боевой сборке все вызовы callParent заменяются на прямые вызовы методов на нужных объектах, вызовы Ext.define() заменяются на более прямолинейный и быстрые механизмы и т.д.

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

Интерфейсы не тянут с собой реализацию.

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


Не перевалят. У нас очень компактный код и мы не пихаем в бандл лишнего.

Вы опять сравниваете тёплое с мягким. Ваш фреймворк делает чуть-чуть, может обходиться малым кодом. Наш фреймворк делает очень много всего в очень многих и очень разных браузерах. Плюс обратная совместимость и всё остальное. Если бы это можно было сделать в 100 строках, мы бы сделали, дураков нет.


Ну, или вот ребятам из системного отдела Microsft попробуйте рассказать про компактный код. Они вас внимательно выслушают.


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

Это не проблема, а фича. Точнее, две. И xtype, и xclass поддерживались с давних времён; если вам было недосуг почитать документацию или открыть тикет в поддержке, то это не наши проблемы.


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

На практике — нет, не било ни разу. Потому что:


  1. Мы говорим о боевой сборке, в которой нет и не может быть динамических зависимостей. Всё дерево вычисляется перед сборкой и является иммутабельным
  2. Замена кода сводится к банальному выкусыванию callParent и ссылкам на уже вычисленные методы в уже вычисленных зависимостях, см. п. 1
  3. Всё это очень, очень хорошо закрыто тестами.

А теперь лирическое отступление: вся эта ситуация отличается от ES6/ES7 и транспиляторов примерно чем? А хотя бы тем, что мы не зависим от чесания левой пятки у неизвестных людей, которые могут к чёрту сломать Babel или NPM в любой момент с катастрофическими для нас последствиями.

НЛО прилетело и опубликовало эту надпись здесь
«Реализация» классов в TypeScript и ES6 совпадает, все отличие TypeScript — в добавлении типизации.

Спасибо, буду знать. В общем как я и думал, TypeScript по факту это просто амулет для адептов секты статической типизации, им без неё депрессивно и одиноко. :)

Меня уже настараживает рост количества статей на тему "почему я перешел с angular2 на vue.js
Действительно все так плохо? Я нахожусь в процессе изучения angular. Уже написал свое первое приложение. При написании столкнулся с большинством из описанных в недостатков. Меня давно посетила мысль — "стоит ли продолжение изучения". Angular позиционирует себя как фреймфорк но он так и не дал мне слоя для Экшенов. Пришлось внедрять ngrx… так стоит ли все таки продолжать писать на нем? Кто защитит angular?

Именно для подобных людей я и писал данную статью! Поверьте, подобные статьи появляются не просто так. Надеюсь моя аргументация убедит вас хотя бы попробовать Vue.js
Что скажете по этому аргументу:
Angular позиционирует себя как кросплатформенный. Для манипуляции с домом рекомендуется использовать Renderer для поддержки различных устройств.

Vue.js поддерживает кросплатформенность?
Да, посмотрите на Weex. Собственно его и разрабатывают одни из основных мейнтейнеров — Alibaba.
А вот бы еще Vue с React'ом сравнить. Мы после первой версии ng 1.5 ушли на React. К React'у тоже много вопросов, наиболее больные: обратная совместимость и обилие реализаций flux. С готовыми компонентами там тоже не сказать, что прям супер. Иногда подумываю, что не смотря на все минусы ExtJs3, по количеству качественных UI-компонентов он оставляет позади многие современные и модные JS-фреймворки.

Про имхо пишут только хорошее. То ли еще не успели много написать и волну хейта ждать через год, то ли китайцы такие молодцы решительно не понятно, а вкладываться в изучение еще одного фреймворка нет уже моральных сил.
У Vue.js очень понравились однофайловые компоненты. Грубо говоря, в React можно добиться того же эффекта через CSS-in-JS, но подход с разделением компоненты на html + js + css кажется более естественным. Анимации делаются гораздо проще, чем в React. Ну и в целом остается впечатление, что пользоваться vue проще.
Из недостатков — слабая поддержка IDE (в моем случае WebStorm), не хватает подсказок автодополнения.

Анимации — да, ахиллесова пята реакта. А разделение js и html "как во Vue" можно делать используя stateless functional components (там просто jsx) вместе с recompose. В итоге везде получаются чистые функции, благодаря чему очень легко декомпозировать/композировать и до неприличия просто покрывать юнит-тестами.

С ngrx/store и ngrx/effects на Angular писать очень приятно. Более-менее сложное/крупное приложение даже боюсь себе представить без них.

тогда я не понимаю почему angular обзывают фреймворком, когда на самом деле это библиотека.

Воспользуюсь моментом и задам вам вопрос по angular-у :)

Могли бы вы мне прояснить как правильно реализовать консистентность компоненты при роутах. Суть в том что компонента каждый раз пересоздаётся при переходе на нее через роутер. Я полагаю что хранить все состояние компоненты в store решает проблему. Правильно ли дублировать все данные компоненты в сторе?

В частности проблема проявляется при валидации формы на стороне клиента.
С валидацией на стороне сервера все хорошо, данные пришли в стор — компонента нарисовала ошибки.
Но как быть с клиентской валидацией, ведь там используется reactive forms?
т. е. найденные ошибки не сохраняются в store, тем самым при последующем показе компоненты (ну например я сделаю переход по истории назад и вперед) — ошибки исчезнут, так как компонента заново пересоздалась и все данные пропали.

неужели нужно и клиентскую валидацию перенести в слой effects?

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

Где заканчивается набор библиотек и начинается фреймворк — это хороший вопрос. Фреймворк может быть монолитным или модульным. Модульный — это и есть набор библиотек по сути. Я думаю, что тут два критерия:


  • наличие штатного процесса bootstrap-а приложения (это вообще такое заметное внешнее отличие фреймворка от библиотеки);
  • согласованность интерфейсов библиотек, таким образом, что в комплекте получается бОльшая ценность.

Можно считать ngrx опциональным модулем Angular :-) Если со временем его примут в основные репозитории, это будет совсем не удивительно, а даже закономерно.


В сторе — да, все состояние, но не "вьюшное", а уровня model. И селекторов не жалеть, много — не мало :-)


При этом store не отменяет стандартную "ангуляровскую" иерархию input-output. Это все комбинируется. В мире react есть термины "presentation component" и "container component". В angular имеет смысл делать точно так же. Presentation components про store не знают, там input-output.


С формами — надо подумать :-). Вообще может быть плюс-минус два варианта UI. Первое — когда форма редактирует "рабочую копию" (грубо говоря, клон), и есть кнопки типа "сохранить"/"отменить" — тогда по submit-у делается action со всеми изменениями, и потеря изменений при навигации воспринимается естественно. В этом случае проблем нет (и от меня обычно хотели именно такой логики UI). Второй вариант — когда редактируется-валидируется все на лету, тогда, конечно, состояние валидности тоже должно быть в сторе — ведь тогда наверняка есть другие компоненты, которые селектят редактируемое значение, и невалидное им не нужно.


В эффекты сваливать это точно не надо, в эффекты валятся, мм, сайд-эффекты :) Вот хорошая картинка:
https://codesequence.github.io/ngrx-workshop/assets/player/KeynoteDHTMLPlayer.html#58


В идеале, эффект — это цепочка rxjs-операций, на входе один action, на выходе — другой. При хорошем знании rxjs получается в эту логику уложить что угодно. У меня начало хорошо получаться где-то через два месяца :-)


Ну и раз уж зашла речь про роутер, не могу не упомянуть ngrx/router-store и RouterStateSnapshot.

спасибо.
можно еще ликбеза :)
никак не могу понять логику которая скрывается за тем что в redux разделили экшены и редьюсеры. ведь редьюсер можно представить как метод экшена.
в чем соль этого?
> в чем соль этого?

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

Соль в том, что action — это DTO и его можно сериализовать и, к примеру, передать на другую вкладку. Или вовсе на другой компьютер через бакэнд.

Экземпляры классов тоже можно сериализовывать/десериализовывать.

Но стандартных сериализаторов с такими возможностями — нет. В этом плане "родной" синтаксис JSON сослужил экосистеме плохую службу.

Redux — это такой упрощенный Flux, а Flux — это такой упрощенный CQRS, "спроецированный" на фронтенд. Почитайте про CQRS и получите ответы на все вопросы. ;)

Поддержу. Обычно в таких ситуациях оставляю ссылку на эту книжку.

Самое поразительное тут то, что разработчики Flux, по их собственному признанию, понятия не имели про CQRS, но пришли к ровно такому же дизайну (только с другими названиями). Great minds think alike :-)

У меня слишком много претензий к FB, чтобы сравнивать их с great minds (хоть я и прекрасно понимаю метафору). Однако, стоит, все-же, отдать этим ребятам должное — они знают как правильно делать IT-маркетинг.

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

> разработчики Flux, по их собственному признанию, понятия не имели про CQRS

Многое говорит о разработчиках Flux.
Можно юзать reuse strategy.
Но, она помечена как експерементальная (хотя об этом в доке ничего не сказано) и мы при внедрении столкнулись к жуткой утечке памяти (может быть косяк был и наш, но неизвестн ов чем).
medium.com/@juliapassynkova/angular-2-component-reuse-strategy-9f3ddfab23f5
medium.com/@juliapassynkova/angular-2-component-reuse-strategy-9f3ddfab23f5

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


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

Да, всё так печально с Angular 4. Начинал несколько месяцев назад тестовый проект на Angular 4 для изучения сего фреймворка. До этого был вполне приятный опыт с Angular 1.5.x. Но теперь же, за что ни возьмёшься — одна боль. Документация — боль.
Но где-то месяц назад вскользь посмотрел vue.js и желание возвращаться к Angular 4 отпало.

Так что, видимо, не на пустом месте у многих людей возникают аналогичные мысли и чувства на счёт перехода на vue.js
По какой-то причине команда Angular решила сделать класс HttpParams иммутабельным.

А это не только в angular-е, сейчас вообще модно везде пихать иммутабельные объекты… Делается же оно для того чтобы избежать трудновоспроизводимых ошибок в сложном софте (кто-то где-то поменял то что не должен и у нас всё умерло).


RxJS operator import

Так а angular то тут причем? (самое забавное что некоторые операторы лежат в других файлах...)


Navigation

То что написано это цветочки, самая засада в том что похоже вообще нету именованных роутов, соответственно если есть /object/:id/comments, то везде придется писать this.router.navigate(['other', id, 'comments']);, как потом это поддерживать — загадка (или как-то можно?)


Вообще писать про документацию Angular даже нет смысла

А чем дока то не нравится? Она сейчас в виде допиливая реального приложения, вполне неплохо имхо, особенно для начинающих. Думаете абстрактные примеры были бы лучше? Ну а перевод вообще хз зачем нужен — (1) там все очень просто, (2) перевод всегда отстают от оригинала (а у них там постоянно что-то меняется). И кстати на SO обычно всё уже есть (удивительно, но оно даже не сильно путается с angular js).


Совершенно не ясно зачем делать именно так.

А какая разница какой css? SCSS кстати включается один раз и навсегда — всего то надо указать соответствующую опцию для cli при создании проекта (а если использовать scss то можно импортировать чужие стили и возможно это бы решило проблему с приоритетами).

похоже вообще нету именованных роутов

Тут я даже больше скажу. В альфа версии ангуляра были именованные роуты. И в документации даже была рекомендация пользоваться ими. И на примере объяснялось, почему это так удобно. Когда я обновлял ангуляр в своем проекте до стабильной версии, я был удивлен, с какой стати именованные роуты выпилили. Такой непоследовательности в разработке я искренне не понимаю.

Дисклеймер: данная статья строго субъективна...

Вот никак не понимаю в чём польза субъективных статей? Критика должна быть объективной, а не субъективной.
Про синтаксис шаблонов вообще не понял в чём ваша претензия.
Обещали, что будет достаточно только [] и ().… К сожалению в реальности директив едва ли не больше чем в AngularJS.

И что Вы предлагаете? Выкинуть эти директивы или что?
Вот если подобное убрать, то получится добротная статья. А так пустая трата времени.

Не поверите, но да, выкинуть эти директивы :)

Подробнее можно? Чем заменить?
К примеру, есть два варианта:
*ngIf="!isHidden"
или
[style.display]="isHidden ? 'none' : 'block'"

У вас есть выбор. Не вижу здесь противоречия — «Обещали, что будет достаточно только [] и ()». Обещание выполнено, если автор его привел дословно. Использовать ngIf вас никто не заставляет. Но с директивой код выглядит приятнее.

У меня немного другой посыл был: если выкинуть директивы, то и ангуляр уже не нужен.

Опять я должен додумывать. Но я понял о чём Вы. В этом случае тоже надо привести примеры «как должно быть», возможно, из других JS-фреймворков. Тогда критика будет конструктивной.

Как бы очередной шквал не поднять, но:


{!isHidden && <div>hi!</div>}
А как будет, если внутри не просто «hi!», а целый шаблон с переменными? Вложенные скобочки?
{!isHidden && (
  <ul>
    {items.map((item, i) => (
      <li key={i}>{item}</li>
    )}
  </ul>
)}

Вопрос не в синтаксисе (дело привычки), а в том, что можно и без директив интерфейс компоновать

Основная идея Ангуляр — это расширение возможностей HTML, сделать HTML динамическим.
HTML is great for declaring static documents, but it falters when we try to use it for declaring dynamic views in web-applications. AngularJS lets you extend HTML vocabulary for your application.

То, что вы предлагаете противоречит идеологии Ангуляр. Ну не нравится вам эта идея — ищите другое. Или критикуйте конкретно эту идею.
Вопрос не в синтаксисе (дело привычки), а в том, что можно и без директив интерфейс компоновать

По-моему вы критикуете именно синтаксис. Или вам не нравится название «директива»?

Ну я и критикую идею Ангуляр и вместе с ним критикую HTML. Как бы тут все не начали на перебой доказывать, что HTML — суть веба, у меня со временем сложилось другое мнение: HTML — это огромный кусок легаси, который упал нам на хвост, и приходится его везде за собой таскать. Неудобный, устаревший, с кучей костылей.


Мне не нравится, что я добавляю примеси компоненту снаружи этого компонента. Я его натурально патчу добавлением какой-то неведомой ерунды через *directive. Я нарушаю инкапсуляцию компонента, тогда как все возможные примеси должны быть объявлены внутри компонента, и это нормально. Ненормальны все эти костыли с директивами, появившиеся (а изначально в первых RC ng2 их не было) из-за того, что местные компоненты не могли оборачивать другие без дополнительных dom-нод. Вот и портировали директивы из ng1.

> Я нарушаю инкапсуляцию компонента, тогда как все возможные примеси должны быть объявлены внутри компонента, и это нормально.

Это как это? Примесь по определению должна быть внешней. Максимум — можно требовать, чтобы она применялась только в классам, реализующим определенны нинтерфейс. А «примеси, объявленные внутри компонента» — это уже явно не примеси, может, имелось виду что-то другое?

Возможно, трейты больше подойдут?


EDIT: Ну, то есть, компонент должен быть конечной точкой описания всего его поведения. Различные комбинации этих поведений должны описываться в виде инпутов (флагов), а не солянкой из патчащих директив снаружи

> Ну, то есть, компонент должен быть конечной точкой описания всего его поведения. Различные комбинации этих поведений должны описываться в виде инпутов (флагов), а не солянкой из патчащих директив снаружи

С таким подходом и НОС убрать придется :)

С какой стати? :) HOC порождает новый компонент, директива — нет

> HOC порождает новый компонент, директива — нет

Это на самом деле лишь условность, пронаблюдать которую можно исключительно в определенных граничных условиях из-за особенностей реализации change detection :)

А так вобщем-то никто не запрещает интерпретировать применение директивы как создание новой компоненты.

А, вы опять про свои "HOC" в ангуляре, я не их имел в виду :)


Проблема в том, что порядок "применения" HOC (которые настоящие HOC, в Реакте) вы выбираете явно путем композиции, а директивы мешаются в общую кучку. И я кстати не знаю (честно) как разрешается в ng2 порядок применения директив. Вот в ng1 это сделано реально отвратительно, прям как z-index'ы.

> И я кстати не знаю (честно) как разрешается в ng2 порядок применения директив.

Он решается тем способом, что в случае применения неструктурных директив напортачить затруднительно (то есть их применение «почти» коммутативно, или на это следует рассчитывать при их написании), а структурные директивы применяются только по одной к ноде.

Да нет, примеси — это именно что изнутри. А снаружи — это плагины.

Примесь — эта функция, которая класс приняла и другой класс вернула. Где тут «изнутри»?
> Вы сейчас описали не примесь, а декоратор.

Это зависит уже конкретно от языка. Важно-то, что в любом случае везде примеси — внешние сущности. В вашем же примере из вики — примесь comparable ничего не знает о классе, к которому применяется, и действует на него «снаружи».

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

Яркий пример примеси:


enum common_fields = "int row; int col;";

class Person {
    mixin( common_fields );
    string name;
}

Сама по себе примесь разумеется внешняя сущность. Но примешивает её сама сущность (функция, класс, модуль), а не тот, кто эту сущность использует.

Это лишь одна из реализаций, причем наверняка еще и в языке со статической типизацией.

> Но примешивает её сама сущность (функция, класс, модуль), а не тот, кто эту сущность использует.

Вы слишком большое внимание уделяете синтаксису (то, что строчка с миксином внутри определения класса), смотрите на семантику (да, к слову, в большинстве вариантов реализации миксин применяется на готовый класс явно, то есть и синтаксически «снаружи»). В вашем случае — миксин не внутри класса, к которому вы его применили. Он внутри класса-результата. А класс, к которому применен миксин — это class _Anonymous { string name; }

Думаю вам стоит отдохнуть и перечитать мой комментарий ещё раз :-)

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

+100, и мало того: HTML вообще категорически не подходит для создания приложений. Это язык разметки документов, и сколько бы ни тужились W3C, таковым он и останется. Даже WebComponents ситуацию сильно не облегчат, это кривой костыль.


Впрочем, само русло таких мыслей уже крамола. Этак можно додуматься до страшных вещей, вроде написания приложений на чистом JavaScript и использования библиотеки компонентов, которая манипулирует HTML где-то под капотом.


Но постойте, где-то я это уже видел...

Имеем, что имеем. GWT-like решения не приживаются.

Пардон, при чём тут GWT? Я говорил о написании приложений на чистом JavaScript, а не Java.

Да я понимаю, просто чуть дальше подумал. Кроме HTML у нас ничего нет. Только JS, ворочающий HTML под капотом, который вы "где-то уже видели" :)

Кроме HTML у нас есть DOM API, которое никто не мешает использовать напрямую. Генерации HTML можно избежать практически на 100%.


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


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

DOM API

угу, такое же неповоротливое легаси, не знаю даже что хуже


можете просто писать код JavaScript, который просто исполняется в браузере напрямую, в том же виде, в каком вы его написали

Могу, но не пишу, ибо я не мазахист и предпочитаю хоть какие-то абстракции.


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

Ну вот вы и описали этот необходимый слой.


Насчёт "не приживаются" как бы могу поспорить.

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

угу, такое же неповоротливое легаси, не знаю даже что хуже

А вы пробовали его по-настоящему вдумчиво курить? Я пробовал, и оно не такое плохое, как кажется на первый взгляд. Тем более, когда выбора нет. /s


Могу, но не пишу, ибо я не мазахист и предпочитаю хоть какие-то абстракции.
Ну вот вы и описали этот необходимый слой.

Так за чем дело стало? :)


Насчет "не приживаются" я имел в виду DX, а не продажи.

Не знаком с термином. Что означает DX?


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

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

Тем более, когда выбора нет.

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


Так за чем дело стало?

По-разному, есть проекты на реакте, есть на разных ангулярах.


DX

Developer Experience. Это как UX, только DX.

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

Это кому как. Я предпочитаю не вставать в позу, а использовать существующие инструменты. И каждый раз внезапно выясняется, что всё не так уж плохо, и если не рыдать крокодильими слезами, а работу работать, то она таки работается.


По-разному, есть проекты на реакте, есть на разных ангулярах.

Реакт это каким образом слой абстракции над DOM? Оно же просто за шкирку берёт и мордой в свой псевдо-XML салат тыкает всю дорогу, причём ещё и в оторванный от HTML. Худшее, что можно придумать: не HTML, не DOM, и не абстракция никакая, а лютая, бешеная смесь кода с тегами. PHP, дубль два.


Ангуляр в этом плане гораздо лучше смотрится, при всех своих болячках. Оно если и не абстрагируется от HTML, то хотя бы сильно не отрывается.

Ради интереса: вы какие-нибудь фреймворки использовали в продакшн кроме Ext JS и UniGUI?


Реакт это каким образом слой абстракции над DOM? Оно же просто за шкирку берёт и мордой в свой псевдо-XML салат тыкает всю дорогу, причём ещё и в оторванный от HTML.

А что по-вашему тогда абстракция? А React Native тоже browser DOM использует? А серверный рендеринг?

Ради интереса: вы какие-нибудь фреймворки использовали в продакшн кроме Ext JS и UniGUI?

Нет, сам не использовал, не было необходимости. Участвовал в проектах миграции с Angular 1 на Ext JS, но в роли консультанта больше, т.к. из потрохов одного вендора в потроха другого смотреть обычно некогда. Мы больше идеи тырим. :)


Про UniGUI тоже не в курсе, по крайней мере пока.


А что по-вашему тогда абстракция?

Достаточная абстракция, в данном случае, позволяла бы писать код, не зная особенностей HTML и/или DOM. Позволяет ли вам React не знать, как будет выглядеть HTML разметка? Не думать об особенностях веб среды, а сконцентрироваться на вашем приложении?


Если ответ "да", значит абстракция достаточная. На мой испорченный вкус и имея возможность сравнить с другими решениями, абстракция в React намазана тонким слоем на HTML и трещит по швам.


А React Native тоже browser DOM использует?

React Native это безусловно пример глубокой абстракции, т.к. методы разработки веб-приложений перекладываются на совершенно инородную среду. Другое дело, что сама идея вгоняет меня в оторопь: возьмите всё самое плохое, что с таким трудом долгие годы выкорчёвывало PHP, со звоном ляпните это в HTML/JavaScript и потом самозабвенно пихайте густой струёй в чуждую среду, игнорируя громкий треск лопающихся по швам конвенций и лучших практик.


Был бы верующим, крестился бы до синяков.


А серверный рендеринг?

Каким образом серверный рендериг поможет вам абстрагироваться от HTML, если именно HTML и является конечной целью? Поясните мысль, пожалуйста.

> Достаточная абстракция, в данном случае, позволяла бы писать код, не зная особенностей HTML и/или DOM. Позволяет ли вам React не знать, как будет выглядеть HTML разметка? Не думать об особенностях веб среды, а сконцентрироваться на вашем приложении?

Вы какбы не совсем понимаете, как оно устроено. Что в реакте, что в ангуляре, о разметке как раз вы и не думаете, потому что там разметки нет. Там есть декларативное описание интерфейса (которое выбрали намеренно «под html», так же как это делается и в современных гуитулкитах вроде какого-нибудь javafx), но это не html, он не работает как html и даже генерит оно в результате не html (в реакте — вдом, в ангуляре — вью, в обоих случаях — это js-объекты на js) :)
А выводом всего это на экран (в виде реального дом, в виде хтмл в случае server-side рендеринга, в случае нативных интерфейсов для мобилок/десктопа, или если угодно, для рисования розовых единорогов) — занимается конкретно слой рендера. Поменяли рендер — и никакого хтмл не осталось и в помине, при этом jsx/шаблоны у вас останутся.
Вы какбы не совсем понимаете, как оно устроено.

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


Что в реакте, что в ангуляре, о разметке как раз вы и не думаете, потому что там разметки нет.

Подождите, давайте с самого начала тогда. Реакт немного в сторонку отодвинем, давайте возьмём за пример Ангуляр: с ним я хотя бы чуть-чуть знаком.


Вот пример из документации: https://docs.angularjs.org/guide/templates, в котором чёрным по белому говорится про HTML разметку, расширенную (augmented) директивами Angular.


Даже если я вообще совсем ничего не понимаю, и вся эта конструкция из примера не имеет отношения к разметке HTML, то каким образом она является абстракцией от HTML, если подобна ему чуть более, чем полностью? "Если оно выглядит как утка, ходит как утка, и крякает, как утка — я назову его уткой" ©


но это не html, он не работает как html и даже генерит оно в результате не html (в реакте — вдом, в ангуляре — вью, в обоих случаях — это js-объекты на js) :)

Я не вижу, каким образом JavaScript объекты, управляющие состоянием дерева DOM, могут подтверждать или противоречить тому, что мы с вами обсуждаем. В конце концов любое веб-приложение является кучкой DOM элементов и скриптов, других вариантов пока нет.


Речь идёт о том, есть ли у вас возможность не мыслить в терминах кучки DOM элементов и скриптов, или такой возможности нет. Я в упор не вижу, каким образом Angular позволит оторваться от веб-разработки, если первое, с чего начинается приложение, это тег <html>, пусть и с дополнительными атрибутами.


Поменяли рендер — и никакого хтмл не осталось и в помине, при этом jsx/шаблоны у вас останутся.

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

> Вот пример из документации: docs.angularjs.org/guide/templates, в котором чёрным по белому говорится про HTML разметку, расширенную (augmented) директивами Angular.

Тут возникла терминологическая путаница, возможно, я сам виноват, что не уточнил. Когда в 2017 упоминают ангуляр, то обычно имеется ввиду второй (четвертый, пятый, ну и так далее) ангуляр, который совсем другой фреймворк.

> Вот в таком случае абстракция как раз и будет, но не в случае с web приложениями.

Так она и есть, что значит «будет»? И почему не в случае с веб-приложениями?

> web приложения в современном виде не являются образчиком вменяемого подхода к разработке приложений в общем смысле

Пока что лучшего подхода для разработки УИ не придумали, хотя делалось много разных попыток. За неимением гербовой — приходится писать на простой.
Тут возникла терминологическая путаница, возможно, я сам виноват, что не уточнил. Когда в 2017 упоминают ангуляр, то обычно имеется ввиду второй (четвертый, пятый, ну и так далее) ангуляр, который совсем другой фреймворк.

Хорошо, давайте посмотрим на современный Angular. В обзоре архитектуры опять же написано английским по серому (выделение моё):


Angular is a framework for building client applications in HTML and either JavaScript or a language like TypeScript that compiles to JavaScript.

The framework consists of several libraries, some of them core and some optional.

You write Angular applications by composing HTML templates with Angularized markup, writing component classes to manage those templates, adding application logic in services, and boxing components and services in modules.

Angular 2/4/whatever может и другой фреймворк, но предназначен он для разработки веб-приложений и HTML упоминается в самом начале. О каких высоких абстракциях мы тут можем разговаривать?


Так она и есть, что значит «будет»? И почему не в случае с веб-приложениями?

"Будет" это просто оборот речи. Имелось в виду, что Angular и ему подобные фреймворки/библиотеки изначально ориентированы на разработку веб-приложений и создавались именно для этого. Никаких особенно высоких абстракций для веб-приложений они не дают, поскольку вы всё равно должны быть в курсе, что разрабатываете именно веб-приложение. Трансформация же веб-приложения в нативно-мобильное даёт на выходе что-то иное, не то, что было на входе, и уже будет являться достаточной абстракцией, хоть и очень странной.


Пока что лучшего подхода для разработки УИ не придумали, хотя делалось много разных попыток. За неимением гербовой — приходится писать на простой.

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


Не надо забывать, что Веб начинался со статических документов и гиперссылок. То, что сейчас называется приложениями, от статических страниц не страшно далеко ушло. Я точно так же, как и вы, за неимением лучших инструментов пользуюсь HTML, DOM и JavaScript, но назвать эти инструменты чем-то, кроме безобразно кривых костылей, у меня язык не повернётся.


Советские ботинки тоже хорошие, если других не видел. ©

> Angular 2/4/whatever может и другой фреймворк, но предназначен он для разработки веб-приложений и HTML упоминается в самом начале.

Ну упоминается, и что? В самом фреймворке то ни html нет, ни dom (если не учитывать слой самого рендера, реализацию которого пользователь фреймворка не видит).

> Никаких особенно высоких абстракций для веб-приложений они не дают, поскольку вы всё равно должны быть в курсе, что разрабатываете именно веб-приложение.

Нет, не должны. Зачем? Разработчику вообще не нужно знать, где и как будет работать его приложение. Он описал УИ, описал его логику, а кто и как там будет ее запускать — на сервере, клиенте, с домом или без, нативно или нет — не важно. От этих деталей фреймворк нас абстрагирует.

> Трансформация же веб-приложения в нативно-мобильное даёт на выходе что-то иное, не то, что было на входе

Так и в веб-случае у вас на выходе совсем не то.

> Доставка контента с помощью веб-технологий даёт неоспоримые преимущества, но прямизна разработки как UI, так и прочих компонент приложения в эти преимущества не входит.

Конечно же входит. Именно по-этому практически все современные гуи-тулкиты мимикрируют под html/css. Можно сколько угодно называть подобный подход кривыми костылями — но лучше до сих пор никто не придумал.
От этих деталей фреймворк нас абстрагирует.

Вашими бы устами… Впрочем, дальше дискутировать мне уже лень и времени жалко. Цитируя любимую фразу моего босса: Let's agree to disagree.


Именно по-этому практически все современные гуи-тулкиты мимикрируют под html/css. Можно сколько угодно называть подобный подход кривыми костылями — но лучше до сих пор никто не придумал.

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

Речь идёт о том, есть ли у вас возможность не мыслить в терминах кучки DOM элементов и скриптов, или такой возможности нет.

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

Т.е.разработчик-прикладник не должен создавать строить дерево на основе «div»-ов, li, ng-if и ng-repeat, а взять некий готовый компонент «acme-tree», воткнуть его директиву в компонент «acme-panel», которая воткнута в компонент «acme-app», прописать свойства, подисаться на события — и не должен волноваться, какой конечный HTML/JS/CSS сгенерится в результате. В идеале, нативные HTML элементы (или даже вовсе не HTML) должны встречаться только в терминальных компонентах.

А вот тот, кто делает эти «acme-tree», «acme-panel» и т.п. вполне себе могут волноваться о деталях рендеринга, о доступности и т.п.

Т.е. да, Angular-приложение действительно начинается с html/body/ng-app, но при наличии развитой библиотеки компонент весь HTML на этом и должен закончиться. Angular сам по себе не предоставляет полную библиотеку высокоуровневых компонент (панели, гриды, деревья, навигация и т.п.), достаточной для написания любого приложения, он даёт некий базовый набор (формы, роутинг, базовые сервисы) и API для создания/расширения библиотек компонентов.
> Речь идёт о том, есть ли у вас возможность не мыслить в терминах кучки DOM элементов и скриптов, или такой возможности нет.

Ну так она и есть. У вас же нету ни дома, ни скриптов. Как вы можете мыслить тем, чего нет?

> но при наличии развитой библиотеки компонент

Мы зачем-то все в одну кучу мешаете. Задача ангуляра — абстрагироваться от манипуляций с домом, html и прочим. Он это делает. А библиотеку компонентов предоставлять — задача библиотек компонентов.

> и не должен волноваться, какой конечный HTML/JS/CSS сгенерится в результате.

Так он и не волнуется :)
Мне кажется то ли я не на тот коммент ответил, то ли вы. Я отвечал nohuhu, и как раз о том, что Angular позволяет абстрагироваться от DOM и позволяет меньше волноваться о рендеринге.
Ах, ок. Я подумал, ваш тезис состоит в том, что раз ангуляр библиотеки компонент не предоставляет — то и абстрагироваться не дает.
Предполагается, что разработчику конечного пользовательского приложения следует мыслить в терминах компонентов. Мышление в терминах HTML, скриптов и стилей следует отдать разработчикам компонентов.

Что интересно, именно то, что вы описываете, и делает Ext JS...


Angular сам по себе не предоставляет полную библиотеку высокоуровневых компонент (панели, гриды, деревья, навигация и т.п.), достаточной для написания любого приложения

… и не делает ни один из конкурентов.


он даёт некий базовый набор (формы, роутинг, базовые сервисы) и API для создания/расширения библиотек компонентов.

К сожалению, это малая часть того, что реально нужно для построения большого приложения. Основное мясо находится далеко не в роутинге и базовых сервисах. Можно сколько угодно говорить об абстракциях в низкоуровневых библиотеках навроде Angular или React, но сути это не меняет: компоненты вам всё равно придётся либо где-то искать, либо делать самим. А дальше желаю удачи абстрагироваться от HTML и всего остального.


Нет, конечно же это не проблема, кто мог такую ересь подумать. Любая же серьёзная организация способна запилить свой собственный grid.

НЛО прилетело и опубликовало эту надпись здесь
А в чем, собственно, разница? *ngIf же не базовая директива, она реализована поверх фреймворка, а не вшита в него.

Против базовых ничего не имею, более того, это реально удобнее в рамках привычного HTML. Почему я против директив уж вы-то точно знаете, а так — описал в комменте выше

Очень доставляли подобные шаблоны в Spacebars. Точнее там их юзал в связке с Jade (на тот момент еще), в нем все эти циклы, условия, интерполяция переменных, подстановка компонентов и т. д. вообще выглядели нативно, что мне казалось проявлением чего-то божественного. Типа не может же быть такого, что прочитав 2 страницы документации по jade и еще немного по Blaze, потратив от силы пару часов, можно начинать делать интерфейс, разбивая все на компоненты, и все без боли и страданий, и сразу получая работающий код, с хорошей декомпозицией, и делая все максимально наивным способом.


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

Хочу дополнить по поводу библиотек, основанных на bootstrap, в частности, ngx-bootstrap (она же ng2-bootstrap), ng2-select, от valor-software. Увы и ах, хотя и самые распространенные, с продуманностью и глючностью у них есть проблемы, особенно у select2, который выглядит довольно заброшенным. Но бог с ним, с select2, даже modal в виде сервиса появился только этим летом, и то без resolve (без передачи параметров в конструктор). Некоторые глючные стили теперь “вморожены“ и не фиксятся без !important..


Как альтернатива для bootstrap, еще появилась (imho) более вменяемая ng-bootstrap, от тех людей кто писал angular-ui для angular-js, но там только ещё не выпущенный bootstrap4, и тоже альфа-беты.


За инфу про VMware спасибо!

Эм, в ngx-bootstrap сервис NgbModal был с давних времен, а resolve не нужен — инпуты проставляются через modalRef.componentInstance

Скорее всего ты говоришь про ng-bootstrap (это другая библиотека, на bootstap 4 альфа — у меня она упоминается во втором абзаце). В ngX-bootstrap добавлен сервис был пару месяцев назад:
https://github.com/valor-software/ngx-bootstrap/pull/2047

Точно! Не заметил.
Исправлено, спасибо.

С ручными импортами в rxjs — это проблема неработающего в случае с прототипами/объектами/псевдо-неймспейсами tree shaking, по сути временная. Когда-нибудь ее решат, и можно будет импортировать весь Rx, не беспокоясь о размере билда. Конечно, было бы хорошо уметь ругаться на этапе компиляции — но если до такого умения дошли, то можно и tree shaking сразу сделать.

C претензиями к Roter, HttpClient и Forms я соглашусь, но к плюсам ангуляра можно отнести относительную модульность и как результат возможность не использовать эти модули, что мы благополучно и делаем на нашем проекте — у нас свой роутер, свой http клиент и свои Dynamic Forms. Причины почему, так вышло были разные и я не агитирую поступать так же, но, тем не менее, возможность заменить не базовые модули ангуляра есть, если стандартные чем-то не устраивают.
Раньше я тоже считал, что модульность Angular — большой плюс для Lazy Loading'а. Но задумайтесь — весь минифицированный Vue.js весит 60Кб. Спрашивается, а стоит ли весь этот boilerplate с модулями того?
Я имел в виду, что с архитектурной точки зрения основа Ангуляра не привязана к отдельным его модулям и он не принуждает их использовать. Ничто не мешает делать запросы через, например, jQuery или fetch.

Не смотрели ли вы в сторону $mol, который целиком и полностью написан на TypeScript?


Нужен он CLI для того, чтобы упростить создание новых компонентов/модулей/тестов итд.

CLI нужен, лишь когда приходится писать много типового кода. В $mol, чтобы создать компонент нужно всего-лишь создать файл, написать в нём строчку кода и всё.


В целом не совсем разделяю взгяд автора на RxJS, т.к. библиотека невероятно мощная.

Но и невероятно неэффективная.


Но суровая правда в том, что Object.observe нативно мы все же не увидим

Какое отношение имеет RxJS к Object.observe?


Потому что вы очевидно (потратили кучу времени на поиск проблемы) забыли заимпортировать сам оператор

В $mol такой проблемы в принципе нет, так как зависимости подключаются автоматически по факту их использования.


Теперь для работы с параметрами предлагается подписываться на события роутера.

Зачем вообще какой-то там роутер, если можно просто прочитать реактивное значение?


pages() {
    return [
        this.Menu() ,
        ... this.$.$mol_state_arg.value( 'order' ) ? [ this.Order() ] : [] ,
    ]
}

в Angular есть два типа форм: обычные и реактивные.

В $mol всё реактивное и кастомизируемое. У компонент есть свойства, в которые он может писать и из которых читать. В простейшем случае:


value( next = '' ) { return next } 

А владелец уже может одно-/дву-сторонне связать его с любым другим по любой хитрой формуле.


Без метаданных декораторы тоже можно использовать — во время компиляции, но толку в таком случае от них не очень много.

От той metadata, что генерирует TS пользы не особо много: никаких интерфейсов, только ссылка на класс. А вот сами по себе декораторы позволяют уменьшить копипаст.


Dependency Injection в Angular. Сама по себе концепция замечательная, особенно для unit тестирования.

В динамически типизированном языке польза для юнит тестирования сомнительна, ведь и так можно налету изменить что угодно. Мы остановились на более практичном компромисе — контексте. Например, в компоненте может быть написано:


this.$.alert( 'Hello!' )

Где $ — по умолчанию — глобальный контекст. Но любой компонент в дереве рендеринга может изменить контекст для всех вложенных в него на любую глубину компонент:


@ $mol_mem()
context_sub( ) {
    const context = this.context()
    const subContext : $mol_view_context = Object.create( context )
    subContext.alert = ( message ; string )=> this.$.$my_dialogs.alert( message )
    return subContext
}

Всё, теперь вложенные компоненты, ничего не зная ни про какой DI, не системный алерт вызывают, а тот, который задали мы, а TS, разумеется, проверяет соответствие сигнатур. Аналогично можно не только функции дёргать/переопределять, но и любые другие сущности: переменные, классы, объекты.


А вот пример компонента из проекта на Angular:

Заголовок спойлера
import {Component} from '@angular/core';

import FileService, {ContentType, IFile} from "../file.service";
import AlertService from "shared/alert.service";

@Component({
  selector: 'app-file',
  templateUrl: './file.component.html',
  styleUrls: ['./file.component.scss']
})
export class FileComponent {

    Input() item: IFile;

    constructor(private fileService: FileService, private alertService: AlertService) {
    }

    public isVideo() {
        return this.item.contentKeyType === ContentType.VIDEO;
    }

    public downloadFile() {
        this.fileService.download(this.getFileDownloadUrl()).subscribe(() => {
            this.alertService.success();
        });
    }

    private getFileDownloadUrl() {
        return `url-for-download${this.item.text}`;
    }
}

На $mol было бы куда лаконичнее:


Заголовок спойлера
namespace $.$$ {

    export class $my_file_loader extends $.$my_file_loader {

        item() {
            return null as $my_file
        }

        is_video() {
            return this.item().contentKeyType === $my_file_type.VIDEO
        }

        @ $mol_mem()
        downloadFile() {
            this.$.$my_files.download( this.download_url() )
            this.$.$my_alerts.success()
        }

        private download_url() {
            return `url-for-download${ this.item().text() }`;
        }
    }

}

Но лучше упростить апи:


namespace $.$$ {

    export class $my_file extends $.$my_file {

        is_video() {
            return this.file.is_video();
        }

        @ $mol_mem()
        download() {
            this.file().download()
            this.$.$my_alerts().success();
        }

    }

}

Синтаксис шаблонов — основная претензия к Angular. И по вполне объективным причинам.

В $mol вообще нет шаблонов как таковых. Есть только: компоненты, декларативное описание их взаимосвязей (условно это можно считать шаблонами без логики) и скрипты с логикой (TypeScript). Шаблоны — слишком низкоуровневые штуки, которые только мешают построению приложения из компонент.


доки Vue. Мало того, что написаны подробно и доходчиво, так еще и на 6 языках, в т.ч. русском.

В $mol нет таких развесистых док, да ещё и на 6 языках. Зато исходные коды простые, понятные и содержат кучу реальных примеров использования. Например, тот же грид не пытается уметь всё на свете от фильтрации до паджинации, а предоставляет минимально необходимых интерфейс, чтобы как угодно его кастомизировать. То есть тут на лицо филисофия юникс — каждый компонент делает только свою задачу, но делает её хорошо и легко стыкуется с другими компонентами.


body .ui-tree .ui-treenode .ui-treenode-content .ui-tree-toggler

В $mol атрибуты, к которым привязываются стили, генерятся автоматом, с учётом контекста. Что позволяет переопределять стили любого элемента стороннего компонента, как бы глубоко в компонентной иерархии он там ни находился, при этом сохраняя одну и ту же специфичность и избегая конфликтов имён. Например: [my_app_menu_head_close_path] {} — это стиль для пути в svg-иконке, которая является кнопкой закрытия в шапке страницы, которая является панелью меню в нашем приложении.


Наличие двух различно работающих компиляторов само по себе довольно опасно звучит,
и на деле постоянно приводит к проблемам.

По той же причине в $mol нет рантайм компилятора и пофайловой загрузки скриптов. Даже во время разработки собираются продакшен бандлы, чтобы разработчик видел ровно то, что он получит на проде.


Да, я понимаю, что выбирать фреймворк по наличиую UI компонентов в корне неверно

Почему это? Вполне себе верно. Поэтому в $mol мы сразу же разрабатываем и стандартную библиотеку компонент, чтобы пользователям не приходилось велосипедить одно и то же.


довольно скудное количество готовых наборов UI компонентов

Важно не количество, а качество. Куда лучше, если сообщество сконцентрировано на улучшении одной стандартной библиотеки, чем фрагментированно на кучу ui-наборов.


библиотека Clarity от vmware. Набор компонентов впечатляет, документация крайне приятная, да и выглядят здорово. Как никак VMware серьезнейший мейнтейнер и есть надежда на светлое будущее.

Касательно $mol — уже видел ваши комментарии про него ранее, но боюсь размеры community слишком малы, чтобы избрать его для серьезного enterprise приложения. А pet проекты и на Vue делаются супер быстро (опять же размеры community и простота/быстродействие).

А про упавший билд Clarity — спасибо за юнит тесты, которые действительно что-то проверяют (уверен, что пофиксят в ближайшее время).
А pet проекты и на Vue делаются супер быстро

На $mol ещё быстрее.


размеры community

Какая польза от размера комьюнити? Большой выбор велосипедов? Большой выбор экспертов на SO?


простота/быстродействие

$mol ещё проще, модульнее и с глубокой поддержкой ленивого рендеринга.


упавший билд Clarity — спасибо за юнит тесты, которые действительно что-то проверяют

Не просто упавший билд, а сломанная мастер ветка со всеми вытекающими.

НЛО прилетело и опубликовало эту надпись здесь

А какой более адекватный ответ тут может быть? Вы делаете необоснованные предположения — вам отвечают, что вы не правы. Проверить можете сами, если не верите.

НЛО прилетело и опубликовало эту надпись здесь

А как думаете IDE справлялись с ES5, где никаких импортов не было? Сканировали весь проект и всё.

НЛО прилетело и опубликовало эту надпись здесь

А c TypeScript отлично и единообразно справляются благодаря Language Services.

НЛО прилетело и опубликовало эту надпись здесь

Разумеется, он же обратно совместим с JS.

Да вы с комментариями про $mol уже стали прямо-таки локальным мемом

Зачем так много долларов?

Вы не любите доллары?

НЛО прилетело и опубликовало эту надпись здесь

Что хочу сказать после того, как команда довела до релиза средненького размера проект (SPA, ~40k sloc ): выбором angular довольны.


Batteries included в широком смысле слова — от инфраструктуры (ng-cli великолепен) до заданной структуры проекта и навязываемой декомпозиции. Сторонних модулей уже (местами) достаточно много.


Typescript и aot сильно снижают количество регресионных факапов. Спорно (а мне спорить лень), но за годы знакомства с typescript'ом у меня все сильнее растет удивление, что кто-то еще пишет на голом js.


А главное — практически ни разу ни у кого из команды не возникло чувства "я сражаюсь с фреймворком". Не возникло чувство, что он ограничивает; что есть вещи, которые на vanilla.js были бы проще.


В плане UI еще в статье забыли @angular-mdl — местами сырая, но очень приятная библиотека.


Основные минусы (ну куда же без них?):


  • О документации проще сказать что ее не существует. То, что есть — плевок в лицо.
  • Более отвратительной системы роутинга я еще не встречал. Надеюсь, ее сожгут и сделают заново.
  • За организованный репозиторий модулей отдал бы левую ногу

В целом: для больших SPA пока что иных вариантов не видим. А для мелочи (особенно fire-and-forget мелочи) vue уже очень сильно начитает тащить своим минимальным размером

А в чем проблема роутинга? Только начал разбирать angular и хочеться узнать про эту проблему подробнее?
Скорее всего mjr27 имеет в виду params и queryParams, которые Observable. С другой стороны, они позволяют при смене роута на тот же компонент, но с другими params, обновлять его, не пересоздавая.
Кроме того, нет нормальных именованных роутов и тупая сигнатура Router#navigate
> Кроме того, нет нормальных именованных роутов

А что подразумевается под «нормальными именованными роутами»?
Назначение путям имен, например orders => '/items/:xx'. Типк как сделано в ui-router например, или vue-router. Чтобы например можно было поменять путь, не меняя код везде, где этот путь используется. То есть, чтобы можно было например изменить'/items/:xx' на '/foo/orders:xx' не делая поиск-замену по всему проекту.
> Назначение путям имен, например orders => '/items/:xx'.

const paths = {
    path: "my/patch",
    anotherPatch: "another/patch",
    oneMorePatch: "one/more/patch",
}

const appRoutes: Routes = [
    { path: paths.path, component: MyComponent },
    { path: paths.anotherPatch, component: AnotherComponent },
...
];

так? или что еще должно быть?

Вот такое должно быть. Без этого грустно


const appRoutes: Routes = [
    { path: "language/:lang/category/:category/item/:item", component: MyComponent , name: "itemView" },
];

// ...

const url: string = this.router.reverse("itemView",  {lang: this.lang, category: this.categoryId, item: item});

А в идеале даже


/* Привет из django */
 {path: "language/(?P<lang>\s{2,3})/category/(?P<category>\w+)/item/(?P<item>\d+)", component: MyComponent , name: "itemView" }
Ну это все пишется за полчаса. Потому и убрали. Нужен такой функционал достаточно редко, а реализуется — элементарно, причем в том виде, в котором будет нужен в данном конкретном случае.
Ну это все пишется за полчаса

Явно не за полчаса + странный аргумент для "batteries included" фреймворка.


Нужен такой функционал достаточно редко

Необоснованное предположение. Нам такой функционал был не нужен достаточно редко; обработка валидности входных параметров в контроллере же (как предполагается самим фреймворком) — явное смешивание полномочий.


В том виде, в котором будет нужен в данном конкретном случае

В самом общем случае урл выглядит как "...[var1:format]...[var2:format]...[var3:format]..." Зачем было искусственно это ограничивать — я так и не понял

> Явно не за полчаса + странный аргумент для «batteries included» фреймворка.

«batteries included» никогда не означало наличие редко нужного функционала, вопрос реализации которого — сотня строк кода.

> обработка валидности входных параметров в контроллере же (как предполагается самим фреймворком) — явное смешивание полномочий.

Это правильно, валидность надо проверять в роутере. В ангуляре специально для этого есть canActivate гварды. При этом проверять можно не только формат синтаксиса, а выполнение любых условий. Например, роут foo/:id при несуществующем в базе айдишнике столь же невалиден, сколь и роут с неправильным синтаксисом.

> В самом общем случае урл выглядит как "...[var1:format]...[var2:format]...[var3:format]..." Зачем было искусственно это ограничивать — я так и не понял

Ваш «общий случай» не учитывает синтаксиса аргументов и именованных аутлетов (как раз тот функционал, который «на коленке» не напишешь), а потому просто не работает.

редко нужного функционала

Если навигация это "редко используемый функционал", то я даже не знаю, что такое часто используемый.


canActivate гварды

К сожалению, не панацея. Я хочу проверку ссылки в момент ее генерации (о проверке в compile-time я уже не говорю).


Или хоть что-либо отличное от каши any[] в [routerLink]


роут foo/:id при несуществующем в базе айдишнике столь же невалиден, сколь и роут с неправильным синтаксисом

Сильное утверждение. Навскидку


https://twitter.com/hashtag/++++++++++
https://twitter.com/hashtag/llllllllll3llllllll


Ваш «общий случай» не учитывает синтаксиса аргументов и именованных аутлетов

На то, что структура URL для именованных аутлетов прибита девятидюймовыми гвоздями, я предпочел не жаловаться, в Router и без этого проблем хватает.


Данный способ как раз расширяем (e.g "/category-{id}{aux:/item-{id}}"), в отличии от встроенного "вот вам url.split('/'), радуйтесь"


P.S: Вообще, думаю, спор на самом деле ни о чем. Вам стандартной схемы хватает, мне однозначно нет. Так что буду плакаться, колоться, и делать велосипед. Спасибо за интересную дискуссию.


/off

> Или хоть что-либо отличное от каши any[] в [routerLink]

Роут нельзя типизировать, потому что это по определению — просто строка. К слову, все ваши предложения с "/category-{id}{aux:/item-{id}}" сразу блокируют в роутерлинке что-либо кроме any[].

> К сожалению, не панацея. Я хочу проверку ссылки в момент ее генерации (о проверке в compile-time я уже не говорю).

Кто мешает?

> Данный способ как раз расширяем (e.g "/category-{id}{aux:/item-{id}}"),

А чем вас, собственно, не устраивает /category;id={id}? тем, что ";" вместо "-"?

Вообще не понял аргумента. Строку нельзя превратить в типизированную структуру? JSON.parse негодует.


RouterTypeService.register("int", /\d+/, (val) => typeof val === "number", parseInt, x=>x.toString());
RouterTypeService.register("uuid", /[a-f0-9]{32}/, parseUuid, x=>x.toString());
{path: "/category-{id:int}{aux:/item-{itemId:uuid}", name: 'test'}


this.router.navigate('test, {id: 10, aux: {itemId: 'aa...00'}});


Кто мешает

Вообще не понял вопроса, если честно.


(new UrlBuilderService()).makeCategoryUrl(id, itemId)?


А чем вас, собственно, не устраивает /category;id={id}? тем, что ";" вместо "-"?

Если коротко — да хотя бы тем, что я хочу именно так а не иначе. Достаточная причина? Система маршрутизации, под которую приходится подстраиваться, веет 2001м годом а-ля category.php?id[]=12&id[]=13


Конкретно в текущем проекте у нас полу-статический контентный сайт с давней историей и кучей трафика по прямым ссылкам и букмаркам (да, такое еще существует). И этот сайт по нажатию кнопки "сделать п… то" превращается в современное spa.


И я хочу чтобы у ангулара были точно такие же ссылки, какие были уже второй десяток лет.


Я много фреймворков перевидал, но пока что это первый в котором, когда настолько примитивная функция сделана настолько "для галочки".

> Вообще не понял аргумента. Строку нельзя превратить в типизированную структуру? JSON.parse негодует.

И какой тип аргумента navigate у вашего примера? И как его выразить в рамках системы типов ТС?

> Вообще не понял вопроса, если честно.

Я говорю, кто не дает вам валидировать роуты в момент создания? У вас есть ф-я, которая генерит роуты, в чем проблема проверять роут в ней?
как его выразить в рамках системы типов ТС
да хоть public navigate<T>(route: string, params: T, options: RequestOptions>. Довести до абсолюта public navigate<T>(params: T, options: RequestOptions> по очевидным причинам не получится.

У вас есть ф-я, которая генерит роуты, в чем проблема проверять роут в ней?

Два контраргумента:


  1. Зачем бить "туда" и "обратно" на два разных куска, если это всё можно задать 1 раз декларативно?
  2. А где должна быть эта функция? Вижу 4 варианта:
    • Отправляющий компонент (где создается URL): привет, копипаста; структурно неверно
    • Принимающий компонент (куда ведет URL): как достучаться? что если компонент по нескольким схемам URL доступен? Что с использованием в других проектах?
    • функция: привет от DI и тестов
    • сервис/injectable: ну вроде сильных контраргументов нет

А теперь вопрос — зачем мне сервис маршрутизации, когда у меня уже есть сервис маршрутизации?


UPD: изменил, парсер съел угловые скобки

> да хоть public navigate

И кто помешает мне вызывать navigate(route, anyObject) с anyObject, неподходящим под сигнатуру роута route? Какой толк от типа, который ничего не фиксирует?

> Зачем бить «туда» и «обратно» на два разных куска, если это всё можно задать 1 раз декларативно?

Что бить?

> А где должна быть эта функция?

Там, где вы описываете роут, очевидно.
кто помешает мне вызывать

navigate<T>(route, anyObject), парсер лох


Там, где вы описываете роут, очевидно.

А где я описываю роут, например, в случае lazyLoad? В каком из двух файлов?

> navigate(route, anyObject), парсер лох

Ответ на вопрос-то где? Вот я пишу navigate(route, anyObject), все прекрасно тайпчекается. В чем смысл такого ограничения на типы?

> А где я описываю роут, например, в случае lazyLoad? В каком из двух файлов?

В каком вам удобно, в таком и описывайте.

В тайпскрипте? От navigate<IItemParams>(route, <any>anyObject)? Никто не помешает, ясен перец. Но в первом же кодревью за это накажут.


В каком вам удобно, в таком и описывайте.
Отличный ответ. Лично мне ни в каком не удобно.

Честно, не понимаю о чем разговор. Вас устраивает — пользуйтесь на здоровье. Меня нет, по длинному списку озвученных выше причин. От продолжения спора для меня ничего не изменится, так что удаляюсь.

> От navigate(route, anyObject)? Никто не помешает, ясен перец.

А, так вы тип генерика руками записывать собираетесь? я сразу просто это не понял. Непонятно, чем тогда не устраивает вариант navigate(routeFrom(route, params)).

> Отличный ответ. Лично мне ни в каком не удобно.

Непонятно тогда, зачем вы требуете функционал, который вам будет неудобен.

Это исчезает из многих роутеров, например, из последнего react-router.


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


Однако, отсутствие opt-out статического именованного роутинга реально напрягает, сейчас он нужен в 90% случаев.

Да в нем плохо все.


  • негибкость: урлов типа /[id:\d+]-[section:\w+]-[name:\w+].html существовать не может
  • да, отсутствие именованных роутов. Собирать везде ссылки типа ['/content', language, 'section', book] — отдельное удовольствие. А менять еще более отдельное
  • Бажный lazy routing. Создать несколько аутлетов в корневой компоненте модуля нельзя еще с 2 RC1
  • Цирк при попытках достучаться до параметров родителя (например где-то там наверху есть параметр lang)

Такое чувство, что авторы Router'а живут в мире, где все урлы выглядят как /about или /hero/:id и какают бабочками

Я честно говоря не понимаю, зачем использовать непопулярные библиотеки которые не востребованы на рынке когда есть React + Redux? Это просто как минимум не практично на мой взгляд. Причем даже если закрыть глаза на востребованность, то я не вижу никаких значительных преимуществ Vue перед тем же React.
Количество вакансий на hh:
1) Angular 1541
2) React 1511
3) Vue 282
На сегодняшний день это действительно основной минус Vue, если для вас наиболее важно скорое трудоустройство. Но ведь и React когда-то был в таком же статусе? Однако темпы роста популярности Vue.js гораздо выше.
Вероятно в этой выборке нет разделения на AngularJS и Angular, то есть основная часть уходит к AngularJS.
Причиной востребованности иногда может быть вовсе не дизайн библиотеки, а размер компании, стоящей за ней. Бизнес хочет быть уверен что технология, в которую он вкладывается, не исчезнет через пару лет. Отсюда и количество вакансий. То же правило что и у телевизора — кто в эфире, тот и прав. Angular/React соответственно Google/Facebook. Правда у «хипстеров» Гугла в этом плане с кредитом доверия уже есть некоторые проблемы, после того как они всех «доверившихся» прокатили с Angular2, сделав несовместимым с Angualr1.
А Vue по виду получается простая и удобная — может протоптать себе дорогу из без «катков» в виде мега-корпораций.
Сможет ли Vue протоптать себе дорогу покажет только время… а пока… имеем то, что имеем. Лично я сильно сомневаюсь что Vue долго продержится в такой жесткой конкуренции… но это пока что только моё объективное мнение.
Выше говорят, что за vue.js стоит Alibaba. А это «бездонный океан» бюджета и специалистов. Так что «каток даже не паровой, атомный».

Теперь по умолчанию в связке с Vue поставляется небезызвестный Laravel. Это тоже должно повлиять на популярность Vue в том числе и на hh.

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

Ну вот опять вы все о том же :)


Отвратительная — возможно; процедурная — вряд ли; быдлокодерская — стопроцентно; копипаста — вряд ли; плохой код — это какой?; плохо типизируется — отлично типизируется; компоненты делают дерево данных кривым — вряд ли, инкапсуляция ж; код редьюсеров растет — может они не тем занимаются?; сложность поддержки растет — вряд ли; адекватных вещей — это каких?; крайне сложно поддерживать — поддерживаем и норм; иллюзия простоты и кривая обучения — да, наверное; код устаревает — вряд ли; недо-фп — стопроцентно; хипстеры и типизация — стопроцентно; юнит тесты неадекватны — а что с ними не так?


Кстати, по поводу недо-фп. Я тут играюсь немного, переписал стор под сигнатуру редьюсеров Action -> State -> State вместо стандартной (State, Action) -> State — стало значительно удобней, особенно с интеграцией той же ramda. Вместо объектов теперь оперируем преобразованиями.

  1. Ну не могу я спокойно раз за разом читать комментарии вроде "давайте все переходить на редакс", уж простите.
  2. Процедурная — 100%, смотрим исходники: https://github.com/reactjs/redux/blob/master/src/createStore.js
  3. Типизация: покажите мне пример, где я из стора достаю данные, передаю в компонент через connect и оно проверяет типизацию в компайл-тайм. И вообще — я бы с удовольствием посмотрел на типизированный стор. Или как вы ваш action=>state=>state типизируете?
  4. Код редюсеров растет за счет количества похожих редюсеров, а не за счет увеличения ответственности редюсеров
  5. Вот только инкапсуляция протекает, если такие компоненты необходимо расширять
  6. Я не видел тестов, которые проверяют реальную логику работы. Те тесты которые я видел — бесполезны. Я грешу на недо-фп и болезненную боязнь абстракций, в результате функции становится сложно тестировать. Все-таки простой объект легче покрыть тестами, чем функцию, которая возвращает функцию, которая возвращает функцию.
  7. Мне сейчас очень нравится MobX. В сравнении с редаксом — как на мерс после жигулей пересел. Значительно ниже порог входа — всего три ключевых слова, которые необходимо понять, однонаправленный поток как основное преимущество флакса и никаких недостатков редакса. Код выглядит понятным, легко поддерживается, быстро работает. Один человек может писать слой MobX (модель), выдавать вменяемый и понятный API, а другой использует этот слой в Реакт-слое (view)
> И вообще — я бы с удовольствием посмотрел на типизированный стор.

без проблем делается, вот например github.com/ngrx/platform/tree/master/example-app/app,

> Значительно ниже порог входа

Редакс ведь тот же паб/саб, то есть порог вхождения не особо высок, но вот код дофига писать это да, загроможденно получается. MobX как раз в связке с React вроде как значительно уменьшает количество шаблонного кода.
  1. Простите, а вы уверены, что это Редакс, а не что-то похожее? Я не зря упомянул не только дерево (которое типизировать несложно, хоть и не очень красиво), но и connect (функция редакса) с компонентом


  2. МобХ мне кажется значительно проще за счет отсутствия непонятно зачем нужных строковых констант, более удачных ключевых слов, отсутствию иммутабельности (поменять объект где-то в середине глубокого дерева для неподготовленного человека может оказаться непосильной задачей).
1. вот первое что нагуглилось spin.atomicobject.com/2017/04/20/typesafe-container-components Хз это ли имеется ввиду, react-connect никогда не использовал.
2. мне тоже МобХ нравится, и по сути подобная риактивность уже встроена в VueJS.
И еще более чем достойная альтернатива: github.com/FormidableLabs/freactal

Вообще, тренд к «фрактальному стейту» идет — Freactal, Mobx State-Tree, cycle-onionify, Elm Architecture.
  1. Ну да, обсуждали уже
  2. Ммм, но интерфейс-то функциональный, какая разница какая реализация
  3. А неее, это уже react-redux, и там действительно проблемы, потому как TS не может вывести тип возвращаемого значения mapStateToProps и, как следствие, вырезать полученные ключи из пропсов оборачиваемого компонента. Хотя, если ему явно их указать в тайп-аргументе, то все заработает. Кстати, мне-таки удалось заставить вырезаться эти пропсы но только для случаев передаваемого объекта, а не фукнции
    Так, что Action -> State -> State не приносит типизацию в стор, так как там она уже есть, а лишь позволяет писать редьюсеры без упоминания state. Тут корректнее даже запись Action -> (State -> State). В комбинации с линзами просто удобнее возвращать из редьюсера скомпоуженые функции-сеттеры. Следующим шагом хочется попробовать собрать стор чисто из линз, чтобы иметь прямой доступ к ноде в стейте без всяких этих реселектов, дабы не дублировать композицию на чтение и на запись.
  4. Вы про одинаковые редьюсеры под сущности? Ну можно же их и в абстракцию сунуть.
  5. Не, не протекает, если принимать внутренние компоненты через своего рода DI (через контекст), оставляя в defaultProps стандартную реализацию, на которую ссылается модуль. Таким образом можно в сторонке собрать дерево компонентов, а потом через DI подменить нужные компоненты их контейнерами. Инжектор такой собирается на коленке, только вместо мэпа лучше держать какую-нибудь минимально простую реализацию стрима (та же most.js), чтобы работал shouldComponentUpdate.
  6. Если внутри редьюсеров сидит какая-нибудь гадость из серии thunk и promise, то да, это боль. Если же нет, то все вроде бы достаточно удобно.
  7. Что-то он все не заходит у меня никак… Надо наверное, еще один поход организовать

3) А разве есть альтернативные реализации без этих проблем? Какой смысл обсуждать редакс без контекста связи с реактом? Зачем вся эта головная боль, Если в МобХ все работает легче и нативно?
4) "Абстракции — зло", все такое.
5) И сколько либ под редакс позволяют это делать?)
6) Ну Тханк помоднее тех же саг будет. Какова вероятность, что придя в новую фирму вы там увидите одну или другую надстройку?
7) Могу через пару дней в личку описать, как мы МобХ готовим, если интересно, может зацепит.

НЛО прилетело и опубликовало эту надпись здесь
Да, давайте статью! Вроде про MobX давно ничего не было. А все что было — на уровне tutorial для начинающих.

Сам давно к нему присматриваюсь, но никак не удается пробить стену недоверия остальных членов команды :(

В отличие от Redux, он подкупает своей интуитивностью, и низким порогом входа. И мне, как фуллстеку, проще заходит ООП с SOLID и вот этим всем. Хоть это сейчас и не модно. Также, с ним гораздо удобнее группировать код по фичам, а не по архитектурным слоям.

А еще, он позволяет хранить presentational state в обычных observable-свойствах компонента. Вместо использования this.setState(...), который ограничен «плоским» объектом, и работает неинтуитивно из-за «отложенного применения».

Забыл 2) ну dispatch в компонентах с агрессивными сайд-эффектами — тоже обычная процедурщина.

2) ох, не буду спорить, окей :) в любом случае, я не вижу каких-либо проблем с этим, стор все-равно один, и диспатч к нему один, и спускается он в контейнер в виде зависимости "снаружи", вроде норм
3) Ну редакс позиционируется отдельно от реакта, и, в принципе, идея мне очень по душе. Вон и в ангуляр портировали, и во вью используют (зачем-то)
4) Мы же все-равно все их используем
5) Либ нет, ибо никому (да-да хипстерам) это не нужно. Но я не зря написал, что реализация пишется на коленке. Простейший HOC.
6) Моднее не моднее, не знаю, не пью смузи гоняюсь за модностью. Танки удобны на туду-листах, шаг чуть дальше и вариантов 2 — саги и обзерваблы.
7) Может и зацепит, давайте. Но я уже потерян для общества, у меня уже выработалась патологическое отвращение к мутабельности :) Именно отсюда все эти линзы, призмы и ко. Ну а лучше, действительно, статью, прямо с полевой кухни.

> и обзерваблы

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

Выглядит неплохо. Но если вы собрались мапить стейт в UI, то стейт должен отражать иерархию интерфейса, что не очень. Если же у интерфейса своя компоновка то нужны селекторы, и мы получаем redux + reselect. Только стор в виде стрима "на scan'е".

> то стейт должен отражать иерархию интерфейса, что не очень.

Иерархию должен поддерживать «локальный» стейт. Вообще же суть идеи в том, что главная проблема современных фреймворков — разная модель работы с разными стейтами. Есть дом (вдом), есть локальный стейт (внутренний стейт компоненты), есть глобальный стейт (например, в виде редакса), есть эвенты, есть lifecycle-коллбеки компонент, есть роутер. И для всего для этого какие-то свои способы работы, которые по-разному реагируют на разные вещи. Хорошо видно, допустим, на примере ангуляра — вот у нас есть инпуты, когда вы поменяли инпут, то при чендж детекшоне все, что было в шаблоне с этим инпутом, обновится, то есть дом перестраивается за инпутами. А вот внутренний стейт компоненты — не перестраивается.
Или в реакте — компонент представляет ф-ю из локального стейта в вдом-стейт, но эвенты не входят в локальный стейт, по-этому мы не можем написать просто ф-и стейт -> стейт (стейт -> вдом в данном случае, т.к. нам именно этот кусок нужно нагенерить) и скомпозировать, нам надо делать через жо — вешать колбек на эвент и менять стейт, вместо какого-нибудь let $myComponent = $world.byComponent(myComponent); $myComponent.byElement(myButton).byType(Events.LeftClick).withLatestFrom($myComponent.byType(State)).map(([evt, state]) => ...).mergeTo(Render($myComponent))
главная проблема современных фреймворков — разная модель работы с разными стейтами.

В $mol такой проблемы нет, присоединяйтесь :-)

У вас в $mol есть общий глобальный стейт приложения (world), предоставляющий чисто функциональный интерфейс для взаимодействия? Не думаю.

$mol не про ФП. А при чём тут оно?

Тогда как решается проблема работы «по-разному» с разными «кусками» стейта? Как минимум, должна быть возможность одинаково работать с эвентами интерфейса и внутренним стейтом компонента. То есть, они должны быть представлены объектами, реализующими один и тот же интерфейс. Что это у вас за объект и что за интерфейс?

Интерфейс один — реактивные свойства (каналы ввода-вывода). Там по ссылке всё разжёвано же.

Там много непонятных картинок и мало кода. Хотелось бы увидеть следующие примеры:
1. Пользователь кликает по кнопке, некоторая существующая дом-нода удаляется (пусть сама кнопка и удаляется?)
2. Меняется локальный стейт (значение isHidden), дом-нода удаляется
3. Меняется глобальный стейт (значение isHidden), дом-нода удаляется
4. Срабатывает lyfecycle хук (если у ваших компонент они есть) — дом-нода удаляется

1 и 2 — одно и то же, ибо существование того или иного узла зависит от какого-то состояния.


$my_app $mol_view
    killed?val false
    sub /
        <= Hero $mol_button_major
            click?event <=> kill_me?event null

sub() {
    return this.killed() ? [] : [ this.Hero() ]
}

kill_me( event : Event ) {
    this.killed( true )
}

3 — глобальный от локального отличается только расположением. Например, изменим хранение killed с локального для компонента на localStorage:


killed( next? : boolean ) {
    return this.$.$mol_state_local.value( 'killed' , next ) || false
}

4 — Можно считать, что их нет, да. Компоненты лениво создаются по мере необходимости и автоматически уничтожаются, когда от них никто не зависит.

> 1 и 2 — одно и то же, ибо существование того или иного узла зависит от какого-то состояния.

Нет, не то же. Именно в том и соль, что во втором случае менять локальное состояние руками вы не должны, следует отреагировать на евент.

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

И, да, можно написать указанный код на чистом js? Я не знаю, как парсить ваши ребусы. И реализацию killed для первого случая еще хотелось бы увидеть.
Нет, не то же. Именно в том и соль, что во втором случае менять локальное состояние руками вы не должны, следует отреагировать на евент.

Вы уж определитесь, хотите ли вы единообразия или нет :-)


Естественно, руками можно все стейты смержить в один.

Зачем?


И, да, можно написать указанный код на чистом js?

Из того view.tree генерируется примерно следующий ts-класс:


export class $my_app extends $mol_view {

    @ $mol_mem()
    killed( val = false ) { return val }

    sub() {
        return [ this.Hero() ]
    }

    Hero() {
        return $mol_button_major.make({
            click : event => this.kill_me( event )
        })
    }

    kill_me( event : Event = null ) { return event )

}

$mol_mem — реактивный мемоизатор, сохраняет возвращаемое функцией значение в локальный стейт.

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


Реактивность же на изменяемых значениях принципиально рассматривает событие как нечто принципиально иное, отличное от состояния.

Ну да, у стримов есть только одно направление коммуникации. А у каналов — два. Логически-то в любом случае будет 2 направления движения данных и каждое со своими особенностями.

Причем тут канал? Разве click : event => this.kill_me( event ) — это канал?

Да.


Только затягивающий канал:


value : ()=> this.name()

Двусторонний канал:


value : next => this.name( next )

Двусторонний канал используемый только для проталкивания:


click : event => this.kill_me( event )
> Вы уж определитесь, хотите ли вы единообразия или нет :-)

Именно этого и хочу. В вашем же случае работы с эвентами и внутренним стейтом происходит неединообразно.

> Зачем?

Чтобы работать с ними одинаково.

> Из того view.tree генерируется примерно следующий ts-класс:

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

Единообразно. Разница лишь в направлении движения. стейт "затягивается", а ивенты (как и любые новые значения) "проталкиваются". На каком-то уровне (от локального, до глобального) "проталкивание" меняет состояние и далее оно уже "затягивается" в обратную сторону.


Ну вот вы руками мержите стейт — вешаете колбек на клик.

Ничего там не мержится. "проталкивание" ивента приводит к императивному изменению стейта.


Где там, кстати, сама логика сокрытия кнопки?

Вот же:


sub() {
    return this.killed() ? [] : [ this.Hero() ]
}
> Единообразно. Разница лишь в направлении движения. стейт «затягивается», а ивенты (как и любые новые значения) «проталкиваются». На каком-то уровне (от локального, до глобального) «проталкивание» меняет состояние и далее оно уже «затягивается» в обратную сторону.

Вот этот момент (где проталкивание меняет состояние) я и не хочу делать руками. Я хочу, чтобы «проталкивание» могло сразу менять результат рендера, дом.

> Вот же:

В примере выше — другой sub(). Кроме того — непонятно, где меняется само killed. Давайте вы уже целиком рабочий код приведете?

> Ничего там не мержится. «проталкивание» ивента приводит к императивному изменению стейта.

Вот это и есть тот самый «мерж», о котором я говорю. Вы делаете эвент куском стейта, и делаете это _руками_.

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

Где-то вам всё-равно нужно руками объяснить "глупому компьютеру", что вы хотите, чтобы кнопка пропадала по нажатию на неё. Сам он за вас эту логику не напишет.


Я хочу, чтобы «проталкивание» могло сразу менять результат рендера, дом.

Перепрыгивая все слои абстракции? А если эта кнопка рендерится в canvas или в ymaps? В реактивной архитектуре меняется только источник данных, а зависимые состояния обновляются на его основе. Вот расположение этого источника может быть разным.


В примере выше — другой sub().

Один класс генерится, другой его расширяет и добавляет логику.


Кроме того — непонятно, где меняется само killed.

Вот же:


kill_me( event : Event ) {
    this.killed( true )
}

Вы делаете эвент куском стейта

Да нет, ивент выкидывается, а стейт меняется. Это ж реакция. Странно называть это мержем.


Давайте вы уже целиком рабочий код приведете?

Давайте я вам лучше покажу пример с двусторонним биндингом:


export class $my_hello extends $mol_view {

    @ $mol_mem()
    name( next = "" ) { return next }

    @ $mol_mem()
    Name() {
        return $mol_string.make({ 
            hint : () => "Name" ,
            value : next => this.name( next ) ,
        })
    }

    message() {
        let name = this.name()
        return name && `Hello, ${ name }!`
    }

    sub() {
        return [ this.Name() , this.message() ]
    }

}

Результат: http://mol.js.org/app/hello

> Сам он за вас эту логику не напишет.

Конечно, не напишет. Однако, он может сам за меня смержить полный стейт.

> Перепрыгивая все слои абстракции?

Какое перепрыгивание? Рендер — просто ф-я из стейта в дом. Стейт изменился (кнопка нажата) дом перерендерился. Проблема в том, что по дефолту случившиеся эвенты не входят в стейт, в итоге приходится руками создавать кусок локального стейта и обновлять его в коллбеке на эвент. Вместо того, чтобы просто написать event => dom.

> Да нет, ивент выкидывается, а стейт меняется. Это ж реакция.

Сам факт того, что произошел эвент — _уже_ меняет стейт вашего приложения. Кнопка была нажата. По-этому, в принципе, не должно требоваться вводить и менять какой-то _дополнительный_ стейт.

> Один класс генерится, другой его расширяет и добавляет логику.

Я как должен догадаться, что у вас где генерится и чего меняет? Давайте вы уже напишите нормальный код, который будет полон, понятен и который можно будет обсуждать, а не какие-то куски, требующие прокачанного навыка чтения мыслей для понимания?
Вместо того, чтобы просто написать event => dom.

Вы, конечно, можете написать ваш event => dom :


sub() {
    return this.kill_me() ? [] : [ this.Hero() ]
}

Но это говнокод.


Сам факт того, что произошел эвент — уже меняет стейт вашего приложения.

Там много разных ивентов происходит. Далеко не все из них имеют смысл в моём приложении. event-based архитектура имеет кучу недостатков. Лучше иметь data-flow архитектуру.


Я как должен догадаться, что у вас где генерится и чего меняет? Давайте вы уже напишите нормальный код, который будет полон, понятен и который можно будет обсуждать

Это полный код приложения по ссылке. Что вам не понятно? Или вам исходники $mol_string и $mol_view ещё нужны?


Ок, давайте я добавлю коментов:


 // Компонент "приложение Привет"
export class $my_hello extends $mol_view {

    // Изменяемое свойство "имя"
    @ $mol_mem()
    name( next = "" ) { return next }

    // Поле ввода имени
    @ $mol_mem()
    Name() {
        return $mol_string.make({ 

            // задаём плейсходлдер
            hint : () => "Name" ,

            // двустороннее связывание значения поля ввода и имени
            value : next => this.name( next ) ,

        })
    }

    // Приветственное сообщение
    message() {
        let name = this.name()
        return name && `Hello, ${ name }!`
    }

    // Внутри приложения будут отображены поле ввода и приветственное сообщение
    sub() {
        return [ this.Name() , this.message() ]
    }

}
> Вы, конечно, можете написать ваш event => dom:

Это совсем не то, что требуется.

> Там много разных ивентов происходит. Далеко не все из них имеют смысл в моём приложении.

Ну так берите только нужные, какие проблемы?

> Это полный код приложения по ссылке.

Дайте полный код предыдущей задачи, я не знаю, что должен делать код приложения по ссылке.

Выводить приветствие, подставляя в него введённое имя.

> Ммм, но интерфейс-то функциональный, какая разница какая реализация

Итерфейс к стору — функция dispatch. А она не функциональная.

Редакс прекрасно типизируется. С type-guards типизируются редьюсеры. connect вообще-то типизированный, но с отвратительными тайпингами, которые не используют новые фишки Typescript вроде mapped types.

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

Типизация


Вдруг, кому пригодится.

Далее подразумевается, что используется Flow. Там, вроде бы, есть описания типов, но у меня не удалось их завести. Получилось многословно, но лучше так, чем вообще без. Делал как-то так:

Типизированные компоненты с Redux
// @flow

type AppState = {
  sample: string,
}

type MyDivAttrs = {
  stringProp: string,
};

type MyDivCbs = {
  funcProp: () => mixed,
}

type MyDivProps = MyDivAttrs & MyDivCbs;

class MyDiv extends React.Component<MyDivProps> {
  render() {
    const { stringProp, funcProp } = this.props;

    return (
      <div onClick={funcProp}>{stringProp}</div>;
    }
}

const mapStateToProps: (AppState) => MyDivAttrs = (state) => ({
  stringProp: state.sample,
});

const mapDispatchToProps: MyDivCbs = {
  funcProp: () => alert('Clicked')
};

export default connect(mapStateToProps, mapDispatchToProps)(MyDiv)



P.S. потерял веру во Flow, потому что на практике он оказался глючноватым. Вернее, не сам Flow, а сопутствующие средства разработки: опробовал WebStorm и VS Code с разным уровнем успеха. Последний некоторое время даже работал. Потом отвалился. Такие дела.
Что касается default exports, считаю это в целом плохим тоном, даже просто потому что потому неубодно это импортировать — нужно каждый раз давать названия которые по хорошему должны быть одинаковыми во всех точках импорта.

А что плохого в одинаковых названиях?

Дело как раз в том что при импорте из default модуля обычно нужно придумывать название импортируемому, и придумывают его по разному. То есть как раз названия не одинаковые получаются в коде. И авторифакторинг с default не всегда нормально работает.
export default class SpecificName

Может, недостаток не в самом импорте, а в том, что он может быть неименованным?

Для полноты картины каким образом потом это импортируется?

PS не уверен, но возможно default экспорты помимо прочего не тришейкятся нормально, просто предположение.
import SpecificName from './SpecificName'

Про ТриШейк, простите, не понял

> Про ТриШейк, простите, не понял

Вот первое что нагуглил сейчас github.com/webpack/webpack/issues/2866 То есть предположение похоже оправдалось, хз починили ли.

> import SpecificName from './SpecificName'

Здесь проблема что SpecificName вбивается руками (может IDE и заимпортирует, но руками его можно изменить на произвольное, так что по сути руками), вместо SpecificName можно вбить что угодно и это плохо. В случае именованного экспорта было бы {SpecificName} и здесь все однозначно, и аворефакторинг и ришейкинг сработает хорошо тк AST стандартно строится.

Ну, возможно вы и правы, тот дефолт, что есть сейчас в жс — Не очень.

Отличная статья, на news.ycombinator.com такому место если бы кто перевел на английский. Там любят срачи фреймвоков.
Я планировал сразу написать на английском, но не был уверен в востребованности. Переведу через некоторое время.

Переводите! Действительно, будет в тему

В нашей команде мы проспали вспышку, и вовсе, до сего момента, не использовали Angular 2/4. О чем не сожалеем. Когда с ним начали работать, первое что бросилось в глаза это CLI. Дальше были маты, но я люблю Angular 4, зачем было бы делать фреймворк, который уже существует. Каждый из них имеет свои плюсы и минусы, с этим вряд ли можно будет что-то сделать.

В целом клевая статья, добавил в закладки, буду использовать как справочник по фреймворкам.
При добавлении хорошей поддержки TypeScript в Vue этот Angular уже не нужен будет, так же как и React.
image
Ну правда же, ребята как будто академическую/дипломную работу пишут, а не фреймворк для людей :)
Именно. Меня впечатлила новаторская идея все построить на Rx.js / Zone.js: map, mergeMap, flatMap, switchMap, concatMap, exhaustMap,… — серьезно? Для индусов, пишуших энтерпрайз? Дорогие разработчики, вы в каком мире живете?
Проблема Ангуляра не в RxJS, а в том, что он используется там, где не нужно. В HttpClient например
> В HttpClient например

Вы так говорите, как будто в реальности кто-то использует HttpClient без кастомных оберток.
Мне кажется что вот это как раз не такая уж и проблема. Как говорят в армии — лучше пусть безобразно, но однообразно. Еще зоопарка там не хватало :) Беда в том что шпиговали, как китайскую утку, всем новым новым-вкусным, что нашли.
Что мешает не использовать RxJS и работать с данными как вы привыкли это делать ранее? Просто сделайте обёртку для преобразования ответа от http запроса в Promise.

RxJS он такой, как только его изучишь, хочется пихать везде :-)


Хотя в случае с HttpClient есть и польза: логика вида "в случае server/network error повторить запрос с таймаутом, но не больше трех раз" на Rx делается тривиально, а с промисами надо городить огород. Ну и с ngrx/effects удобно получается.

А могу ли я во vue отрендерить другой компонент в качестве хоста, накидав ему пропсов, без дополнительной dom-ноды?

Правильно сделали что проспали, даже древнючий AngularJS можно и сейчас нормально готовить. А потом неспеша перейти на чтот-то Vue подобное.

Да, вполне хватает.


Пока на работу доберешься ещё один фреймрок выйдет или очередная версия.

На самом деле осознанно не добавлял в список, т.к. это лишь надстройка над angular/material2.
Кстати весьма спорное решение, например с недавнего времени получилось, что есть два разных DataTable. Плюс ко всему ИМХО очень неудачные API.
Но надо признать, что на момент начала написания данной статьи, компонентов было гораздо меньше, так что работают ребята быстро.
Это костыль пока material.angular.io не вырастит.
Начал использовать недавно, ох и багучая поделка.
Умудряются в билды добавлять нерабочие imports, не тестируя.
Одно время использовал, но некоторые компоненты были исправлены своими руками.
Думал сменить.
Очень любил Angular и закрывал глаза на все его недостатки, пока не начал писать на React.

То же самое, первый Ангуляр любил до Реакта. Второй, правда, попробовал еще до Реакта и невзлюбил сразу.

Автор молодец.
Добавить нечего.
Полностью поддерживаю.
А как обстоят дела у Vue c server side rendering? Вот у Angular есть Universal.
Или progressive web apps? Тут есть Ionic.
C SSR дела обстоят отлично — NUXT, а Ionic — Weex
А я разве писал, что есть проблемы?
Просто тайпинги не идеальные, vue-class-component сторонний пакет (описания скоро доработают и откажутся от него) и из коробки webpack шаблон не поддерживает TS (но это тоже уже скоро).
Не первый раз читаю подобные статьи про Angular, React и некоторые другие фронтэнд фреймверки/либы (кстати про Vue пока такое не особо пишут, видимо только пока). Сам уже 4 года использую Ractive и вообще не понимаю этих проблем.
Идеального ничего нет… во всем можно найти недостатки… Но что реально есть, так это востребованность на рынке определенной технологии.
Это правда, есть некоторые вещи которые я бы и в Ractive изменил, но они скорее из разряда «Чувак а не ох*енел ли ты? Совсем ниче делать не хочешь». В остальном все круто. Лично для меня в Ractive 2 минуса: он могу бы быть быстрее и меньше размера (а может и не мог бы, хз), хотя даже так он быстрее многих других либ. Ну и он прям совсем не хайповый и известен по большей части за бугром. Хотя это может даже плюс.
Про ошибки в шаблонах, которые не отображаются при JIT-компиляции. Насколько я читал, разработчики ангуляра к пятой версии хотят сделать быстрые инкрементальные сборки для AOT и выпилить JIT совсем.
Почему-то комментарий добавляется не туда… предполагается к habrahabr.ru/post/337578/#comment_10409828

Это все здорово конечно, но печально сразу по нескольким причинам:
1. Я уверен, что иначе работающий AOT для многих будет просто новостью, да да не все знают про --prod.
2. Наверняка снова будет вагон Breaking Changes
3. Зачем постоянно делать плохо, чтобы потом исправлять? Может быть стоит чуток посидеть и подумать над архитектурой. Как никак не студенческая лабораторная.
1. Это действительно очень грустно, так как Angular запущенный в dev-режиме не устанет вам напоминать об этом в консоли, а самый простой способ от этого избавиться, используя Angular CLI, запустить с этим самым ключом. Ну и dev/prod-конфиги в папке environment должны наводить на какие-то мысли. Грустно, что разработчики использующие angular, не могут в документацию.
Я сам использую Angular с 2-rc.1 версии, когда никаким CLI еще не пахло, и уже тогда интересовался, как правильно производить prod-сборку. В официальной документации был и есть на это ответ, с полным описанием разницы между JIT и AOT.
2. По заверению разработчиков, не будет. Все, что скоро должно устареть, будет помечаться как deprecated и выводиться соответствующие оповещения об этом при сборке.
3. Я абсолютно не согласен с вами, что разработчики angular-а настолько плохие специалисты, что постоянно делают нам плохо. На мой взгляд, они создали наиболее удобный и универсальный фреймворк, благодаря которому fronted-разработка сильно упростилась и перестала походить на обмазывание BE-костяка скриптами и библиотеками. Да и вообще, большинство претензий как автора статьи, так и комментаторов мне абсолютно не понятны и попахивают вкусовщиной.

Ну и npm update не переведет ваш проект с 4 на 5 версию автоматически. Предполагается, что при смене мажорной версии, любой разработчик изучает changelog и советы по переходу на новую версию, а не делает это с закрытыми глазами на проде.
> Зачем постоянно делать плохо, чтобы потом исправлять?

Что исправлялось? Писать код в aot-compatible манере было рекомендовано задолго до релиза. А ошибки отображаются через language service, плагины для vsc и вебсторма есть.
НЛО прилетело и опубликовало эту надпись здесь
Похоже, вы просто не нашли времени познакомиться с TS и прочувствовать на себе преимущества статической типизацией. А если рассматривать сравнение с динамической типизацией, то выяснится, что у DT нет никаких преимуществ перед ST, кроме сомнительного «более низкий порог вхождения в ЯП».

Еще иногда на динамике быстрее и легче писать мелкие скрипты до ста строк.

Да, конечно, для небольших скриптов, типа *.sh, это подходит. Но я имел в виду разработку более серьезных приложений. Поэтому, раз уж заикнулся о преимуществах статической типизации, то вкратце их перечислю:

  1. вы всегда уверены что написанный метод и результаты его работы используется вами правильно;
  2. ошибки класса «сравниваем несравниваемое» или «пихаем невпихуемое» исключаются на стадии компиляции;
  3. после перехода на ST (например, при переходе с JS на TS) вы с большой вероятностью обнаружите, что таких ошибок у вас дофига; и даже не ошибок, а скорее досадных опечаток, которых ваш замылившийся глаз в упор не замечает;
  4. нет необходимости заниматься лишними проверками типов самостоятельно; вообще, переход на ST — это довольно дешевый способ повысить качество кода, особенно когда кодовая база растет быстро за счет большой команды;
  5. ваш IDE станет намного дружелюбнее по отношению к вам; а если вы все еще пишете в блокноте, то это дополнительный стимул перейти на IDE;
  6. рефакторинг перестает быть нудным и кропотливым занятием, после которого частенько появляются новые баги; поправив какой-нибудь метод вы не пропустите какое-нибудь место, где он вызывается в дебрях вашего проекта — компилятор услужливо вам напомнит;
  7. читабельность кода заметно повышается.
> Еще иногда на динамике быстрее и легче писать мелкие скрипты до ста строк.

Это вообще верно было пока нормально не проработали системы типов для динамических языков. Сейчас на том же TS 99% идиоматического js-кода прекрасно типизируется безо всяких проблем (разве что проблемы с прототипным наследованием, потому что его никто не изучал особо), а оверхед по объявлению типов — по факту нулевой.
Я не нашел? Может быть вы невнимательно читали, или это не совсем ясно из статьи (хотя я пытался) — я работаю с TypeScript несколько лет, с самых первых версий, еще когда он работал только в Visual Studio.
Это невероятно полезный инструмент, и я желаю всем его хотя бы попробовать. Я даже лекцию в одной очень известной российской конторе делал о нем…

Другое дело — его нужно использовать по назначению.
Команда Angular по какой-то причине этого делать не захотела.
Нет, я писал не вам, а отвечал на этот комментарий
Вот что происходит с проектом когда 20-30 разработчиков должны комитить что-то за зарплату, в относительно не большой проект, он превращатся в монстра. Непонятно зачем гугл вливает туда деньги, даже сам гугл этот ангуляр не использует*.

Вообще то использует.

После того, как пара основных разработчиков Angular ушли в свой стартап, не думаю, что в Google будет ставить на Angular в новых проектах.


И, кстати, недавно обновленный Youtube теперь на Polymer. Кажется, именно Polymer это новый фаворит Гугла

Гугл использует ангуляр для внутренних сервисов.

А есть актуальная информация 2017 года? Все что я видел уже устарело как минимум на год.

например, основные разработчики ангуляра покинули Гугл. Как вы думаете, это могло не сказаться на технологиях внутри компании?

Не за год, конечно же. Это же не твиттер какой-нибудь. Уход разработчиков тут разве что лет через пять может сказаться.

изначально тред был об этом:


Непонятно зачем гугл вливает туда деньги, даже сам гугл этот ангуляр не использует

Поэтому я и спросил что нового запустил Гугл на ангуляре в этом году. Кажется, что ничего такого нет.
Получается, что гугл не развивает ангуляр и вливает туда деньги, а просто поддерживает, чтобы уже запущенные проекты были на плаву.

Ну так в итоге мы выяснили, что гугл ангуляр использует. Потому и деньги вливает. А то, что «просто поддерживает» — вроде не новость, второй ангуляр изначально был заточен под кровавый тырпрайз, а это на 90% и есть поддержка существующего. Весьма странным выглядит ваше удивление, что утка крякает.

А еще Гугл использует GWT. Но сказать, что он туда вливает кучу средств не получится.


Вот еще пример: конференция Angular Summit, и Гугла там в спонсорах нет.
Зато на Polymer Summit это по сути единственная представленная компания. Мне кажется, что вывод, куда сейчас вкладываются PR-средства, очевиден.

> А еще Гугл использует GWT. Но сказать, что он туда вливает кучу средств не получится.

А в ангуляр вливает? Насколько больше?

> Вот еще пример: конференция Angular Summit, и Гугла там в спонсорах нет. Зато на Polymer Summit это по сути единственная представленная компания.

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

Почему вы не упоминули DevExtreme UI framework? Мы его в работе используем. В целом хватает пока хватает.
Оно не бесплатное и не полностью опенсорсное.
Все дело в коммунити. Вот если в js появился spring из java иди .net mvc из c#, то я уверен, что 90% выбрали бы jQuery или vue. Но это же не говорит что с spring и .net mvc что-то не так.

Кроме того из всего перечисленного реальные неудобства могут доставить только большой стек при ошибках и возможно неправильно настроенный cli. Сейчас пишу проект сгенерируемый с помощью angular-cli, так мне кажется что предыдущие проекты, которые я настраивал самостоятельно, пурусобирались значительно быстрее. И если это действительно так, то это обычная проблема. Если посмотреть большинство генераторов, то они все собраны, мягко говоря не так как хотелось бы.

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

И если меня что-то раздражает, я свое пишу, это очень помогает отвлечься и способствует развитию.

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

Проблема начнется, когда проект станет немного больше и вообще перестанет собираться с out of memory :)
Люблю такие статьи, всегда есть что новую почерпнуть, к тому же это точный маркер того что, у обсуждаемой библиотеки все хорошо в плане ЖЦ, vue.js ждет тоже самое, дайте ему время.
Лично у меня за время что angular доступен и его текущей реализации, складывается ощущение что они «не много не рассчитали».
> довольно скудное количество готовых наборов UI компонентов
И это ещё мягко сказано! В основном в коробке идёт красивая анимированная пальце-тыкательная хромая замена стандартным контролам браузера (которая хорошо если на 50% покрывает возможности стандартных — далеко не везде есть нормальная навигация с клавиатуры, tabindex, ARIA-фичи и т.п.). Время идёт, а готовых комплексных решений для нагруженных интерфейсов не появляется, хотя npm завален гридами разной степени кривости. Да, инструмент гибкий, бери и пиши — но я не готов писать ExtJS или хотя бы что-то вроде EasyUI самостоятельно.
UniGUI, потолок вхождения около нуля. И гриды и чарты и кнопки.
далеко не везде есть нормальная навигация с клавиатуры, tabindex, ARIA-фичи и т.п.

Вообще нигде нет. Dojo 1 пыталось быть сколько-нибудь доступным, но ниасилило, а больше никто даже не пытался. Accessibility это очень трудно и больно, я вам как доктор говорю. :(

В основном в коробке идёт красивая анимированная пальце-тыкательная хромая замена стандартным контролам браузера

Вы наверное про Angular Material 2? Но она не совсем в коробке, просто Google продвигает данную тему (Material Design) и поэтому рекомендует по-умолчанию. На самом деле UI систем много, часть из них перечислены тут angular.io/resources в разделе UI Components. Рекомендую приглядеться к Semantic UI, Clarity Design System и Prime NG.

Я лично чаще всего использую голый bootstrap.css без bootstrap.js/jQuery (4 версия наконец-то собирается из SCSS, что делает более простой сборку с помощью Angular CLI).
НЛО прилетело и опубликовало эту надпись здесь
Реакт — такое я никогда не приму и не пойму.

А что не так?

Не ОП, но рискну предположить, что сам вид этой дикой белибердической смеси псевдо-JavaScript с псевдо-HTML вызывает рвотные позывы у людей, чьё чувство прекрасного не забито в кровавую тряпочку годами самобичевания с PHP?

НЛО прилетело и опубликовало эту надпись здесь

Можно продолжать уходить в минуса, а можно наконец-то рассказать, в чем именно проблема с JSX, кроме слепого следования карго-культу "разметка отдельно от логики".


Какие проблемы решает ко-локация html и стилей в js-файлах уже не раз обсуждалось.

НЛО прилетело и опубликовало эту надпись здесь

Обжегшись один раз, вы дуете на воду. То, как JSX встраивает html в JS-код не имеет ничего общего с текстовыми файлами на PHP. Хотя бы потому, что в JSX вы не можете открыть тег и не закрыть его. У JSX строгий синтаксис, который не позволит вам наделать нелепых ошибок в разметке.


Некоторое время назад я выложил статью со своим мнением про JSX, может быть вам будет интересно.

> Хотя бы потому, что в JSX вы не можете открыть тег и не закрыть его. У JSX строгий синтаксис, который не позволит вам наделать нелепых ошибок в разметке.

Проблема с генережкой html-разметки в PHP никогда и не имела ничего общего с незакрытыми тегами и нелепыми ошибками, проблема была в том, что код неизбежно превращается в невнятную помесь какашек.

По-этому реакция на JSX у подавляющего большинства людей, имеющих серьезный опыт работы с PHP — вполне ожидаема и закономерна. Особенно, когда они видят _реальный_ JSX-код (из реального приложения, а не из примеров) и понимают, что, да, первое впечатление не обмануло — это PHP в худших его проявлениях, как выше сказали — привет из 90-х, все ровно так, будто одел старый разлезшийся свитер.

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

Ну ок, на JSX можно писать говнокод. В разделенном HTML/JS тоже можно.


Однако хорошо оформленный JSX удобнее, чем пара JS+шаблон.


Если вам так не кажется, то ок — ваше дело. Но писать комментарии в формате "страдайте глупцы" — точно не стоит.

> Однако хорошо оформленный JSX удобнее, чем пара JS+шаблон.

Можно увидеть этот самый «хорошо оформленный JSX»? Чтобы там не было кучи ненужных мелких компонент (сильно затрудняющих восприятие разметки в целом) или чего-нибудь вот такого:
{!isHidden && (
  <ul>
    {items.map((item, i) => (
      <li key={i}>{item}</li>
    )}
  </ul>
)}

и проблема здесь не в самом факте перегруженности синтаксиса, к синтаксису можно было бы привыкнуть, если бы не одно «но»: в случае с шаблонизатором обычно есть один ясный и понятный способ решить задачу, которую решает данный кусок кода. Вы возьмете 10 программистов и вам 10 напишут одинаково. В случае с JSX — каждый, блин, напишет как-то по-своему.

Здесь я вам ничего нового не расскажу. Нормальная разметка, как по мне.


В Handlebars будет примерно так же


{{#unless isHidden}}
  <ul>
    {{#each items}}
      <li>{{title}}</li>
    {{/each}}
  </ul>
{{/unless}}

На AngularJS будет чуть покороче


<ul ng-if="!isHidden">
  <li ng-repeat="item in items">{{item}}</li>
</ul>

Но есть и обратная сторона: здесь смешали html и управляющие конструкции. Если на <li> навесить еще class, ng-click, то потом будет сложно беглым взглядом найти ng-repeat. Поэтому очень сомнительная польза от компактности

> Но есть и обратная сторона: здесь смешали html и управляющие конструкции.

В варианте на JSX смешали не просто html и управляющие инструкции, а html и большее подмножество JS.

> Если на навесить еще class, ng-click, то потом будет сложно беглым взглядом найти ng-repeat.

ng-repeat как раз будет отлично виден всегда — именно потому, что это одна из немногих управляющих конструкций. Она всегда выглядит одинаково и используется одинаково. В случае же jsx глазу вообще не за что зацепиться — вам надо распарсить полностью произвольный js код (что на порядок сложнее, чем вычленить один токен) и понять его семантику. Понимаете, в чем разница? Это очевидное преимущество специализированных решений над универсальными. JS — универсальный язык, и он откровенно плох в генерации представления для разметки, потому как никогда для этого предназначен не был, JSX улучшает картину, но несущественно. Шаблонизаторы — лучше, потому что они специально заточены для построения представлений конкретного вида. Именно по-этому даже PHP выигрывает у JSX по удобству описания разметки. Он для этого предназначен, он для этого был спроектирован. JSX — нет.
А у меня в проекте встречается даже такой код, и мне от этого немного грустно:

Кака
render() {
  const { prop1, prop2, prop3, prop4 } = this.props;
  
  return (
    <div>
      {/* a large bunch of markup */}
      {/* and we got this at nesting level ~6-8 */}
      <SomeComponent
        config={{
          attr1: 'attribute 1',
          attr2: 'attribute 2',
          attr3: 'attribute 3',
          attr4: {
            subattr1: prop1,
            subattr2: prop2
          }
        }}
      >
      </SomeComponent>
}



А ещё половина кода использует styled components, а половина — scss. И целая горка других проблем и нюансов.

Из-за этого немного смотрю в сторону vuejs (как минимум, не будет styled component и scss каши), но проектов таких пока в наш офис не заходило.

А как вам вот такой вариант:


<If condition={!isHidden}>
    {() => {
        <ul>...</ul>
    }}
</If>

Или вот такой:


{IF(!isHidden, () => {
    <ul>...</ul>
})}

Мне интересно, чем можно разбавить JSX чтобы он смотрелся не как набор js-хаков.


Или необходимость этих () => { ... } все портит?

> А как вам вот такой вариант:

Вы невнимательно прочитали мой пост. Я же специально указал — проблема не в кривом синтаксисе _самом по себе_. Он не очень, но к любому синтаксису привыкаешь. Проблема именно в наличии «а как вам вот так» — в том, что одно и то же можно сделать по-разному. Когда мы работаем с шаблонизатором, то мы видим перед собой уже практически готовую верстку, в которой глаз сразу ухватится за некоторые выделенные токены (вроде ng-repeat), то есть это html + добавка. В случае с JSX мы имеем дело с js + добавка, что на порядок сложнее для разбора. Чтобы понять, что сгенерирует js-код — ну, надо разобрать этот код, понять, что он нагенерит. В случае шаблонизатора — вам и не надо ничего разбирать, вы уже довольно-таки точно видите, что получится в итоге. Шаблонизаторы именно потому хороши, что они используют возможности html, а никто лучше html языка для описания dom не придумал. JS ему сильно в этом проигрывает, именно в силу своей универсальности.

Но вот только в ПХП был серверный код бизнес-логики вперемешку с HTML.


Дело не в JSX, конечно же. Есть несколько альтернатив ему, в том числе, и весьма похожие на шаблонизатор Ангуляра, которые позволяют писать как бы HTML, и компилировать его в вызовы createElement.


Но их никто не использует. Потому что настоящая мощь Реакта — в том факте, что компоненты — это обычные JS объекты. Я не устаю писать это в каждом комментарии в сраче о JSX.


Шаблон Ангуляра — это, конечно, похоже на ХТМЛ (особенно, если ты видел пример из getting started и не видел реальный production код). Но это все-равно строка.


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


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

> Но вот только в ПХП был серверный код бизнес-логики вперемешку с HTML.

Ну так в SPA у вас тот же код, который раньше был серверным, теперь на клиенте.

> Но их никто не использует. Потому что настоящая мощь Реакта — в том факте, что компоненты — это обычные JS объекты. Я не устаю писать это в каждом комментарии в сраче о JSX.

Так их никто не использует, потому что реакт плохо с этим работает. Он заточен под пехепешную модель, т.к. создавался для портирования php-кода на js.

> Шаблон Ангуляра — это, конечно, похоже на ХТМЛ (особенно, если ты видел пример из getting started и не видел реальный production код). Но это все-равно строка.

Во втором ангуляре шаблоны компилируются в js-объект, точно так же, как jsx.

> А вот как взять потомков одного типа, и склонировать их для каждого элемента массива и отрендерить в отдельное место?

Легко догадаться, что так делать не надо. Надо описать модель данных, в которой будет «взять, склонировать» и что там еще надо, а потом по этим данным, используя примитивные операции, нагенерить вьюху. В итоге в одном месте вы работаете с чистыми данными (ничего не зная о дом), а в другом — примитивным образом их визуализируете. JSX, как видно, стимулирует мешать все в одну невнятную кучу, да еще и предлагает этот баг в виде фичи.
Ну так в SPA у вас тот же код, который раньше был серверным, теперь на клиенте.

С чего бы это серверному коду быть на клиенте? Да и каким образом это возможно, ПХП выполнялся на сервере, реакт и другие — на клиенте. Он при всем желании не полезет в базу, не прочтет файл с диска на сервере и т.п.


Легко догадаться, что так делать не надо.

Знаете, я был практически уверен, что вы скажете "зелен виноград".
Так делать не хочется, пока не попробуешь :) Но это же мощнейший инструмент, который позволяет кучу задач (особенно при разработке библиотек и компонентов) решить изящным способом.


По сути, это и есть полноценная композиция компонентов, а не огрызок, как в Ангуляре.


Во втором ангуляре шаблоны компилируются в js-объект, точно так же, как jsx.

Совсем не так же. В Реакте можно оперировать результатами там же, в коде, то есть это по сути другой вид записи. В Ангуляре результат компиляции коду компонента не доступен.

Про PHP (ну, то есть, не совсем PHP): XHP :-)

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

В реакте нет html в javascript. или , это обычные объекты, которые если и создают разметку за кулисами, то только потому, что являются частью шаблонизатора. То есть, .jsx, это всего навсего указания шаблонизатору в декларативном стиле. Тем более, если Вы такой старый, а значит, должны быть опытный, то ваши слова идут Вам в минус, так как Вы не осознаете что js это ТОЖЕ представление. Компоненты это часть представления и логика которая в них присутствует, является логикой представления. И можно было бы продолжать до бесконечности, но не нашлось бы даже пикселя, который лег на чашу в поддержку Вашего мнения. Кстати в angular представление тоже за счет js генерируется и это вполне нормаль. Те кто рвал горло раньше, что js это логика, он просто не понимал чего именно, так же как серверисты рвут глотки что у них в обычных приложениях mvc на сервере.

Всё клиентское приложение — это представление. И в этом самом представлении стоит разделять html-шаблоны от программной логики. По куче причин. Основная — шаблоны вперемешку с логикой теряют своё основное назначение — возможность буквально видеть результат результат. Без этой возможности шаблоны не нужны и можно просто фигачить объекты, без подражания HTML-у.

возможность буквально видеть результат результат

ну бросьте, ng-repeat вам ничего "буквально" не покажет, придется включить мозги. Какая разница тогда ng-repeat или map?


Без этой возможности шаблоны не нужны и можно просто фигачить объекты, без подражания HTML-у

Бинго!

Разница в том, что если не знать про ng-repeat — то останется валидная разметка с одним элементом в списке. А если не знать про map — то в разметке останется какая-то фигня.

В "разметке" останется JS. Чистый, обычный и валидный

Что человеку, новичку в JS не сильно помогает.

> В «разметке» останется JS. Чистый, обычный и валидный

Который надо в уме исполнить, чтобы понять, чего этот JS нагенерит. А в случае с ng-repeat я сразу вижу готовую ноду, потом надо только отметить, что: «ага, эту ноду размножить, раз там ng-repeat». К слову, таких директив в ангуляре всего-то пара штук (то есть легко запомнить), а сколько есть разных вариантов записи для аналогов for/if в JSX? Да десятки.

В JSX я вижу не ноду, а преобразование — список айтемов преобразуется в список нод, мы всегда отталкиваемся от данных.


В ангуляре-то пара, а кастомных в природе сколько?


для for есть единственный вариант — map
для if — && и тернарник, не так уже и много

> В JSX я вижу не ноду, а преобразование — список айтемов преобразуется в список нод, мы всегда отталкиваемся от данных.

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

> для for есть единственный вариант — map
для if — && и тернарник, не так уже и много

Ага, конечно. Только вот есть те же «а-ля шаблонизатор», есть сдабривание iife, есть просто подергивание каких-то методов (которые хрен его знает, что могут возвращать, пока не посмотришь, а потому факт наличия цикла вы сразу и не сможете определить).

> В ангуляре-то пара, а кастомных в природе сколько?

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

Ну нет же, я ж написал уже, ng-repeat — не результат. А то, что он "проще для восприятия" (что спорно, учитывая безумный dsl внутри аттрибута), не делает его лучше.
Не знаю, может, я уже потерян для общества, но я не вижу ни единой проблемы в map, он ровно ничем идеологически от ng-repeat не отличается. А то, что вам гибкости больше дается стандартными средствами, ну, не знаю, по мне так это преимущество.


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

Но я ж не знаю, что там скрыто в ней? Придется "выполнить ее в уме" :)


Ага, конечно. Только вот есть те же «а-ля шаблонизатор», есть сдабривание iife, есть просто подергивание каких-то методов (которые хрен его знает, что могут возвращать, пока не посмотришь, а потому факт наличия цикла вы сразу и не сможете определить).

Вы же в коде на это не жалуетесь. А для "посмотреть, что вернет" есть TS и IDE. А факт наличия цикла мне и не нужно определять, особенно, если он спрятан в методе или вообще в подкомпоненте.


А чтобы увидеть картину в целом, есть инструменты, например react dev tools, отрисовывающие дерево компонентов вперемешку с DOM. Так что это не проблема JSX. Вы же джавовый байт-код руками не сканите ради "общей картины".


А вообще, мне кажется, мы плавно подходим (и кажется, что опять) к проблеме, которую symbix озвучил ниже — любому внятному верстальщику рано или поздно придется апгрейдиться до разработчика. А в этом случае, использование одного языка вместо кучи спорных dsl только на пользу.

"проще для восприятия" (что спорно, учитывая безумный dsl внутри аттрибута

ng-repeat качественно ничего не меняет по сравнению с результатом. Только количественно. Поэтому его можно просто игнорировать, когда не важно число повторов.


я не вижу ни единой проблемы в map, он ровно ничем идеологически от ng-repeat не отличается

Эти два варианта тоже ничем не различаются?


`Hello, ${name_prefix} ${name}!`

"Hello, " + name_prefix + " " + name + "!"
Эти два варианта тоже ничем не различаются?

А какое это отношение имеет к ng-repeat/map?

Очевидно же, первый вариант — это использование шаблонизатора (ng-repeat), а второй — универсальных инструментов, предоставленных хост-языком (map). Кстати, хороший пример :)

Эээ, строковые темплейты — фича языка.

Зачем же её ввели, если всё это можно делать и обычным ES5?

Это специальный ДСЛ для того, чтобы генерить строки. Ничем не отличается от специального ДСЛя для того, чтобы генерить дом :)

Да, только это DSL в комплекте с языком, а не со сторонним двиглом, вот и вся разница.

> Ну нет же, я ж написал уже, ng-repeat — не результат.

Конечно, результат. Вы смотрите и видите, какая нода получилась. А потом, увидев ng-repeat, понимаете, что там не одна она такая, а их много. гляда на произвольный js-код в JSX вам надо в уме выполнить этот код, чтобы получить ту информацию, которая вслучае шаблонизатора есть _сразу_.

> Но я ж не знаю, что там скрыто в ней? Придется «выполнить ее в уме» :)

Только вот кастомные структурные директивы встречаются в ангуляре примерно раз на несколько тысяч строк. Насколько часто в JSX встречаются кастомные функции? :)

> Вы же в коде на это не жалуетесь.

Потому что код предназначен для другого. Код потому и пишется на тьюринг-полном языке со всякими встроенными свистоперделками, что массив задач, который может решаться при помощи этого кода — очень большой и задачи очень разные. Код шаблона же (или jsx) решает очень узкую задачу (и только одну) — генерация представления дом-дерева (кусков дом-дерева) во вполне конкретном и четко определенном формате.
Это, например, как конечные автоматы. Вы можете написать конечный автомат на любом тьюринг-полном языке (на том же js), но на практике предпочитаете пользоваться узким и специально заточенным языком (регекспами), который специально для описания КА и предназначен.
Только вот кастомные структурные директивы встречаются в ангуляре примерно раз на несколько тысяч строк. Насколько часто в JSX встречаются кастомные функции? :)

Зависит от кода. И директив бывает столько, что в глазах рябит и функций. Хотя вот функций обычно меньше, обычно это просто компоненты. Так как можно отрендерить в качестве хоста дру… а, вы знаете, что там дальше.
Ну и получается, что с директивами все-равно нужно маркап прогонять в уме, так что все "преимущества" ng-repeat теряются.

> Зависит от кода. И директив бывает столько, что в глазах рябит и функций.

Это можно пример такого кода?

> Ну и получается, что с директивами все-равно нужно маркап прогонять в уме

Раз в несколько тысяч строк — нужно. В остальное время — не нужно :)
Это можно пример такого кода?

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


Раз в несколько тысяч строк — нужно. В остальное время — не нужно :)

Нет, так не честно. Либо прогоняем, либо нет.

> Нет, так не честно. Либо прогоняем, либо нет.

На практике важен не сам факт того, что прогоняем, а как раз то, насколько сложно это и как часто приходится делать :)

> Что там делают эти магические атрибуты, черт знает.

Будете смеяться — но ничего не делает :D
И я, блин, серьезно — правда ничего (в плане перестройки dom-дерева).
На практике важен не сам факт того, что прогоняем, а как раз то, насколько сложно это и как часто приходится делать :)

На практике и map с первого раза в голове оседает. Знаю о чем говорю :)


Будете смеяться — но ничего не делает

По идее по ним там выборка какая-нибудь идет через @ContentChildren какой-нибудь. То же сами кстати, что и распарсить this.props.children, только на своем велосипеде.

> На практике и map с первого раза в голове оседает. Знаю о чем говорю :)

Я же говорил — не было бы беды, если бы там ВСЕГДА был map. Но там произвольный js-код. Если ограничить JSX каким-то вменяемым подмножеством JS — он будет вполне ок. Проблема именно в том, что там может использоваться ВЕСЬ JS.

> По идее по ним там выборка какая-нибудь идет через @ContentChildren какой-нибудь.

Но именно атрибуты — ничего не делают, то есть это просто темплейт, в который потом на места let-атрибутов подставляются значения из контекста (контекст применяет уже внешняя директиваб ngx-datatable).

И на самом деле (кстати) это и есть рассахаренный «звездочковый» синтаксис
<ng-template let-row="row" let-value="value" ngx-datatable-cell-template>
            My name is: <i [innerHTML]="row['name']"></i> and <i>{{value}}</i>
            <div>{{joke}}</div>
          </ng-template>

->
<ng-container  *ngx-datatable-cell-template="let row=row; let value=value">
    My name is: <i [innerHTML]="row['name']"></i> and <i>{{value}}</i>
    <div>{{joke}}</div>
</ng-container>

примерно как-то так

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


{function() {
  const result = [];
  for (let i = 0; i < items.length; i++) {
    const item = <li>{items[i]}</li>;
    result.push(item);
  }
  return result;
}()}

С тем же успехом можно подобной ерунды и на любом DSL наколбасить.


И на самом деле (кстати) это и есть рассахаренный «звездочковый» синтаксис

Да это-то понятно, просто вот вам и пример, что в этом "строгом DSL" тоже есть несколько путей для реализации. Причем первый еще ладно, второй — совсем же дичь, всевдокод внутри строки, о боги :)

> Естественно, варианты из серии следующего — бред и не принимаются:

Почему не принимаются? И это только один из вариантов. Кроме map могут быть другие варианты преобразования (к списку может быть прихреначен и какой-нибудь фильтр там же, и список может как-то хитро строиться, и map у вас может быть какой-то свой, и вообще это все может быть в похожем на директивы варианты — куча вариантов, в общем).

> Да это-то понятно, просто вот вам и пример, что в этом «строгом DSL» тоже есть несколько путей для реализации.

На самом деле не совсем. Мой вариант со звездочкой неточен, т.к. на самом деле раскроется в:
<ng-template let-row="row" let-value="value" ngx-datatable-cell-template>
    <ng-container>
        My name is: <i [innerHTML]="row['name']"></i> and <i>{{value}}</i>
        <div>{{joke}}</div>
    </ng-template>
</ng-container>

звездочковый эквивалент тут не написать. Возможно, именно по-этому и выбран рассахаренный вариант :)

> второй — совсем же дичь, всевдокод внутри строки, о боги :)

Он не внутри строки :)
Почему не принимаются?

Потому что это чушь же :) Хреновая верстка на голом html от аутсорсера/фрилансера может быть такого же градуса бредовости. Если не хуже


звездочковый эквивалент тут не написать. Возможно, именно по-этому и выбран рассахаренный вариант :)

Ну то есть можно так, а можно этак


Он не внутри строки :)

Строки, строки, аттрибуты — строки.

> Потому что это чушь же :) Хреновая верстка на голом html от аутсорсера/фрилансера может быть такого же градуса бредовости. Если не хуже

Вы опять уходите в сторону обсуждения принципиальной возможности чего-то, когда на практике важна именно количественная оценка. Следуя вашим рассуждениям — неплохо писать на брейнфаке. Потмоу что по факту любой аргумент против брейнфака применим и к другим языкам. Просто в меньшей степени. Иногда — в намного меньшей :)

> Ну то есть можно так, а можно этак

Ну какбы нельзя :)
И даже если бы было можно — опять возвращаемся к количественной оценке.

> Строки, строки, аттрибуты — строки.

Ну нет. Не будет там нигде строки «let value blablabla»

А изменение коллекции @ContentChildren как-то повлияет на содержимое компонента?

Это неизменяемая коллекция. Точнее, это скорее observable. То есть сама она может измениться (если поменяется содержимое компонента), но поменять ее напрямую нельзя.
Конечно, результат. Вы смотрите и видите, какая нода получилась. А потом, увидев ng-repeat, понимаете, что там не одна она такая, а их много. гляда на произвольный js-код в JSX вам надо в уме выполнить этот код, чтобы получить ту информацию, которая вслучае шаблонизатора есть сразу.

Ну так вы когда джаваскрипт код читаете, вы его в уме выполняете? С JSX все так же.

> Ну так вы когда джаваскрипт код читаете, вы его в уме выполняете? С JSX все так же.

Ттак я и говорю о том, что JSX проигрывает шаблонизаторам из-за того, что приходится выполнять в уме JS-код.

Более того, map — это джаваскрипт, npRepeat — это микроязык, свой для каждой директивы.

> Более того, map — это джаваскрипт, npRepeat — это микроязык, свой для каждой директивы.

Именно. По-этому ngRepeat значительно проще и удобнее.

Вот и нет, потому-что один раз сесть и выучить, что такое map — проще и удобнее, чем обмазываться кастомными микроязыками.

Только вот выучить map недостаточно, надо выучить весь js. И это намного сложнее, чем выучить три с половиной директивы :)

Ну как же недостаточно, я ж сравнивал уже выше, ng-repeat — это map, ng-if — && и ?:
Как же сложнее?

Если ограничить JSX так, что другого способа написать эти конструкции в принципе не будет (вообще), то не сложнее. Тогда JSX станет тем же дслем, только с другим синтаксисом.

Думаю, что можно будет как-нибудь сесть за tslint и написать подобных правил. Добавлю в бэклог

Ну да, Реакт — он для программистов. Впрочем, утверждение, что шаблоны Ангуляра будет делать верстальщик — это, скажем так, самообман.

Давайте так —
  1. у Вас есть шаблонизатор, который генерирует html. Шаблонизатор, как любой другой современный шаблонизатор, имеет расширенный синтаксис foreach ifelse и так далее.
  2. теперь представьте что шаблонизатор настолько продвинут, что позволяет разработчику расширить и так расширенный синтаксис
  3. теперь представьте что Вы можете создавать композиции из расширений шаблонизатора, как например использование if в for
  4. теперь представьте что шаблонизатор это реакт-элементы, которые в реальности обычные объекты
  5. теперь представьте что реакт-компоненты это механизм создания пользовательских расширений шаблонизатора


А теперь скажите, какой по Вашему пункт не верен? К сожалению из-за минусов я могу оставлять коменты только раз в день, не обессудьте, я продолжу.

Если Вы опять упретесь, что логика в компонентах, то простите меня за настойчивость, какая? Собрать композицию из компонентов, которые являются частью представления? Это по Вашему логика не представления? Или сетевые запросы и бизнес логика? Если да, то простите меня за грубость, какой дурак её там пишет?

Вам доводилось создавать интерфейсы (читать представления) c#? jаva? canvas?
flex? С чем Вы сравниваете, говоря о правильности компонентов? Мое мнение основано на выше перечисленных технологиях.
> теперь представьте что шаблонизатор настолько продвинут, что позволяет разработчику расширить и так расширенный синтаксис

Смысл шаблонизатора (как и любого ДСЛя или узкоспециализированного инструмента) ИМЕННО в том, что он ограничен в возможностях. Мы платим универсальностью за более удобное решение задач из узкого класса. Если вы делаете шаблонизатор универсальным — основное преимущество (ограниченность) сразу теряется.

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

> То-то в рамках этих ограничений стало тесно, и тут же придумали наикостыльнейшие пайпы!

Какая теснота? Смысл пайпов исключительно в том, что они бывают pure, и в этом случае пересчитываются только тогда, когда изменится аргумент. Такого поведения затруднительно достичь, не замусорив код, это надо реализовывать на уровне компилятора шаблонов.
В противном случае (при отсутствии pure) пайпы были бы совершенно не нужны и ничего бы не давали, можно с тем же успехом дергать обычные функции.
В противном случае (при отсутствии pure) пайпы были бы совершенно не нужны и ничего бы не давали, можно с тем же успехом дергать обычные функции.

Не понял, pure это в кривых реактовских терминах pure? Типа аргумент не меняется, пайп не пересчиваем? Так, казалось бы, почему шаблонизатор должен этим заниматься? Его задача вывести значение, а не накручивать пайплайн преобразований для этого значения. Для этого есть язык, и именно поэтому можно (и нужно) и обычные функции мемоизировать в рамках языка и дергать их с тем же успехом. А если смешивать эти вещи, то вам и шаблонизатор уже не нужен, у вас JSX получился

> Не понял, pure это в кривых реактовских терминах pure? Типа аргумент не меняется, пайп не пересчиваем?

Значит, чистая функция. В ФП-смысле — без сайд-эффектов, результат зависит только от аргумента.

> Для этого есть язык, и именно поэтому можно (и нужно) и обычные функции мемоизировать в рамках языка и дергать их с тем же успехом.

Это не будет работать внутри шаблонов. И там речь не о мемоизации. Если аргумент не изменился — пайп просто не запускается, а дом не перестраивается. Это внутренность алгоритма чендж-детекшона и «снаружи» такое поведение, фактически, не получить.
Значит, чистая функция. В ФП-смысле — без сайд-эффектов, результат зависит только от аргумента.

Ну прекрасно, я ж не спроста переспросил. Чистые функции можно и просто дергать.


Это не будет работать внутри шаблонов.

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


И там речь не о мемоизации. Если аргумент не изменился — пайп просто не запускается, а дом не перестраивается. Это внутренность алгоритма чендж-детекшона и «снаружи» такое поведение, фактически, не получить.

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

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

И тогда он будет вызван.

> Если аргумент мемоизированной функции не меняется, возвращается предыдущее значение, а ее тело не запускается заново, такое же ж поведение.

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

И вернет предыдущее значение для известного аргумента, если он мемоизирован. Средствами языка


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

Это детали реализации мемоизирующего декоратора (раз уж мы про методы, то декоратора), а внутри есть доступ к инстансу компонента. Можете там хоть одноуровневый кэш устроить.


А в случае мемоизации — будет. На кучу списков.

Храните-то вы ссылки на эти списки, так что все норм.

> Храните-то вы ссылки на эти списки, так что все норм.

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

Нет, так как, если вы устраиваете хранилище на инстансе компонента, то это хранилище уничтожится при его анмаунте. И нет больше слез утечек

> Нет, так как, если вы устраиваете хранилище на инстансе компонента, то это хранилище уничтожится при его анмаунте.

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

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

> Ну вы же этот грид видите на странице

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

> Более того, в пайпах так же должна храниться ссылка на входящий аргумент

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

Почему мильон? Мы ж про одноуровневый кэш.


Например, я применяю разные фильтры, убираю/добавляю строки, редактирую где-то что-то. В итоге грид меняется, каждый раз вызывается ф-я преобразования (которую мемоизируем), каждый раз она сбрасывает значения в кеш.

Так и пайп будет каждый раз перезапускаться


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

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

> Совершенно без разницы, где хранится предыдущее значение, оно все-равно хранится

Оно хранится вместо другого значения. То есть, в итоге оверхеда нет.

> Так и пайп будет каждый раз перезапускаться

Но не будет сохранять предыдущее значение.

> Почему мильон? Мы ж про одноуровневый кэш.

Почему одноуровневый? А если пайп ф-я в нескольких местах применяется?

В любом случае, это бессмысленные рассуждения. Я объяснил, зачем конкретно были введены пайпы — для оптимизации, которую иначе (без изменения алгоритма cd) сделать нельзя. Это единственная причина, а какая-то «теснота» или еще там что не при делах. То, что могут быть какие-то другие варианты оптимизации — факт нерелевантный.
Оно хранится вместо другого значения. То есть, в итоге оверхеда нет.

Эммм… Как тогда шаблонизатор, не имея обоих значений, понимает, перезапускать ли пайп или нет? Или там при установке значения выполняются (если значение новое) все связанные с ним пайпы?


Почему одноуровневый? А если пайп ф-я в нескольких местах применяется?

Так вы же сами захотели одноуровневый. Если нужен одноуровневый в месте применения в шаблоне, а не на инстансе, то, наверное, вы меня все-таки поймали. Но за мою практику с реактом мне ни разу такой не понадобился, хотя в реакте мемоизация здесь и там, особенно с каррированными хэндлерами. Как бы я решал такую ситуацию? Черт его знает, скорей всего через мемоизируемые геттеры, ну да, костыль.

> Эммм… Как тогда шаблонизатор, не имея обоих значений, понимает, перезапускать ли пайп или нет?

Я же говорю, он _вместо_ одного значения (результат ф-и) хранит другое (ее аргумент). Естественно, может быть ситуация, когда аргумент больше результата. Или наоборот. Но это уже вопрос статистику, в среднем будет ± одинаково.

> Так вы же сами захотели одноуровневый.

Я просто описывал работу пайпов, а их можно сравнить именно с одноуровневым кешем per instance пайпа.

Тут есть две проблемы — одна вымышленная, вторая реальная (но про другое).


Вымышленная — про разделение труда между верстальщиком и разработчиком. На самом деле, что с JSX, что с html, нашпигованным angular-директивами, так разделять уже не получается, верстальщику нужно "апгрейдиться" до начинающего разработчика в любом случае.


Реальная (но специфичная для реализации) — в том, что JS с ограничением на expression only не очень-то удобен: приходится вместо очевидных if/foreach либо писать менее очевидные конструкции, либо выносить их отдельно, что зачастую снижает читабельность. Это можно решить небольшим расширением JSX по аналогии с кофескриптом (чтобы if etc возвращали значение).

НЛО прилетело и опубликовало эту надпись здесь

Когда я в первый раз увидел JSX, у меня были ровно такие же ощущения, как у вас, и так было где-то год, пока не поработал с React-проектом. За исключением того момента, что я озвучил, нормально все с JSX, тут главное преодолеть ментальный блок :-)


Мне гораздо больше не понравилось, что нельзя использовать DI в конструкторах компонентов. Property injection, конечно, делается, но это хуже: в конструкторе намного заметнее ситуация, когда у компонента слишком много зависимостей.

нормально все с JSX, тут главное преодолеть ментальный блок :-)

Цитируя любимую поговорку моей маман: Если вас ударят в глаз, вы, конечно, вскрикнете. Раз ударят, два ударят, а потом привыкнете.


Ну, или можете не мучиться. Ваш выбор.

Спасибо за статью. Столкнулся при освоении в начале с не которыми вышеописанными проблемами, возможно еще придётся столкнутся, но сомневаюсь, что перестану его «любить» )
НЛО прилетело и опубликовало эту надпись здесь

Смеяться будете, но они еще и закрывают их в полуавтоматическом режиме, если активности нет 3 месяца.

image
// Почему понадобился compose?
'lastName': [null, Validators.compose([Validators.required, Validators.minLength(5), Validators.maxLength(10)])],


Пишу без compose и все работает. ЧЯДН?
Боюсь вы узнаете об этом только когда что-то сломается. Пример из документации.
Вот именно, прежде всего нужно читать документацию. В последней версии официально такой формат поддерживается. Хотя пример без билдера, но он просто инкапсулирует в себя эту логику FormGroup и FormControl.
angular.io/guide/form-validation

Support multiple validators by passing the functions in as an array.



Там же пример.
this.heroForm = new FormGroup({
'name': new FormControl(this.hero.name, [
Validators.required,
Validators.minLength(4),
forbiddenNameValidator(/bob/i) // < — Here's how you pass in the custom validator.
]),
});


Избавиться от Null (но по моему мнению он в сигнатуре неообходим, т.к. указывает на первоначальное значение контрола) можно с помощью элементарного exctention метода, который пишется за несколько минут с тестами.
Ну чтож, здорово, что это наконец исчезло из документации.
Интересно что тут методы есть, а описания нет: angular.io/api/forms/Validators
Вы должны понимать, что статья писалась не за 1 день (к сожалению) и перепроверять каждую страницу документации angular ежедневно я не имею возможности.

Так что с одной стороны я рад, что API стало чище. А с другой — почему не сделали этого сразу?
А с другой — почему не сделали этого сразу?

Справедливое замечание. Но с другой стороны — фреймворк развивается, я уже несколько раз код переписывал с RC->Release->Минорные Updates. Теперь жду 5 версии.
ERROR TypeError: observable.do is not a function

Была такая проблема давно.


С Typescript 2.3.3 и rxjs@5.4.3 приведенный код без импорта оператора не проходит компиляцию.
Если сделать импорт из 'rxjs/Rx' или 'rxjs/add/operator/do', то код компилируется и в runtime отрабатывает без ошибок, сборка webpack.

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

Вижу что наболело, но все пройдет :)
Я переписал все контролы для форм, сделал нормальные валидаторы, таблицу со всеми наворотами, переписал хттп клиент (тот что был во втором ангуляре — ужасен, да и следующий не далеко ушел) и успокоился.


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


Если оставить в стороне апи, то само ядро ангуляра — компоненты — очень даже хороши.

> Я переписал все контролы для форм, сделал нормальные валидаторы, таблицу со всеми наворотами, переписал хттп клиент

А что не так с формами, валидаторами и хттп-клиентом?

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

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

Эм, при чем тут формы? Это же все претензии к компонентам, которых аннгуляр не предоставляет (и не должен, т.к. не является библиотекой компонентов).
у форм нет возможности делать маски или форматировать вывод

Для масок есть https://github.com/text-mask/text-mask (сам правда не использовал ибо не очень их люблю), форматировать можно или через accessors или создать кастомный контрол. Кросс-валидация спокойно делается через кастомный валидор (все формы это кучка NgControl и внутри валидатора можно добраться до любого из них).


чего стоит только гадание по еррор обьекту какого он типа или какого статуса или это вообще таймаут.

HttpErrorResponse?


Роутер

Странно что про него не сказали — а ведь это просто уёмрак :(


  • obervable resolver-ы грузятся только последовательно (в трекере есть несколько предложений)
  • canActivate проверяется сразу для всех children, если какой-то вернет falseни один из них не будет загружен (бага тоже есть)
  • именованные router-outlet — дичайшая дичь, учитывая предыдущий пункт вообще не понимаю где и как их можно использовать
  • нет именованных маршрутов (выше уже писал)

angular-cli

Заслуживает отдельного теплого слова — тестирование перед релизами отсутствует напрочь, каждый релиз что-то ломает. А самый прикол что используя последние версии typescipt-а приходится собирать с --aot=false --build-optimizer=false. 1.6 еще не ставил и не хочу ибо не уверен что она вообще работает :( (?)


А чем дока то не нравится?

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


ЗЫ: Ну и напоследок из забавного (нет) — из ng-content исчезают <tr> #16103

И забыл — aot позволяет использовать только public свойства/методы, что тоже есть дичь :( (исправлять никто не собирается, типа всё так и должно быть....)

> И забыл — aot позволяет использовать только public свойства/методы, что тоже есть дичь

В чем дичь? Все вполне логично, с какой стати у шаблона должен быть доступ к приватным свойствам?

С той что шаблон и компонент это одно целое и эти поля, как правило, нигде кроме шаблона не используется и использовать не должны, соответственно, выставление их наружу это нарушение инкапсуляции. А дичь же в том что без aot оно прекрасно работает. Поэтому мне совершенно непонятно что мешало унаследовать шаблон он класса компонента и тем самым получить доступ к protected свойствам (насчет private вопрос дискуссионный, я скорее тоже против).

> С той что шаблон и компонент это одно целое

Совсем нет, у одного класса компонента может быть много шаблонов, а у одного шаблона — много классов компонентов. С-но, и все дальнейшие рассуждения становятся неверными.

> А дичь же в том что без aot оно прекрасно работает.

Без АОТ оно работает потому, что без АОТ типы в шаблонах никто не проверяет. То есть это (что работает) баг, а не фича.
Совсем нет, у одного класса компонента может быть много шаблонов

Пример для angular-а можно? Ибо мне кажется что это невозможно на практике...


а у одного шаблона — много классов компонентов

А это скорее чисто теоретическая возможность.


Более того, при наследовании компонентов вы неизбежно поймете что DI в конструктор это тоже дичь, которую никак не исправить...


Дичь

А дичь оно потому что приходится или копировать все зависимости базового компонента в каждого наследника или инжектить Injector, который усложняет отслеживание зависимостей. И то и то плохо.

Да там и с АОТ типы почти не проверяются. Запросто можно подписаться на несуществующее событие, ошибиться с именем трансклюда или параметра. И не будет падения ни при сборке, ни в рантайме — просто не будет работат и разбирайся сам, где накосячил. Ну а уж отложенная проверка типов (это когда код транслируется и запускается в течении секунды, а тем временем в фоне секунд 10 проверяются типы и выдаётся ошибка, если что) — вообще чудная вещь. Она периодически отваливается, в результате чего пока не перезапустишь сервер и не поймёшь, почему у тебя нифига не работает. Или наоборот, у тебя всё работает, а продакшен сборка падает.

Скоро уже будет проверятся, см. fullTemplateTypeCheck

Публикации

Истории