

Show HN: Msngr.js, a messaging library for JavaScript - BinaryIdiot
https://github.com/KrisSiegel/msngr.js

======
BinaryIdiot
I started working on this small library some time ago and use it in many of my
personal projects. It’s not meant to replace any existing libraries (though
you could certainly use it to replace some things here and there) but to
augment by using messaging. I use this quite frequently when I work with web
components where I try to make my messages as generic as possible so I can
separate my UI from my business logic completely.

Not sure if others will find it useful but figured I’d see what feedback
hacker news would have, if any :)

~~~
pcthrowaway
Hi, thanks for sharing. I'm fairly inexperienced with using any kind of
message-based event management so my question may reveal a deficit in
understanding on my part: Would something like this be a javascript-runtime
environment translation of message brokering libraries like ZeroMQ and
RabbitMQ? If so, does that mean an application that already utilizes a
messaging library such as those two could plug in msngr.js on the client or
server-side (if using node) and use messages received from the message broker
more directly, instead of having to translate them into emitted events?

~~~
BinaryIdiot
So msngr.js currently only works within your current process (so a web page or
a node app) and is meant to help organize code and interface with internally,
and externally, developed components. I do hope to eventually interface it
with other brokering libraries but since it's a small, pet project of mine
that's a bit far off I think.

------
prottmann
What is the benefit of msngr compared to other pub/sub libraries like
AmplifyJS
([https://github.com/appendto/amplify](https://github.com/appendto/amplify))
or Postal
([https://github.com/postaljs/postal.js](https://github.com/postaljs/postal.js)).

Both of them are battle tested and have a big community.

~~~
jbob2000
We moved away from the pub/sub model in our app. It became too difficult to
manage all the pub subs happening across modules, especially in a large
project with many team members. We're restructuring our app to be better
organized and to use a live-binding library.

~~~
currywurst
I'm really interested in how this model scales, so could you please explain a
bit what was difficult to manage in pub/sub ? I would imagine that if your
topics and channels are well-defined and documented in one place, and the
modules also declare what topics they pub/sub, one would get clear boundaries
for maintenance.

Also, what do you mean by live-binding ?

~~~
jbob2000
> if your topics and channels are well-defined and documented in one place

That's the problem. It's hard to get this done. Developers like to develop,
it's like pulling teeth to get us to document things. I've found its much
easier and faster to have a codebase that speaks-for-itself, in a way.

Don't get me wrong, we definitely _do_ document things. But the miniscule
things like implementation details are just too small to be worth spending
time on.

We've been in production for about 7 years now. Our team has pretty much
completely turned over in that time. Knowledge and conventions get lost, much
better to have the codebase dictate how things should be done. A developer
will read the code+comments before they read the documentation.

Hmm how to explain live-binding... Angular's $scope and CanJS' Observables are
examples of live-binding. Basically, you can pass around a live-binding object
and changes made to it in one module are immediately reflected in another.
Whereas with a pub/sub model, you publish messages out to a hub and it is up
to the module to decide how to react to the message.

A good example of how we use live-binding is with sessions. We have a global
live-bound object that holds the session data. Each module that needs to use
session info simply refers to this global object. If we perform an API call
that returns 401 and kills the session, our API module kills the session
object and all our modules immediately respond to this change. We don't have
to declare any listeners, or subscribe to any pubs; we just use the object.

~~~
mandeepj
> Basically, you can pass around a live-binding object and changes made to it
> in one module are immediately reflected in another.

This can work pretty good up to certain level but after that this can go out
of hand pretty quickly. The cascading effect will become hard to debug.

> Whereas with a pub/sub model, you publish messages out to a hub and it is up
> to the module to decide how to react to the message.

At least it is at one place to modify and debug. This is loosely coupled. You
can easily decide how to react based upon messages. Very easy to introduce new
workflows or use cases.

> We have a global live-bound object that holds the session data.

Looks like you are sitting on something that is waiting to explode soon.
Global objects are evil

~~~
jbob2000
> This can work pretty good up to certain level but after that this can go out
> of hand pretty quickly. The cascading effect will become hard to debug.

Totally agree, we recognized this before we began using them. They are used
for common elements between modules, and we don't hold a lot of data with
them.

>At least it is at one place to modify and debug. This is loosely coupled. You
can easily decide how to react based upon messages. Very easy to introduce new
workflows or use cases.

Maybe. With pub/subs you still need to go hunting for a rogue publish.

With my session example, we use the session object to display the user's name
in various places. It's easy to use the session object to do this; I can just
stick it in the view. With pub/subs, I would have to listen for the publish
and then update the view, and I would have to do this in many modules. Turns a
0 line operation into a 5-line one.

> Global objects are evil

Not true at all! A session is a global thing, isn't it? Why wouldn't it belong
in the global context? Edicts like "global objects are evil" end up paralyzing
your development and you will sometimes have to do even more evil things to
get around them.

~~~
mandeepj
Looks like you know what you are doing. Good.

>With my session example, we use the session object to display the user's name
in various places. It's easy to use the session object to do this; I can just
stick it in the view.

Correct. No need for pub\sub here since data is coming from server and we are
not manipulating it. Pub\sub is required in scenarios where actions are taking
place on client side like user registration, forgot pwd or ordering a product
etc

> A session is a global thing, isn't it? Why wouldn't it belong in the global
> context?

Absolutely. Session is more of a read-only object after once set on the
server. I know some people use it to store objects and that is not right.

A bad example of a global object would be

var settings =

{ showCheckoutbutton: false, Ordertotal: 200, calculatedtax: false,
showOffers: true, ShowTopbar: false }

I constructed this hypothetical object just to give an idea about an evil
entity. Some developers would set certain properties in certain functions. It
would definitely show zombie behaviour at certain times.

I enjoyed our conversation. Thanks for being so nice with your response.

------
Mahn
What problem does this solve? Can't you just simply declare the "loosely
coupled" methods as functions and call them wherever needed in vanilla
javascript? Perhaps I'm missing something but judging by the examples, and
assuming the messages are local to a particular process, I don't see why would
you do this:

    
    
        msngr.register({ topic: "Save", category: "Profile", dataType: "application/json" }, function (payload) {
            console.log("Save profile information here");
        });
    
        msngr.emit({ topic: "Save", category: "Profile", dataType: "application/json" }, {
            name: "Kris",
            country: "United States"
        });
    

Rather than:

    
    
        function saveProfile(payload) {
            console.log("Save profile information here");
        } 
        
        saveProfile({
            name: "Kris",
            country: "United States"
        });

~~~
michael_fine
The examples don't illustrate this very well, but the benefit of message
passing is flexibility/decentralization of events. To use your example, if
when you saved the profile you wanted to also pass it to an internal analytics
database, makes more organizational sense to have that database just register
a listener for a save profile event, rather than having to add a very
auxiliary step within the saveProfile function. This gets more and more
helpful the more listeners you have, and while I haven't looked at this
library in depth, can also be a very natural way of writing async code.

