Pull to refresh

Comments 18

Вот так вот просто. Собственно именно по этой причине такая интересная концепция как Object.observe была исключена черновиков стандарта. Ну что, все еще думаете что нам так уж нужен $scope?
Фактически вы убрали реактивное взаимодействие, заменив его на интерактивное. Это работает в простейших линейных случаях: делаем то, потом это, а затем ещё кое что. Но сложность экспоненциально растёт с каждым ветвлением логики. Статья про атомы иллюстрирует этот процесс. Реактивное программирование — это ж чуть ли не единственное достоинство ангуляра, по сравнению с остальными фреймворками. Зачем вы так жестоко с ним? :-)

Как вы думаете, какое значение будет выведено? Явно не то что мы хотели.
Как раз именно то. Не понимаю, почему вы хотите тут что-то другое. Другое дело, что инициатором любого биндинга должен быть внешний компонент, а не внутренний. И именно эту проблему надо решать, а не вводить сомнительные односторонние биндинги, которые приводят лишь к такого рода тавтологиям: on-item-select="$ctrl.selectedItem = selectedItem" selected-item="$ctrl.selectedItem"

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

Только javascript! В этом основное преимущество dirty checking-а между данными и представлением, а не между представлением и DOM, как например в React. Мы полностью отделяем UI от состояния приложения, а такие вещи банально проще тестировать.
Это преимущество реактивного программирования, а не грязных проверок. У грязных проверок одно преимущество — простой код. Но они крайне не эффективны. Но вообще говоря, декларативно разделять надо не только view-model и dom, но и model и view-model.
Реактивное программирование — это ж чуть ли не единственное достоинство ангуляра, по сравнению с остальными фреймворками.


Так, я может чего-то не понимаю, но с каких пор в ангуляре есть реактивное программирование? Мы в каком-то из топиков уже это обсуждали и выяснили, что для FRP ангуляр не очень подходит. В Angular2 для реактивщины используется rx.js. Но ладно, даже если допустить что под «реактивностью» мы тут подразумеваем реакцию на изменение данных, то ничего же не поменялось.

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

Как раз именно то. Не понимаю, почему вы хотите тут что-то другое.

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

которые приводят лишь к такого рода тавтологиям


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

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


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

Это преимущество реактивного программирования, а не грязных проверок.

Вот опять… я уже начинаю сомневаться в своем понимании «реактивного программирования». Это же просто биндинги, MVVM и т.д. FRP тут причем?
Так, я может чего-то не понимаю, но с каких пор в ангуляре есть реактивное программирование? Мы в каком-то из топиков уже это обсуждали и выяснили, что для FRP ангуляр не очень подходит.
Ну, он там корявый, но всё же есть.

В Angular2 для реактивщины используется rx.js.
Это даже хуже вотчеров в плане поддержки :-)

Просто вместо двух ватчеров (один создает ангуляр при изоляции скоупов и другой — вы, когда хотите отслеживать изменения внутри директивы) мы теперь используем явный вызов метода при изменении свойства, и остается один ватчер. Инициатором вызова этой функции остается ангуляр, и вызываться он будет исключительно по изменению значения.
Представьте себе ситуацию: у вас 3 свойства А1, А2, А3, каждое из которых зависит от каждого (или почти каждого) из 3 других свойств Б1, Б2, Б3. Когда устанавливается значение А1, вам нужно пройтись по всем зависимым свойствам и сказать им обновиться. Поддерживать эти «обратные зависимости» приходится вручную, что неизбежно приводит к ошибкам и неэффективности. Именно с этой проблемой и борется реактивная архитектура. Только в случае FRP (knockout, атомы) зависимость прямая (от зависимого к зависимостям), а в случае стримов (rx.js, bacon.js) обратная (от зависимости к зависимым).

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

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

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


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

Это даже хуже вотчеров в плане поддержки :-)

Аргументируйте. Ну и опять же rx.js не залязит в компоненты (обычно, хотя у меня в списке «попробовать» еще и это значится). Мне очень понравилась реализация работы с HTTP в Angular2 с использованием Observable.

Представьте себе ситуацию: у вас 3 свойства А1, А2, А3, каждое из которых зависит от каждого (или почти каждого) из 3 других свойств Б1, Б2, Б3.


Чем сеттеры отличаются от $watch? ваша задача решается либо через deep watch, либо кастомные ватчеры, либо через 5 отдельных ватчеров которые запускают именно реакцию.

const a1 = Symbol('a1'); 
// ...
class MyComponent {
    set A1 (val) {
        // ...
        this[a2] = calcA2(this[a1]);
    }
    set A2 (val) {
        // ...
        this[a3] = calcA3(this[a2]);
    }

    // ну или можно было бы одну функцию описывающую переходы замутить
}


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

Меня смущает такая избыточность кода на ровном месте.

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

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

типичный пример — эксельчик


Судя по вашим комментариям в каждом топике, сказывается специфика вашей работы. У вас эксельчики — это типичные примеры. И там да, нужны и FRP и прочие вещи. Но это далеко не «типичные» задачи для большинства разработчиков. Мне кажется что именно это является основной причиной, по которой нам так сложно достичь взаимопонимания.
Сравним реализуцию компонент на Ангуляре и на Сферическом Фреймворке в Вакууме…

Объявление компоненты

