По сути, формальных критериев для этого нет (и я считаю, не нужно их искать, иначе получите не хороших, а соответствующих). Но по работе и по отношению в команде это видно, и этого достаточно.
UTC DateTime позволяет сравнивать даты из разных часовых поясов, и отображать даты в часовом поясе пользователя. Это дает общую относительную систему координат, и часто этого достаточно.
Но иногда возникают задачи, когда требуется узнать дату и время в системе координат пользователя.
Например, иногда важна именно выбранная дата (без времени), и она может отличатся из-за разницы в часовых поясах. Здесь UTC не поможет, из него нельзя восстановить реально выбранное пользователем значение (без дополнительной информации о часовом поясе, скажем, из профиля).
Самый надежный и хороший подход — это хранить DateTimeOffset, и работать с ним как на сервере, так и на клиенте. Использовать свой формат сериализации (возможно, с фоллбэком в часовую зону по умолчанию, для старых клиентов).
Все остальное, включая хранение UTC, это полумера. UTC решает проблему сравнения дат, но не всегда помогает правильно их отображать.
Вообще, работа с датами — тема довольно неочевидная и с множеством подводных камней, особенно если в некоторых случаях нужны только даты без времени. Нужно всегда (как отметили уже выше) понимать, что именно нужно показать: дату события в часовом поясе пользователя, дату, как ее ввел пользователь или еще что-то.
В смысле "не могут быть однонаправленными" и "притворяться, что обратного потока нет"? Могут быть, и никто не отрицает обратный поток.
Однонаправленные потоки означает, что информация о данных для представления и информация о действиях пользователя на интерфейсе (из представления) доставляется разными путями (в противоположность, например, двустороннему байндингу).
И событие, к примеру, ввода попадает и обрабатывается в состоянии приложения, и лишь опосредованно изменяет само представление. В этом отличие от двустороннего связывания (как в вашем примере), которое одновременно меняет свойство и контрол. Это затрудняет реализацию некоторых сценариев (например, попробуйте нормально реализовать ввод по маске и тп).
Ну, вы вынесли информацию о выделенном элементе на самый верх, в корень глобального состояния, и расшарили его с меню. Это один из очевидных способов "починки" иерархии (вынести на общий уровень родителя), но с кучей недостатков: общие данные будут стремится на самый верхний уровень, нужны специальные механизмы для получения уведомлений об изменениях, потоки данных не однонаправленные.
Для redux можно решить задачу с меню вообще не имея общего состояния, а лишь подписываясь на события изменения выбранного элемента (и предусмотрев "null-событие" сброса выделения).
Архитектура приложения, особенно бэкенд части, обычно строго иерархическая. У нас есть подсистемы, в них модули, в них компоненты, в компонентах используются другие компоненты и т.д. Все хорошо и красиво, исключения редкие, это хорошо работает и хорошо ложится на ООП.
Во фронтэнде это тоже работает, особенно когда речь идет об отображении данных (или, в терминологии стейт-менеждеров, о "потоке данных из состояния в представление"). Это привело к тому, что многие UI фреймворки ориентированы на создание замкнутых сложных компонентов с внутренним состоянием (как правило, смесью данных, состояния приложения и состояния самого компонента + бизнес логика в смеси с логикой UI).
Это перестает работать хорошо, когда начинается взаимодействие с пользователем. UI паттерны для взаимодействия не иерархичны сплошь и рядом. Возьмем текстовый редактор. У нас есть меню (которое находится на верхнем уровне иерархии компонентов), которое изменяет состояние выбранного абзаца в документе (которые находится на самом нижнем уровне). Состояние пункта меню зависит от нижнего уровня. Это нарушает иерархию (в которой нижний уровень должен зависить от верхнего, но не наоборот).
Возникает проблема коммуникации от нижнего уровня к верхнему. Особенно это костыльно получается при использовании изолированных компонентов. Нарушается изоляция — компонент должен сообщать информацию о состоянии наружу (выбран ли текст, или выбрана картинка). Это, конечно, утрировано, для демонстрации проблемы.
App-state management framework (redux, flux, частично MobX) решают эту проблему радикально — они полностью развязывают иерархию компонентов и иерархию состояния приложения. Плюс они дают единую точку входа для любого действия (своего рода универсальный контроллер), и адресация к нужному элементу — это теперь обязанность контроллера.
Это заодно решает и другую, менее острую и реже встречающуюся, проблему — отображение одних и тех же данных в разных видах.
У этой архитектуры достаточно своих проблем, начиная от многословности и слабой связности, заканчивая тем, что привычные паттерны не работают, переиспользование — это боль и мучения (в отличие от "кинь на форму и настрой свойства" подхода с изолированными компонентами).
Главным вопросом при выборе архитектуры UI должен быть "насколько иерархия данных отличается от ирерархии компонентов". Если она не отличается — инкапсулированные классические компоненты будут отлично работать. Если отличается сильно лучше их сразу развязать, чтобы не городить костыли и в итоге не прийти к самодельному flux-у.
Редьюсеры редко переиспользуются потому, что это обычно часть логики приложения (а не компонента). Поведение именно компонента обычно делается внутренним состоянием этого компонента (и его довольно мало, если разобраться).
Но это все-равно отличается от классических компонентов, где смешана логика приложения и логика компонента. Особенно это видно на сложных компонентах типа гридов, которые на реакте и редаксе теряют 80% своей сложности.
Я не смотрел и не использовал именно redux-forms, и, честно говоря, не совсем понимаю, какую выгоду они несут и что именно автоматизируют.
Подходы к декомпозиции redux-based приложений отличаются от "классических", унаследованных от jQuery-based приложений.
Проблемы с декомпозицией обычно начинаются, когда пытаются эмулировать стейтфулл компоненты на базе редакса.
В редаксе точкой декомпозиции являются именно sub-state + actions + middleware. Это делается довольно неудобно, и ни в какое сравнение не идет, конечно, с "классическими" компонентами, особенно с непривычки. В первую очередь это связано с тем, что точка монтирования зашита в коде middleware и mapStateToXXX.
В редаксе отдельно переиспользуется логика и отдельно переиспользуется UI (в виде dumb components). Ну и, соответсвенно, контейнеры пишем каждый раз.
Но сила редакса в том, что он "развязывает" связь один-к-одному между данными и структурой UI. Он легко позволяет отображать одни и те же данные в нескольких видах, без дублирования кода.
UI вообще часто нелогичен с точки зрения иерархии, часто верхние уровни зависят от нижних, например, добавляются пункты меню в зависимости от выделенной строки в гриде. Редакс это позволяет делать относительно легко (послать экшен можно из любого места), на "классических" компонентах это сделать красиво невозможно без введения аналога сообщений.
А разве архитектура с однонаправленными потоками — это не MVC? Ведь именно MVC постулировала зависимости в одном направлении.
На примере Реакта:
Model -> application state,
View -> JSX
Controller -> Reducer + Middleware, разделение на логику перехода по состояниям и логику взаимодействия с "внешним миром".
PoE слэшер чистой воды, однако возможных билдов очень много, и они реально рабочие (в отличие от того же Диабло 3).
Минус — это дико однообразный геймплей, выбранный билд практически невозможно изменить, умение требует очень сильной прокачки для выживания на высоких уровнях.
Сборка Angular 2 приложения — это боль и страдания. Продакшн билд приложения с компиляцией шаблонов и использованием ДевЭкстрим занимает… 8.5 минут!!!
Да, можно использовать watch, так что при сохранении изменений сборка будет запускаться автоматически. Но это не решает проблемы. 1. На практике все выглядит так: я ввожу часть кода, сохраняю, запускается сборка, пока она длится, я ввожу следующий код и сохраняю — в результате получается устаревший бандл, без последних правок. Кто-нибудь сталкивался с такой проблемой? Как вы ее решаете?
Постигая дзен двухсекундными ожиданиями после полусекундных правок.
Существует опция вебпака watchOptions.aggregateTimeout и watchOptions.poll, которая теоретические добавляет задержку перед запуском билда после изменений.
У менеджера по продажам — процент с продаж. Если продаж нет, менеджер увольняется сам, т.к. ничего не зарабатывает. Почему их нет — это вопрос, который должен волновать руководителя только применительно к предприятию, не к конкретному менеджеру.
Если окажется, что она круглые сутки обзванивает клиентов — что это поменяет?
Невозможно контролировать реальную загруженность сотрудника, который сам оценивает время выполнения своей работы. Давать задачу на оценку другому сотруднику нет смысла, т.к. затраты времени индивидуальны для каждой задачи.
Контролировать рабочий процесс не имеет смысла, т.к. если человек не хочет работать быстро, он будет работать медленно вне зависимости от того, что он будет фактически делать. Даже в условиях тотального контроля он будет печатать одним пальцем, только еще и будет испытывать раздражение.
Для стандартизируемой работы нет смысла учитывать что-либо, кроме фактической производительности и качества. Обычно для стандартизируемой работы используется некий минимальный требуемый объем плюс оплата за выработку. Это используется в такси, швейке и много где еще. Контролировать занятость не нужно.
Кто-нибудь вообще знает пример, где может помочь учет фактической занятости?
Не совсем в тему микросервисов, но хочу заметить, что слово "бизнес" применительно к архитектуре приложения не имеет (в общем случае) отношения к коммерции, а обозначает ту "пользу", которую приносит конкретное приложение.
Поэтому сервис авторизации для конкретного приложения — это бизнес-функциональность, но в то же время используемая библиотека для OAuth2 — это уже не бизнес-часть, т.к. она универсальна и не привязана к предметной области.
Поэтому суммирование массива — не бизнес-функциональность, если у нас, конечно, не приложение по суммированию массивов (Excel).
Для этого есть правило первое :)
По сути, формальных критериев для этого нет (и я считаю, не нужно их искать, иначе получите не хороших, а соответствующих). Но по работе и по отношению в команде это видно, и этого достаточно.
UTC
DateTimeпозволяет сравнивать даты из разных часовых поясов, и отображать даты в часовом поясе пользователя. Это дает общую относительную систему координат, и часто этого достаточно.Но иногда возникают задачи, когда требуется узнать дату и время в системе координат пользователя.
Например, иногда важна именно выбранная дата (без времени), и она может отличатся из-за разницы в часовых поясах. Здесь UTC не поможет, из него нельзя восстановить реально выбранное пользователем значение (без дополнительной информации о часовом поясе, скажем, из профиля).
Самый надежный и хороший подход — это хранить DateTimeOffset, и работать с ним как на сервере, так и на клиенте. Использовать свой формат сериализации (возможно, с фоллбэком в часовую зону по умолчанию, для старых клиентов).
Все остальное, включая хранение UTC, это полумера. UTC решает проблему сравнения дат, но не всегда помогает правильно их отображать.
Вообще, работа с датами — тема довольно неочевидная и с множеством подводных камней, особенно если в некоторых случаях нужны только даты без времени. Нужно всегда (как отметили уже выше) понимать, что именно нужно показать: дату события в часовом поясе пользователя, дату, как ее ввел пользователь или еще что-то.
В смысле "не могут быть однонаправленными" и "притворяться, что обратного потока нет"? Могут быть, и никто не отрицает обратный поток.
Однонаправленные потоки означает, что информация о данных для представления и информация о действиях пользователя на интерфейсе (из представления) доставляется разными путями (в противоположность, например, двустороннему байндингу).
И событие, к примеру, ввода попадает и обрабатывается в состоянии приложения, и лишь опосредованно изменяет само представление. В этом отличие от двустороннего связывания (как в вашем примере), которое одновременно меняет свойство и контрол. Это затрудняет реализацию некоторых сценариев (например, попробуйте нормально реализовать ввод по маске и тп).
Ну, вы вынесли информацию о выделенном элементе на самый верх, в корень глобального состояния, и расшарили его с меню. Это один из очевидных способов "починки" иерархии (вынести на общий уровень родителя), но с кучей недостатков: общие данные будут стремится на самый верхний уровень, нужны специальные механизмы для получения уведомлений об изменениях, потоки данных не однонаправленные.
Для redux можно решить задачу с меню вообще не имея общего состояния, а лишь подписываясь на события изменения выбранного элемента (и предусмотрев "null-событие" сброса выделения).
Архитектура приложения, особенно бэкенд части, обычно строго иерархическая. У нас есть подсистемы, в них модули, в них компоненты, в компонентах используются другие компоненты и т.д. Все хорошо и красиво, исключения редкие, это хорошо работает и хорошо ложится на ООП.
Во фронтэнде это тоже работает, особенно когда речь идет об отображении данных (или, в терминологии стейт-менеждеров, о "потоке данных из состояния в представление"). Это привело к тому, что многие UI фреймворки ориентированы на создание замкнутых сложных компонентов с внутренним состоянием (как правило, смесью данных, состояния приложения и состояния самого компонента + бизнес логика в смеси с логикой UI).
Это перестает работать хорошо, когда начинается взаимодействие с пользователем. UI паттерны для взаимодействия не иерархичны сплошь и рядом. Возьмем текстовый редактор. У нас есть меню (которое находится на верхнем уровне иерархии компонентов), которое изменяет состояние выбранного абзаца в документе (которые находится на самом нижнем уровне). Состояние пункта меню зависит от нижнего уровня. Это нарушает иерархию (в которой нижний уровень должен зависить от верхнего, но не наоборот).
Возникает проблема коммуникации от нижнего уровня к верхнему. Особенно это костыльно получается при использовании изолированных компонентов. Нарушается изоляция — компонент должен сообщать информацию о состоянии наружу (выбран ли текст, или выбрана картинка). Это, конечно, утрировано, для демонстрации проблемы.
App-state management framework (redux, flux, частично MobX) решают эту проблему радикально — они полностью развязывают иерархию компонентов и иерархию состояния приложения. Плюс они дают единую точку входа для любого действия (своего рода универсальный контроллер), и адресация к нужному элементу — это теперь обязанность контроллера.
Это заодно решает и другую, менее острую и реже встречающуюся, проблему — отображение одних и тех же данных в разных видах.
У этой архитектуры достаточно своих проблем, начиная от многословности и слабой связности, заканчивая тем, что привычные паттерны не работают, переиспользование — это боль и мучения (в отличие от "кинь на форму и настрой свойства" подхода с изолированными компонентами).
Главным вопросом при выборе архитектуры UI должен быть "насколько иерархия данных отличается от ирерархии компонентов". Если она не отличается — инкапсулированные классические компоненты будут отлично работать. Если отличается сильно лучше их сразу развязать, чтобы не городить костыли и в итоге не прийти к самодельному flux-у.
Редьюсеры редко переиспользуются потому, что это обычно часть логики приложения (а не компонента). Поведение именно компонента обычно делается внутренним состоянием этого компонента (и его довольно мало, если разобраться).
Но это все-равно отличается от классических компонентов, где смешана логика приложения и логика компонента. Особенно это видно на сложных компонентах типа гридов, которые на реакте и редаксе теряют 80% своей сложности.
Я не смотрел и не использовал именно redux-forms, и, честно говоря, не совсем понимаю, какую выгоду они несут и что именно автоматизируют.
Подходы к декомпозиции redux-based приложений отличаются от "классических", унаследованных от jQuery-based приложений.
Проблемы с декомпозицией обычно начинаются, когда пытаются эмулировать стейтфулл компоненты на базе редакса.
В редаксе точкой декомпозиции являются именно sub-state + actions + middleware. Это делается довольно неудобно, и ни в какое сравнение не идет, конечно, с "классическими" компонентами, особенно с непривычки. В первую очередь это связано с тем, что точка монтирования зашита в коде middleware и mapStateToXXX.
В редаксе отдельно переиспользуется логика и отдельно переиспользуется UI (в виде dumb components). Ну и, соответсвенно, контейнеры пишем каждый раз.
Но сила редакса в том, что он "развязывает" связь один-к-одному между данными и структурой UI. Он легко позволяет отображать одни и те же данные в нескольких видах, без дублирования кода.
UI вообще часто нелогичен с точки зрения иерархии, часто верхние уровни зависят от нижних, например, добавляются пункты меню в зависимости от выделенной строки в гриде. Редакс это позволяет делать относительно легко (послать экшен можно из любого места), на "классических" компонентах это сделать красиво невозможно без введения аналога сообщений.
А разве архитектура с однонаправленными потоками — это не MVC? Ведь именно MVC постулировала зависимости в одном направлении.
На примере Реакта:
Model -> application state,
View -> JSX
Controller -> Reducer + Middleware, разделение на логику перехода по состояниям и логику взаимодействия с "внешним миром".
Ну или самый простой вариант — это не разносить транзакционные сервисы по разным микросервисам.
PoE слэшер чистой воды, однако возможных билдов очень много, и они реально рабочие (в отличие от того же Диабло 3).
Минус — это дико однообразный геймплей, выбранный билд практически невозможно изменить, умение требует очень сильной прокачки для выживания на высоких уровнях.
Хмм, разве качество — это не бизнес-требование? :)
Сборка Angular 2 приложения — это боль и страдания. Продакшн билд приложения с компиляцией шаблонов и использованием ДевЭкстрим занимает… 8.5 минут!!!
Постигая дзен двухсекундными ожиданиями после полусекундных правок.
Существует опция вебпака watchOptions.aggregateTimeout и watchOptions.poll, которая теоретические добавляет задержку перед запуском билда после изменений.
У менеджера по продажам — процент с продаж. Если продаж нет, менеджер увольняется сам, т.к. ничего не зарабатывает. Почему их нет — это вопрос, который должен волновать руководителя только применительно к предприятию, не к конкретному менеджеру.
Если окажется, что она круглые сутки обзванивает клиентов — что это поменяет?
Невозможно контролировать реальную загруженность сотрудника, который сам оценивает время выполнения своей работы. Давать задачу на оценку другому сотруднику нет смысла, т.к. затраты времени индивидуальны для каждой задачи.
Контролировать рабочий процесс не имеет смысла, т.к. если человек не хочет работать быстро, он будет работать медленно вне зависимости от того, что он будет фактически делать. Даже в условиях тотального контроля он будет печатать одним пальцем, только еще и будет испытывать раздражение.
Для стандартизируемой работы нет смысла учитывать что-либо, кроме фактической производительности и качества. Обычно для стандартизируемой работы используется некий минимальный требуемый объем плюс оплата за выработку. Это используется в такси, швейке и много где еще. Контролировать занятость не нужно.
Кто-нибудь вообще знает пример, где может помочь учет фактической занятости?
Такое впечатление, что микросервисы, по-вашему, — это как dll, только доступные по сети.
Не совсем в тему микросервисов, но хочу заметить, что слово "бизнес" применительно к архитектуре приложения не имеет (в общем случае) отношения к коммерции, а обозначает ту "пользу", которую приносит конкретное приложение.
Поэтому сервис авторизации для конкретного приложения — это бизнес-функциональность, но в то же время используемая библиотека для OAuth2 — это уже не бизнес-часть, т.к. она универсальна и не привязана к предметной области.
Поэтому суммирование массива — не бизнес-функциональность, если у нас, конечно, не приложение по суммированию массивов (Excel).
"Резко" микросервисным не становится. Смотря что крон запускает. Если какую-то часть приложения, то приложение уже не монолит.
Пережатие видео и картинок, загружаемых пользователями, например.
Просто замечание: насчет Флоу не знаю, но тайпскрипт — это не "статическая типизация".