Обновить
-2
0

Пользователь

Отправить сообщение

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

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

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

Подставка по ноги наклоняется, вся конструкция подпружинена и позовляет покачиваться.
Ноги разгружены и спина тоже.

Работаю чуть больше месяца и очень доволен

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

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

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

тут дело вкуса и сложно вынести из беседы в коментах какой либо артефакт =) предлагаю остановиться =)
А если в какой-то момент поведение станет специфичным для подтипа этого блока?

Я переиспользую только Input ивенты в FormBloc — сами ивенты только меняют свой инпут в стейте и более ничего — вряд ли что-то сильно измениться =)

Но проблема всё равно, на мой взгляд, остается. Просто это скорее про coupling/cohesion – с одной стороны, event знает слишком много про логику обработки, с другой – эта самая логика обработки оказывается размазанной по нескольким классам

Не согласен, coupling/cohesion применимы к модулям. В разрезе Event/Bloc классы ивентов и класс блока — это один модуль и они поумолчанию тесно связаны(coupling) «ивенты конкретного блока». Это сильно связанные классы для реализации одной какой-то логики/компонента.

Про зацепление(cohesion). Если бы я в Event/Bloc засылал BuildContext — это действительно было бы сильным зацеплением на Flutter framework, но такое разумеется пресекается.

(в т.ч. и в самом блоке логика будет – как иначе сделать, например, debounce ивентов?)
debounce сложной/долгой операции — это не логика фичи, это ограничения для жизни в реальной среде с нагрузками на сеть/cpu. Поэтому debounce делаю в Bloc.transformEvents разделяя Event и _DebouncedEvent, последний выполняет долгую/сложную/нагрузо_нежалательную операцию

Я не пропагандирую такой подход =)

  • Object currentState можно специфицировать дженериком, мне всё не начать рефакторинг
  • переиспользуемые ивенты знают только о родительском FormBloc, им не нужно знать в какой конкретный блок его отправляют, достаточно чтобы он был наследником
  • про нарушение SRP категорически не согласен


Про Команду
Если у команды есть нагрузка(ex. user input), то без класса сложно обойтись и как раз нагрузку в конструктор и укладываю, а сигнатура метода выполнения остаётся неизменной.

Про несогласие о нарушении SRP…
The Single Responsibility Principle (SRP) states that each software module should have one and only one reason to change.

Ивенты блока и сам блок — это один компонент логики Business Logic Component, который вполне себе отдельный software module.
Нарушен SRP если этот модуль могут попросить изменить к примеру и Аналитик, и UX'ксер

Хабр статья про SOLID
На каждом проекте люди играют разные роли (actor): Аналитик, Проектировщик интерфейсов, Администратор баз данных. Естественно, один человек может играть сразу несколько ролей. В этом принципе речь идет о том, что изменения в модуле может запрашивать одна и только одна роль. Например, есть модуль, реализующий некую бизнес-логику, запросить изменения в этом модуле может только Аналитик, но никак не DBA или UX.

Ссылка на оригинал SRP от R. C. Martin

Посему не считаю SRP нарушенным =)
Получается в истории «я хочу чтобы кнопка submit активировалась при правильно введённых данных» — вы bool canSubmit держите не в стейте, а во view?

ps я как раз такого избегаю
С null всё понял, интутивно без манифестов в командах избегаем null и не так больно видать мне )

Про кодген — чаще в командах начинающие ребята и это накладывает ограничения.

Я использую свой подход к ивентам — делегировал им исполнение, получилось скрещение паттернов Состояние и Команда(ивенты у нас инстансы команд по сути)

