As much as I like your library, correct me if I'm wrong but I think it is much closer to the Redux architecture than it is to a Bloc one.
Although there is no clear definition of a Bloc yet, from what I've gathered it's much more reactive, should use Sinks are input, and Streams as output.
While this library is used to convert Events (like strongly-typed Redux Actions) into a single State output, using the mapEventToState
reducer function, which is very cool in its way, just not what a Bloc architecture is.
https://www.didierboelens.com/2018/08/reactive-programming---streams---bloc/
or maybe I'm just missing the point on how to use it with Streams/Sinks
Hey, thanks for taking the time to bring this up!
While there are some similarities to redux (mainly the naming), I would argue that this package is still helping implement a bloc architecture.
The goal of the package is to abstract the streams/sinks and make it easy for developers to focus on the business logic instead.
In short, the Business Logic needs to:
- be moved to one or several BLoC s,
- be removed as much as possible from the Presentation Layer. In other words, UI components should only worry about the UI things and not about the business,
- rely on exclusive use of Streams for both input (Sink) and output (stream),
- remain platform independent,
- remain environment independent.
As you correctly stated, there really is no concrete definition of Bloc. By the definition in the article you referenced (above), the bloc package, does in fact, conform.
In my opinion, Bloc is just trying to answer the question of how to separate business logic from ui components and it uses sinks/streams as input/output. I think the part that might be confusing is my naming. When I say state
it really could be anything. State
could be an int
in the case of the counter application or it can be a more complex object in the case of login. The goal again was just to have the Bloc contain as much of the business logic as possible.
Let me know if that helps and I would definitely encourage you to checkout the example counter app in the repo (https://github.com/felangel/bloc/blob/master/example/lib/main.dart) and compare it to the counter app in the article you referenced. I think you'll find them to actually be quite similar.
I really appreciate your feedback and I would love to hear your thoughts.
True, true, state or no state is fine, I'd just argue that it should probably be renamed to ReBlox (™️) or something, in that it derives from the actual pure Bloc pattern presented by various Google employees.
I've imported it thinking it would help me forcibly apply state outputs into my stream-based blocs, when it actually makes the code less rx-y I think, though I can only blame myself for not getting this out of the samples and readme, but hey ;)
Though they (google) probably won't need the Bloc pub package name anytime soon, because it can be implemented with built-in classes, I think it's a bit misleading.
Also, ReBlox is such an awesome name...
Or maybe I'm just stupid because I can't see how to pass through the map method while staying in full functional Rx/Streams. have you got any sample ?
Anyway I'd definitively recommend this lib for ppl that would avoid Rx, I know some of them ;)
Thanks
So I struggled with the name a bit but decided to go with bloc because I am not aware of the “pure” bloc pattern you described. Can you point me to where I can learn more about it?
Also, there is already a lib called rebloc which is more what I think you’re describing.
I agree that the rx is abstracted but that was my intention from the beginning.
Can you describe your use case a bit more and I can try to advise on whether bloc makes sense?
Thanks for all your feedback!
oh ok, yes, rebloc is even more like redux.
just thinking out loud here, what about keeping the awesome
something like :
class CoinsBloc extends Bloc<CoinEvent, CoinsState>
{
CoinsBloc()
{
eventSubject // instead of your _eventSubject
.where((ev) => ev is OnCoinSelectedEvent)
.map((ev) => ev as OnCoinSelectedEvent)
.map((ev) => new SelectedCoinState(ev.coin))
.listen(setState);
// other 'mappings' here
}
// in Bloc class :
void setState(S state) => _stateSubject.add(state);
that would allow for more complicated bindings with combinelatest and external rx sources (from other blocs)
or maybe a RxBloc<evt, state> extends Bloc<evt,state>
that would implement mapEventToState to do nothing I guess.
also eventSubject could instead be a OnEvent that would combinelatest the last event and the last state :mindblown: ?
You can currently manipulate the event stream by overriding the transform method haha. Does that address your concern?
The reducer is just to convert the events to the view model (states) for the presentation layer to consume. How would the view model get created without mapEventToState?
Can you put together a simple example of the classic counter app to demo your proposed usage?
Thanks for the awesome feedback!
meant something like this
https://github.com/benoitjadinon/bloc/commit/6876f24b8467c407aa1bc9c89715bbf5f6088596
not super interesting with +1 -1 but will get awesome when combined with external blocs outputs
but maybe that diverges from redux guidelines, I'm not really familiar with the whole thing to be honest. but I'm not fond of one-function (spof) reducer that becomes a big mess of switch cases and business logic.
coming from mvvm+rx, I'm looking for rx-first BLoCs that output some state. events as input is the cherry on the cake.
I might create my own lib if you think it does not fit yours.
(awe)some BLoC videos I was referring to :
https://www.youtube.com/watch?v=PLHln7wHgPE (shared blocs with angular)
https://www.youtube.com/watch?v=n_5JULTrstU (blocs @ google adwords)
https://www.youtube.com/watch?v=KjoMnsc2lPo (not blocs but fun)
Your branch is very interesting.
I'm not so worried about diverging from redux guidelines haha but how does a constructor full of reactive transformations differ from a mapEventToState
full of different state transformations? I think both approaches have that in common. Other than that, it seems pretty straightforward and I think we can work to incorporate it into the current library.
I think if we were to introduce an RxBloc
maybe we should rethink what a regular Bloc
is. It might make sense to create a ReduxBloc
(although I'm not too fond of the name since it is misleading) and move the mapStateToEvent
exclusively into the ReduxBloc
while keeping the base Bloc
as minimal as possible (just responsible for Streams/Sinks and disposing them).
I want to focus on making the library as simple and easy to use as possible while simultaneously being able to cover a wide variety of use cases.
Alternatively, you can definitely create a separate library if you want to.
Thoughts?
Awesome!, but let's fiddle with the concept a bit more first, maybe with a more complete example.
ReducerBloc
vs RxBloc
is cool, because mapStateToEvent
is unused inside of RxBloc
.
About the constructor thing, it's also to setup the subscriptions asap. cause with a mapper reducer, they kinda would only be called imperatively after an action is received, they wouldn't be so 'reactive' (as a push-based idea) and I'm guessing that's exactly what redux fans do not want, they want control and stuff only to react to events/actions/intents
What i'm searching for as an architecture is more organic building bloc(k)s, that are reacting to each other.
Example : a connectivity state bloc, can be subscribed to by others, and the connectivity state could influence subscriptions it is combined with.
let's fiddle a bit more with the concepts. thanks for being so open-minded ;)
I'll be looking for rx+redux information, cause it seems to me both are not fit to work together
Sounds good! I’ll think about it some more as well and we can put together a proposal with example usage, documentation, etc... before we start working on the implementation. I think once we get the interface down it shouldn’t be too difficult to incorporate.
One thing I’ll say about bloc vs redux is typically I’ve seen bloc used for local state management while redux is used for global state management. Not sure that it’s relevant to our discussion or this library but just wanted to throw that out there.
Closing this and we can continue to discuss outside of this issue.
@felangel you mind creating a gitter channel ? I've got * ideas *
@benoitjadinon yup just created one and added the badge to the readme.
Just a little comeback on this.
I see many peoples on different mediums claiming that they do BLoC using this library.
But this is confusing because it is clearly not BLoC.
That's bad because the name "BLoC" is popular, and whenever someone recommends this pattern, there's a big chance that they'll land here.
Pardon the wording, but it feels like stealing the popularity of the original pattern.
@rrousselGit thanks for your feedback. As I mentioned earlier in this thread, this library is just our interpretation of the BLoC design pattern described here.
BLoC stands for Business Logic Component.
In short, the Business Logic needs to:
- be moved to one or several BLoC s,
- be removed as much as possible from the Presentation Layer. In other words, UI components should only worry about the UI things and not about the business,
- rely on exclusive use of Streams for both input (Sink) and output (stream),
- remain platform independent,
- remain environment independent.
The goal of this project is to help the community not to profit or steal anything from anyone. All of the code is open-source and we don't profit from it in any way.
Thanks!
The issue is:
rely on exclusive use of Streams for both input (Sink) and output (stream),
flutter_bloc
do not respect this. Instead, it uses a dispatcher/reducer combined with immutable state – which BLoC never mentioned.
Both the authors of the BLoC talk and the article you linked agreed that a BLoC looks like this:
class TodoBloc {
Stream<List<Todo>> todos;
Stream<List<Todo>> filteredTodos;
Sink<Todo> addTodo;
}
flutter_bloc
is very far from that interface.
we don't profit from it in any way.
This is not about profit. It is about being fair to the community.
Peoples are interested in BLoC through the talks from multiple Google employee.
But when they search BLoC on google, they will instead land _here_. Which deviate greatly from what was explained in the talk – but with the same name.
That's tricking the community into thinking that _your interpretation_ is what Google speakers meant.
@rrousselGit, Sorry, but as a developer using this package for a fairly large project, I have to disagree with your statement "That's ticking the community into thinking that your interpretation is what Google speakers meant."
Most of us have done exactly what you see in the Google videos, then tried to abstract out the code for better organization and readability. We have written something like this ourselves before using this package. So I don't think the developers are accidentally using this package.
then tried to abstract out the code for better organization and readability.
That's the point. You deviated from the original pattern to make it something custom, different, that better fits your needs.
It's fine. But that's not what was advertised as BLoC.
Other packages are a lot more honest about them being _their interpretation_. Take "rebloc", "fish_redux" as name example.
To further prove that, this package is extremely similar to rebloc from a Flutter team member.
And that packages officially states that it is not pure BLoC but a mixture of BLoC and Redux.
Most helpful comment
@rrousselGit, Sorry, but as a developer using this package for a fairly large project, I have to disagree with your statement "That's ticking the community into thinking that your interpretation is what Google speakers meant."
Most of us have done exactly what you see in the Google videos, then tried to abstract out the code for better organization and readability. We have written something like this ourselves before using this package. So I don't think the developers are accidentally using this package.