Ангуляр (скрипт + вёрстка + конфиг):
angular.module( 'app' ).component( 'myPanel' , {
	transclude : {
		myPanelHead : '?head',
		myPanelBody : 'body'
	},
	template: `
		<div class="my-panel">
			<div class="my-panel-header" ng-transclude="head"></div>
			<div class="my-panel-bodier" ng-transclude="body">No data</div>
		</div>
	`
} )

Сферический Фреймворк (ничего лишнего, только декларативное описание):
$my_panel : $mol_block child
	< header : $mol_block child < head : null
	< bodier : $mol_block child < body =No data


Использование компоненты

Ангуляр (куча тэгов, разделение на приложение и компоненту):
<body ng-app="app">
	<my-panel>
		<my-panel-head>My tasks</my-panel-header>
		<my-panel-body>
			<my-task-list
				assignee="me"
				status="todo"
			/>
		</my-panel-body>
	</my-panel>
</body>

Сферический Фреймворк (ничего лишнего, приложение — тоже компонента):
$my_app : $my_panel 
	head : =My tasks
	body : $my_task_list
		assignee : =me
		status : =todo


Кастомизация компоненты

Ангуляр (нет кастомизации, только копипаста):
angular.module( 'app' ).component( 'myPanelExt' , {
	transclude : {
		myPanelHead : '?head',
		myPanelBody : 'body',
		myPanelFoot : '?foot'
	},
	template: `
		<div class="my-panel">
			<div class="my-panel-header" ng-transclude="head"></div>
			<div class="my-panel-bodier" ng-transclude="body">No data</div>
			<div class="my-panel-header" ng-transclude="foot"></div>
		</div>
	`
} )

Сферический Фреймворк (наследуемся и подстраиваем под себя):
$my_panelExt : $my_panel child
	< header
	< bodier
	< footer : $mol_block child < foot : null
Мы уже как-то в одном из топиков спорили на тему «читабельности» и экономической эффективности. Вы привели довод мол, что вы можете объяснить новичку идеологию вашего фреймворка и он может быстро приступать к работе. Но как на счет таких случаев:

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

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

Ваш «сферический в вакууме» фреймворк не будет мэйнстримом, во всяком случае ближайшие лет пять, пока индустрия не подтянется к этому уровню.
— Вас банально не будет рядом, что бы объяснить новому человеку на проекте, как с этим всем жить.

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

— У проекта не такой большой бюджет что бы нанимать кого-то вашего уровня.

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

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

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

Ваш «сферический в вакууме» фреймворк не будет мэйнстримом, во всяком случае ближайшие лет пять, пока индустрия не подтянется к этому уровню.
Скорее пока какая-нибудь компания не начнёт его продвигать. К сожалению, современная индустрия очень тенденциозна. Сейчас все вакансии по фронтенду пестряд Ангуляром. Но уже появились и первые ласточки, которые наелись ангуляра и ищут что-то другое. Обычно этим другим сейчас выступает Реакт, на котором хоть компоненты можно делать полноценные.
Это не какой-то новый язык программирования, это ближе к haml-подобному шаблонизатору. А вот логика описывается одноимёнными классами на тайпскрипте.


А ваше решение на гитхабе можно посмотреть? Звучит все же уже интереснее.
Использовать события скоупов для организации pub/sub в сервисах, или еще хуже, завязывать какую-то логику приложения на них, это очень плохо.

Почему?
Это внутренний механизм ангуляра, который предназначен только для того, что бы обеспечить уведомление директив о их жизненном цикле. В рамках сервисного слоя намного удобнее использовать обычный диспатчер событий. А в рамках компонентов вам просто не нужны события. Конечно есть и исключения, потому я и написал что если очень хочется то можно, просто лучше «10 раз подумать».
Angular Component Router, который во втором ангуляре (но также доступен и в первой версии, где он пока что не слишком стабилен), работает с компонентами. Получается чтобы "по канонам" сварганить страницу нужно как минимум 3 сущности?

  • внешний компонент который будет взаимодействовать с Router
  • затем директива которая будет обеспечивать некоторую логику получения данных и тд
  • затем как миниуму один компонент который будет это логику "рисовать"
Формально за все это отвечает один компоннет, просто он может состоять из других компонентов. В целом же они собираются добавить что-то типа ресолверов, и тогда логику по получению данных можно будет вынести наверх.
Нужно больше абстракций :-)
Кстати, ждать ли критику Сферического Фреймворка или всё настолько идеально, что и придраться не к чему?
Нужно больше абстракций :-)

Тут нет "абстракций", тут есть "разделение обязанностей". Для апликачек явный поток данных сверху вниз очень упрощает дело (именно по этому я использую ресолверы для получения данных из сервисов, и сервисы для мутации состояния). По сути для счастья нам надо только сервис, ресолвер и компонент.

Кстати, ждать ли критику Сферического Фреймворка или всё настолько идеально, что и придраться не к чему?

Для объективной критики мне надо побольше времени его посмотреть, и время на это у меня будет только в пятницу, к сожалению. Пока же субъективная оценка превалирует просто по стилю ML и т.д.
Но можно и проще: компоненты, сервисы и инъекция зависимостей.
Ресолвер это тот же сервис, просто уточнение его зоны ответственности. Так что да.
Какие есть механизмы управления компонентом из вне (из контроллера), например у меня есть несколько компонентов «медиа-проигрыватель», с методами старт/пауза/стоп, Ангуляр 2 (1.5) предлагает какие-нибудь официальные/правильные подходы для этого?
Sign up to leave a comment.

Articles