каждый ивент имплементит метод,
abstract class BlocEvent {
    Stream<Object> mapEventToState(Object currentState, B bloc);


текущий стейт специально добавлен чтобы не пользовать геттер bloc.state и получить доступ к стейту
if (state is ...) state.foo


Получается bloc является контекстом паттерна состояния и содержит только зависимости
class BarBloc extends BaseBloc<...,...> {
    final Api api;
    final Foo foo;
}


А BaseBloc делегирует исполнение ивентам, по сути являясь диспатчером очереди команд
class BaseBloc extends Bloc<...,...> {
    @override
    Stream<BlocState> mapEventToState(BlocEvent event) async* {
    yield* event.mapEventToState(state, this);
  }
}


Плюсы
  • быстрый переход к коду — тыц на ивенте и ты уже видишь что хотел
  • более читабельнее — читаешь отдельную команду и не листаешь весь класс блока до метода _mapEvent
  • переиспользование ивентов ввода(с валидацией) в разных блоках формах ввода — телефон, пароль, код из смс


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

Есть комент к…

Следующий момент (я о нем уже упоминал, но он достоин того, чтобы по нему еще раз пройтись) – NoSuchMethodError (здравствуй, Java с ее NullPointerException). Говорят, скоро все будет хорошо, осталось всего лишь дождаться миграции самого Flutter'а и всех библиотек, но пока – что есть, то есть.


noSuchMethod актуален только при вызове на dynamiс, вызвать любой метод на null невозможно и нет никакой связи с Java NPE

Собственно прошу объяснить, вдруг это у меня лыжи не едут, либо поправить статью =)

За статью спасибо!
habr.com/ru/post/474968/#comment_20862172

минусатор, есть аргументированные возражения этому коменту?
Cделать приватным final BehaviorSubject onCounterUpd;
Наружу только Observable или Stream, потому что я могу миновать incrementCounter() и сунуть туда какое захочу value и оно минует вашу логику

Это как раз вопрос велосипеда, он уже несостоятелен и его приходится рихтовать.

Зачем здесь async функция? Future incrementCounter() async
Я не пишу решения счетчика на BLoC, оно уже есть от оригинала(Felix) в документации.

Я вношу вклад в сообщество помогая в чатике и критикуя явные проблемы, особенно если это публичная статья для новичков с грубыми ошибками.
меньшее количество строк != читабельность && easy поддержка

BLoC & MVI смысл один один поток на вход, один на выходе
+ предсказуемый стейт

Вы пишете свой велосипед, который может потерять этот +, если не один единственный поток на вход(очередь событий)
Почитайте про синдром NIH

Жду статью про велосипед дериватив MVU(TEA), Redux, MVI, BLoC
flutter_bloc (дальше упоминаю как BLoC) Felix'a Angelo это чуть по-другому реализованный MVI от Dorfman'а
UDF + Rx

Как тебе угодил MVI, но не угодил BLoC?

Intent -> Model -> View
Event -> State -> View

эквивалентные вещи и через тот же Rx
habr.com/ru/post/448776
Вы в статье против BLoС, но вы не в курсе что flutter_bloc — это дериватив MVU(родоначальник подхода ELM TEA)
guide.elm-lang.org/architecture
In fact, projects like Redux have been inspired by The Elm Architecture, so you may have already seen derivatives of this pattern


MVI это то же дериватив MVU и бойлерплейта там тоже много

flutter_bloc, MVU(TEA), Redux, MVI эквивалентны (просто разные реализации)

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

Не нагнетайте
поправь
final onCounterUpd = BehaviorSubject.seeded(count)


убери из конструктора
_Counter(this.count) {
onCounterUpd.add(count);
}


убери из StreamBuilder'а
StreamBuilder(
initialData: _counter.onCounterUpd.value,
stream: _counter.onCounterUpd,
по пункту 2
api.flutter.dev/flutter/widgets/StatelessWidget-class.html
The build method of a stateless widget is typically only called in three situations: the first time the widget is inserted in the tree, when the widget's parent changes its configuration, and when an InheritedWidget it depends on changes.


api.flutter.dev/flutter/widgets/StatelessWidget/build.html
The implementation of this method must only depend on:
the fields of the widget, which themselves must not change over time


Не зная первой цитаты ты стреляешь себе в ногу в будущем(ближайшем)
Не зная второй цитаты ты опираешься на внешние данные, полностью перечя ей (upd тут я неправ)

Ты не читал документацию или не перечитал с пониманием
Автор непонимает основ Rx и Flutter
Ошибки
1. инициализация значения в BehaviorSubject не через named конструктор .seeded(initValue)
2. эта ошибка вытекла из первой, но показала непонимание основ Flutter.
Нельзя ничего инициировать в методе build() любого типа виджета

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность