Коллеги, спасибо, понял, что в плюсах есть дополнительные причины для использования операторов, с их учетом уже минимум не так однозначно выглядит ситуация.
"В компьютерных технологиях есть только две сложные задачи: недействительность кэша и придумывание названий"
— правильнее было бы "инвалидация кэша" (процесс + конкретный термин, не нуждающий в "русификации") и "придумывание имен" (более общая и частая задача — имена функций, классов и тп)
Синглтон легко написать как бы без нарушения SRP — достаточно разбить на условный Foo, реализующий бизнес-логику, и FooSingleton, реализующий доступ к единственному aFoo.
SRP будет соблюден, но ключевые проблемы останутся.
К этому и абзацу ниже: "Чем принципиально отличаются приложения для WEB от обычных настольных приложений?"
к моменту появления и веб-приложений, и даже статичных веб-страниц, кроме настольных приложений, "обычных" для автора, десятки лет существовали распределенные системы с клиентами разной степени "толщины", в которых давно и буднично решались многие вопросы, которые автор почему-то посчитал возникшими только в вебе — и разделение клиентского и серверного кода, и доступ к удаленным ресурсам, и минимизация привилегий, необходимых клиентской части для работы, и тп
В такой огромной статье с кучей пафоса собственно применению наследования посвящено два абзаца с одним примером, и то неверным:
кнопка, нажимаемая один раз: нарушает контракт обычной кнопки (только первое нажатие генерирует ожидаемое событие), а не "дополняет" его — тесты обычной кнопки не пройдут для одноразовой
как раз в UI компонентный подход позволяет обходиться полностью без наследования независимо от конкретной технологии — все делается через композицию, когда одна компонента оборачивает другую
Не пытаясь судить, кто в этом деле прав, отмечу лишь нечистоплотность аргументации автора:
Таким образом, из пояснения компании следует, что безапелляционное решение о блокировке сайта проекта принял бот, над которым человек невластен.
Из отзыва следует, что решение приняла компания, а не бот:
перечислены конкретные причины блокировки — размещение запрещенных материалов и тп, а не "наш бот просто так решил";
прямо указано, что данный отзыв — официальная позиция компании, а не бота
стоит подпись руководителя компании, а не бота.
Разбираться нужно с этими конкретными доводами.
Ознакомьтесь, там много эпичного, например, вот такое: [гневный твит Роскомсвободы]
Вы только что возмущались якобы отсылкой к боту, и тут же приводите как источник информации для читателей чужие гневные твиты. Как же так? Вы же были там, так и напишите от себя или со ссылкой на официальные источники, хотя бы на заявление юрлица Роскомсвободы.
Ну и вишенка:
Не по данной теме, но: Готовы ли вы участвовать в краудфандинге на судебные процессы, направленные на оспаривание и изменение законодательства РФ в отношении интернет-регулирования в Высших судах?
Перевожу: "а теперь, когда я подогрел ваше негодование манипуляциями, хотя бы проголосуйте, чтобы показать, что хабравчане считают интернет-регулирование в целом несправедливым, и хотят бороться против него хотя бы деньгами"
Стыдно должно быть так делать. Еще и дискредитируете тех, кого защищаете — будь они даже сто раз правы, такая защита формирует совсем другое впечатление.
1) Функция первого класса — из вашего определения следует, что это какие-то особые функции, обладающие особыми свойствами, что неверно:
во-первых, нет такого самостоятельного понятия — "функция первого класса" — это всегда свойство языка программирования, которым некоторые из них обладают: "функции являются объектами первого класса".
во-вторых, свойство "объект первого класса" в рамках языка может быть присуще или не присуще любому из типов сущностей языка целиком — переменным, константам, функциям, классам, интерфейсам, пространствам имен и тп; то есть, если в языке функции являются объектами первого класса, то сразу все, а не какие-то конкретно.
в-третьих, свойства объектов первого класса могут различаться от языка к языку; в частности, в чисто функциональных языках переменных нет, поэтому никакая сущность не может быть присвоена переменной — из вашего определения следует, что там функции не являются объектами первого класса; здесь стоит хотя бы сделать оговорку;
в-четвертых, пропущено одно из ключевых универсальных свойств объектов первого класса — такие объекты могут быть созданы во время выполнения программы
в-пятых, приведен некорректный пример, но это сложно понять из-за предыдущего пункта — в языке C функции не могут быть созданы во время выполнения программы — только во время компиляции, поэтому в C они не являются объектами первого класса
На второй взгляд пример кажется не очень жизненным: если пользователь начинает какую-то операцию, он же должен узнать о ее результате, иначе он будет рассчитывать на успех; поэтому обычно уведомления об ошибках (а бывает, и об успехе) отображаются в некой области, не зависящей от текущего контекста; классический пример — ButterBar (желтая полоска вверху) в Gmail. Для такого отображения не нужно отслеживать ЖЦ компоненты, вызвавшей запрос. Компонента при этом может также обработать результаты и по-своему.
а $onDestroy в данном подходе реализует кто? я так предполагаю, @frp записывают себя в некий реестр в инстансе MyProfile, с которым потом работает MyComponent#onDestroy()?
основная мысль вроде ясна, и теперь с ней согласен: Зоны в данной задаче излишни — есть задача синхронизировать ЖЦ компонент и запросов, которые уже друг о друге знают, поэтому достаточно при уничтожении компоненты пометить выпущенные ею запросы как "неактуальные"; для этого у запросов должен быть соотв. интерфейс;
в вашем варианте это решается оборачиванием запросов (и аналогичных ресурсов) в реактивные переменные; и у автора, и у вас запросы учитываются на уровне методов компоненты с помощью декоратора метода (@cancellable vs @frp), только у автора все отслеживает зона, в вашем (по моему предположению) все отслеживает сам компонент как инстанс MyComponent.
ссылку на injector можно передавать с помощью условного BaseController.setCurrentInjector() при старте приложения — это позволит и уйти от предположения, что body — корневой элемент приложения, и в принципе уберет ненужную ответственность из BaseController
текущая реализация довольно хрупка — разработчики должны помнить, что нужно вызывать super.constructor() (а, при написании своего $onDestroy, и super.$onDestroy()), причем такие ошибки, особенно с $onDestroy, могут заметить очень нескоро, и, скорее всего, уже пользователи;
корень проблемы — в использовании наследования — class AccountsController extends BaseController:
решение: превратить BaseController в декоратор класса, оборачивающий/создающий методы $onInit и $onDestroy
[описываемый подход] сильно облегчает разработку, когда связанные компоненты находятся на разных ветвях иерархии
Надо просто не усложнять разработку изначально — не связывать компоненты на разных уровнях иерархии.
Для этого есть простая совокупность правил проектирования, не зависящих от фреймворка:
Компонента (часть UI) может знать только о своих непосредственных потомках (которых она так или иначе и создала)
Компонента-родитель при создании передает непосредственному потомку данные, нужные ему для работы (+ опционально дергает его методы интерфейса), и слушает его события — тупо передает ему обработчик, который надо дернуть
Компонента-потомок не знает о родителе — только генерирует события, а точнее, просто дергает полученные обработчики
Все дополнительное взаимодействие организуется через сервисы («вечные» единицы бизнес-логики): сервисы уже генерируют полноценные события, на которые может подписываться множество слушателей (других сервисов или компонент), с учетом жизненного цикла слушателей (для Angular это — автоотписка компоненты при уничтожении ее scope, как в примере в статье
В основе статьи — ложная дихотомия: «либо фреймворки, либо архитектура».
На самом деле они дополняют друг друга: паттерн — это абстрактное описание типового решения определенной типовой задачи; фреймворки, как правило, — набор конкретных реализаций паттернов. То есть теория + практика.
Понятие «фреймворк» — это сам по себе паттерн уровня архитектуры системы. Соответственно и фреймворк не обязательно должен быть «монолитным» куском кода — даже если это набор типа разных, независимых библиотек, но по счастливой случайности (или, например, потому, что писались одним автором и подгонялись друг под друга) хорошо работающих друг с другом и покрывающих существенную часть приложения, то простое соглашение использовать именно их в проекте и создает фреймворк.
Так что, когда автор пишет, что использует один и тот же набор библиотек, написанных пять лет назад, это и значит, что он использует свой фреймворк.
Вообще кажется, что ключевой посыл статьи — «для b2b особенно нужны юзабилити-специалисты, и это как раз моя студия по юзабилити».
Я считаю, во многом наоборот — фидбэк от b2b-пользователей гораздо легче получить, и он гораздо конструктивнее, чем от b2c. Поэтому нужно просто максимально рано обкатывать на будущих пользователях первые версии, начиная с текстовых описаний и эскизов.
В b2b фокус во многом на функционале, поддержке всех нужных процессов. То есть поддерживать 10 из 10 вариантов бизнес-процесса, но в более громоздком интерфейсе (который «становится» гораздо удобнее после обучения), нужнее, чем поддерживать 3, но красиво, удобно и с низким порогом вхождения. Поэтому приоритет — осознанно не на юзабилити. Плюс чем больше функицонала, тем менее удобным кажется интерфейс, особенно внешнему юзеру.
Это вопрос объемный. Если есть пояснительная записка к этому постановлению, то в ней должно быть объяснено, зачем. К любому законопроекту в Думе такие записки делаются, про постановления Правительства не знаю.
Коллеги пишут, что в различных «продвинутых» странах все уже так или жестче (касается любого публичного доступа) — например, Германия или Сингапур.
Как мне представляется, положительная мотивация такая: больше прозрачность — меньше нарушений. И не только терроризм, но и «мелкие», например, доступ школьников к взрослому контенту или хейтинг школьников в соцсетях.
Да, аргумент.
Коллеги, спасибо, понял, что в плюсах есть дополнительные причины для использования операторов, с их учетом уже минимум не так однозначно выглядит ситуация.
да, недопечатал оставшиеся аргументы.
Каюсь, забыл, что в плюсах конкатенация нетривиальна.
Но все равно, разве так уж плохо
logger.warn("Unexpected blah: %s instead of %s")
, что оправданы кастомные операторы?Я бы настойчиво рекомендовал не использовать операторы вообще — даже если на самом деле "красивее" на первый взгляд, все только ухудшается:
logger.warn(...)
Коллеги, ИМХО перевод цитаты не совсем корректен:
— правильнее было бы "инвалидация кэша" (процесс + конкретный термин, не нуждающий в "русификации") и "придумывание имен" (более общая и частая задача — имена функций, классов и тп)
Синглтон легко написать как бы без нарушения SRP — достаточно разбить на условный Foo, реализующий бизнес-логику, и FooSingleton, реализующий доступ к единственному aFoo.
SRP будет соблюден, но ключевые проблемы останутся.
К этому и абзацу ниже: "Чем принципиально отличаются приложения для WEB от обычных настольных приложений?"
В такой огромной статье с кучей пафоса собственно применению наследования посвящено два абзаца с одним примером, и то неверным:
кнопка, нажимаемая один раз: нарушает контракт обычной кнопки (только первое нажатие генерирует ожидаемое событие), а не "дополняет" его — тесты обычной кнопки не пройдут для одноразовой
Не пытаясь судить, кто в этом деле прав, отмечу лишь нечистоплотность аргументации автора:
Из отзыва следует, что решение приняла компания, а не бот:
перечислены конкретные причины блокировки — размещение запрещенных материалов и тп, а не "наш бот просто так решил";
прямо указано, что данный отзыв — официальная позиция компании, а не бота
Разбираться нужно с этими конкретными доводами.
Вы только что возмущались якобы отсылкой к боту, и тут же приводите как источник информации для читателей чужие гневные твиты. Как же так? Вы же были там, так и напишите от себя или со ссылкой на официальные источники, хотя бы на заявление юрлица Роскомсвободы.
Ну и вишенка:
Перевожу: "а теперь, когда я подогрел ваше негодование манипуляциями, хотя бы проголосуйте, чтобы показать, что хабравчане считают интернет-регулирование в целом несправедливым, и хотят бороться против него хотя бы деньгами"
Стыдно должно быть так делать. Еще и дискредитируете тех, кого защищаете — будь они даже сто раз правы, такая защита формирует совсем другое впечатление.
Иван, есть неточности в определениях:
1) Функция первого класса — из вашего определения следует, что это какие-то особые функции, обладающие особыми свойствами, что неверно:
во-первых, нет такого самостоятельного понятия — "функция первого класса" — это всегда свойство языка программирования, которым некоторые из них обладают: "функции являются объектами первого класса".
во-вторых, свойство "объект первого класса" в рамках языка может быть присуще или не присуще любому из типов сущностей языка целиком — переменным, константам, функциям, классам, интерфейсам, пространствам имен и тп; то есть, если в языке функции являются объектами первого класса, то сразу все, а не какие-то конкретно.
в-третьих, свойства объектов первого класса могут различаться от языка к языку; в частности, в чисто функциональных языках переменных нет, поэтому никакая сущность не может быть присвоена переменной — из вашего определения следует, что там функции не являются объектами первого класса; здесь стоит хотя бы сделать оговорку;
в-четвертых, пропущено одно из ключевых универсальных свойств объектов первого класса — такие объекты могут быть созданы во время выполнения программы
в-пятых, приведен некорректный пример, но это сложно понять из-за предыдущего пункта — в языке C функции не могут быть созданы во время выполнения программы — только во время компиляции, поэтому в C они не являются объектами первого класса
Разумеется) Спасибо!
На второй взгляд пример кажется не очень жизненным: если пользователь начинает какую-то операцию, он же должен узнать о ее результате, иначе он будет рассчитывать на успех; поэтому обычно уведомления об ошибках (а бывает, и об успехе) отображаются в некой области, не зависящей от текущего контекста; классический пример — ButterBar (желтая полоска вверху) в Gmail. Для такого отображения не нужно отслеживать ЖЦ компоненты, вызвавшей запрос. Компонента при этом может также обработать результаты и по-своему.
а
$onDestroy
в данном подходе реализует кто? я так предполагаю,@frp
записывают себя в некий реестр в инстансеMyProfile
, с которым потом работаетMyComponent#onDestroy()
?основная мысль вроде ясна, и теперь с ней согласен: Зоны в данной задаче излишни — есть задача синхронизировать ЖЦ компонент и запросов, которые уже друг о друге знают, поэтому достаточно при уничтожении компоненты пометить выпущенные ею запросы как "неактуальные"; для этого у запросов должен быть соотв. интерфейс;
в вашем варианте это решается оборачиванием запросов (и аналогичных ресурсов) в реактивные переменные; и у автора, и у вас запросы учитываются на уровне методов компоненты с помощью декоратора метода (
@cancellable
vs@frp
), только у автора все отслеживает зона, в вашем (по моему предположению) все отслеживает сам компонент как инстансMyComponent
.Верно понял вашу мысль?
Как конкретно их использовать — оборачивать в них запросы к API? Разве не потребует это множества изменений кода приложения?
И разве для этого не надо будет от них отписываться явно, для чего нужно будет написать кучу
$onDestroy
в компонентах? В чем же выигрыш тогда?ссылку на injector можно передавать с помощью условного
BaseController.setCurrentInjector()
при старте приложения — это позволит и уйти от предположения, чтоbody
— корневой элемент приложения, и в принципе уберет ненужную ответственность изBaseController
текущая реализация довольно хрупка — разработчики должны помнить, что нужно вызывать
super.constructor()
(а, при написании своего$onDestroy
, иsuper.$onDestroy()
), причем такие ошибки, особенно с$onDestroy
, могут заметить очень нескоро, и, скорее всего, уже пользователи;корень проблемы — в использовании наследования —
class AccountsController extends BaseController
:решение: превратить
BaseController
в декоратор класса, оборачивающий/создающий методы$onInit
и$onDestroy
Надо просто не усложнять разработку изначально — не связывать компоненты на разных уровнях иерархии.
Для этого есть простая совокупность правил проектирования, не зависящих от фреймворка:
На самом деле они дополняют друг друга: паттерн — это абстрактное описание типового решения определенной типовой задачи; фреймворки, как правило, — набор конкретных реализаций паттернов. То есть теория + практика.
Понятие «фреймворк» — это сам по себе паттерн уровня архитектуры системы. Соответственно и фреймворк не обязательно должен быть «монолитным» куском кода — даже если это набор типа разных, независимых библиотек, но по счастливой случайности (или, например, потому, что писались одним автором и подгонялись друг под друга) хорошо работающих друг с другом и покрывающих существенную часть приложения, то простое соглашение использовать именно их в проекте и создает фреймворк.
Так что, когда автор пишет, что использует один и тот же набор библиотек, написанных пять лет назад, это и значит, что он использует свой фреймворк.
Я считаю, во многом наоборот — фидбэк от b2b-пользователей гораздо легче получить, и он гораздо конструктивнее, чем от b2c. Поэтому нужно просто максимально рано обкатывать на будущих пользователях первые версии, начиная с текстовых описаний и эскизов.
Коллеги пишут, что в различных «продвинутых» странах все уже так или жестче (касается любого публичного доступа) — например, Германия или Сингапур.
Как мне представляется, положительная мотивация такая: больше прозрачность — меньше нарушений. И не только терроризм, но и «мелкие», например, доступ школьников к взрослому контенту или хейтинг школьников в соцсетях.