[HN Gopher] EventBus 3.1 with plain Java support
       ___________________________________________________________________
        
       EventBus 3.1 with plain Java support
        
       Author : qdghmkop
       Score  : 39 points
       Date   : 2021-06-19 14:11 UTC (8 hours ago)
        
 (HTM) web link (greenrobot.org)
 (TXT) w3m dump (greenrobot.org)
        
       | billjings wrote:
       | 1. I'm happy to see that EventBus has made this change. Let's
       | hope the long overdue AndroidX migration (we're three years into
       | AndroidX, folks) follows close on its heels.
       | 
       | 2. Event buses are really, really bad. (At least, this kind of
       | event bus is) The Android community has some battle scars on
       | this, so I'll drop a little history for the broader audience
       | here.
       | 
       | Event buses were an architectural fad that were briefly explored
       | to address the challenges of communicating in the immature
       | application architectures of the era. The maintenance lifetime of
       | Otto, a competing event bus, is a good reference point for when
       | they might have been considered reasonable practice: 2012 through
       | 2015: https://github.com/square/otto/tags
       | 
       | This tool was abandoned by leading edge shops when they saw how
       | rapidly it could make a complete hash of any thoughtfully laid
       | out architecture. Connections made in an EventBus based
       | application tend to be many-to-many, without the sender of an
       | event having a direct reference to its recipient or vice versa.
       | This is incredibly irritating to debug, and breeds communication
       | patterns that are challenging even in a disciplined codebase. In
       | an _undisciplined_ codebase they can be breathtakingly byzantine,
       | even in small scale development.
       | 
       | Instead of using this, many leading edge shops started switching
       | to RxJava at around 2016. RxJava is a powerful tool with sharp
       | edges and a steep learning curve, but the need was so imminent
       | and the failings of the existing EventBus-style tools so clear
       | that it caught on. Indeed, while Google understandably felt that
       | RxJava was too complex to recommend as an introductory tool,
       | their first party LiveData tool released a few years later was
       | essentially RxJava with the edges sanded off.
       | 
       | Of course, we're now even further down the road than that. Kotlin
       | coroutines+Flow presents its own paradigm shift to contend with,
       | but it's a clear step up from all the other solutions, and has
       | Google's blessing as well. There's not much reason to start new
       | development on top of anything except coroutines.
       | 
       | So where does that leave EventBus?
       | 
       | EventBus is at this point about as legacy as you can get without
       | going all the way back to AsyncTask. Anytime I'm doing a code
       | audit and see this dependency, red flags immediately go up: not
       | only is it a sign that this code is far behind the times, but
       | it's also a flag that I'm going to find some truly unfortunate
       | and problematic design decisions.
       | 
       | People need what they need, and it's of course good to see
       | critical dependencies for legacy applications get upgrades. But I
       | can't recommend strongly enough to avoid this tool.
        
       | SV_BubbleTime wrote:
       | Absolute side topic, but has anyone used an EventBus-like system
       | for C? I have an RTOS project and would like to have some
       | eventbus options to simplify inter task communication.
       | 
       | As with everything, lots of options outside of C, not many in.
        
         | trzy wrote:
         | https://medium.com/prooftrading/proof-engineering-the-messag...
         | 
         | Probably C++ and a bit more complex than you need but could
         | serve as a source of inspiration for your own implementation.
        
       | jafarlihi wrote:
       | If you want to emit and catch events in Java with a lot less
       | overhead check out my tiny event emitter library:
       | https://github.com/jafarlihi/eemit
        
       | an_opabinia wrote:
       | Calling methods via strings where you control all the source code
       | to your own application is pretty toxic.
       | 
       | Since there are no network or persistence boundaries - it's a
       | local app the developer owns 100% of - there are no engineering
       | constraints that require the kind of decoupling of an event bus.
       | 
       | The execution boundary thing ("post messages to other threads")
       | is also pretty dumb. There are a dozen simpler ways to coordinate
       | between a UI and background / business logic thread. Since most
       | application's long-running behavior is _only_ HTTP calls, today
       | 's developer doesn't have to think about it at all - the callback
       | or promise (CompleteableFuture) returned by their URL fetcher
       | forces them to do the right thing.
       | 
       | RxJava is almost always the better choice to be more expressive
       | about UIs. Otherwise, an Android developer should adopt Kotlin
       | for coroutines. Or, frankly, reduce timeouts for HTTP calls to be
       | closer to frame rendering times (16-32ms), pay the extra pennies
       | to serve networked services better, and focus on low-latency
       | remote APIs.
        
         | optymizer wrote:
         | I find your comment overly dismissive of EventBus and I
         | respectfully disagree with you on not needing to decouple
         | components for a local app.
         | 
         | I've worked with GreenRobot's EventBus on a large (100M+
         | installs) app years ago. I worked with RxJava as well. I've
         | also worked with more feature-rich proprietary solutions to
         | EventBus.
         | 
         | EventBus is a library with a straightforward API that junior
         | developers can use with little issues. "Launch this event and
         | add this annotation to make sure it gets processed off the main
         | thread". This is a very real practical advantage, that is not
         | unique to EventBus, but it works well for large teams and does
         | not require you to rewrite methods to return Observable objects
         | just to be able to chain some things together. Does EventBus
         | lead to some eventual problems? Yes. Are they manageable? Yes.
         | 
         | On the other hand, RxJava is a framework and, once it's in, it
         | starts spreading Observables through all the classes in the
         | codebase. Most developers need significant time to ramp up to
         | become productive with it. I used to work with 30+ developers
         | on an Android app. The app I work on now at a different company
         | has thousands of developers working on it. People at these
         | companies collectively concluded that RxJava doesn't bring
         | sufficient benefits to these large teams. Both companies have
         | ripped it out pretty quickly after the initial excitement wore
         | off and the downsides started kicking in.
         | 
         | Kotlin made things much better in the recent years, but it
         | doesn't mean that EventBus is now 'dumb' or 'toxic'. Coroutines
         | on Android weren't widely used in these large apps a few years
         | ago, before Google announced official support, so people were
         | calling "new Thread()", using AsyncTask or, more likely, having
         | ExecutorService threads created by various components in the
         | design without any regard to CPU contention or priority of
         | execution, and instantiating "new Runnable" all over the place.
         | 
         | Also, using the HTTP handler's thread to process business logic
         | _blocks that thread_ and makes it unavailable until the logic
         | is done running - which could take a long time. Boundaries for
         | execution are absolutely required, unless you're working on a
         | small app that doesn't need to care about these issues and
         | where pretty much anything goes. You want to have control over
         | which logic runs on which thread, otherwise you'll needlessly
         | spend time debugging race conditions and deadlocks in
         | production, like me. HTTP threads for delivering HTTP results,
         | image threads for processing images, database threads for
         | writing to the database, and you want to set priority for
         | background, I/O and foreground threads.
         | 
         | That last point you have about reducing timeouts to be closer
         | to frame rendering times is also incredibly narrowly useful.
         | You can invest a ton of time and have the server respond in
         | microseconds but if your users in Bangladesh are using cheap
         | $20 Android phones over 3G connections you still have the same
         | problem and you won't be anywhere near 32ms.
        
           | an_opabinia wrote:
           | > Also, using the HTTP handler's thread to process business
           | logic _blocks that thread_ and makes it unavailable until the
           | logic is done running - which could take a long time
           | 
           | This is true.
           | 
           | > if your users in Bangladesh are using cheap $20 Android
           | phones over 3G connections you still have the same problem
           | and you won't be anywhere near 32ms.
           | 
           | This is of course the crux of the issue. In my opinion,
           | either wait until the infrastructure catches up, or don't
           | write an _interactive_ networked service, for that audience.
           | 
           | Anyway, to at least advance the conversation, I searched for
           | some big open source projects that use EventBus. (https://gre
           | p.app/search?q=org.greenrobot&filter[path.pattern...). Signal
           | for Android is a good example (https://grep.app/search?q=org.
           | greenrobot&filter[repo][0]=sig...).
           | 
           | Let's just take a look at the first class that appears in
           | search results. "SqlCipherMigrationConstraintObserver." Okay,
           | how in practice does this random thing get registered on the
           | EventBus?
           | 
           | Oh look, it's a file that is just instantiating a bajillion
           | classes: (https://github.com/signalapp/Signal-
           | Android/blob/master/app/...) Because dependency injection is
           | stupid on GUI applications, and it messes with all sorts of
           | benefits of direct invocation, they do direct invocation
           | anyway. Except, instead of just like, calling whatever it is
           | they need in SqlChiperMigrationConstraintObserver (or I don't
           | know, just using a Subscription, it's literally called an
           | Observer), they do the _same exact work_ just in a more
           | puzzling way, via instantiating in one class and invoking
           | in... who knows where.
           | 
           | Again, this is why I say toxic. You're going to poke around
           | the repos of what's going on when people actually use
           | EventBus, and you'll discover, in the long term, that people
           | will end up doing O(~direct invocation) work anyway, but
           | _stringly typed_ (or in this case, _annotatively typed_ ).
           | 
           | RxJava has its significant downsides. It's still indirect,
           | it's very hard to debug call stacks with them! RxJava call
           | stacks are meaningless. This is the right criticism. The
           | wrong criticism is, "Bad developers can't handle it."
        
             | randiRando wrote:
             | I agree with your take on event busses but I feel like it
             | describes RxJava pretty well too.
             | 
             | > RxJava has its significant downsides. It's still
             | indirect, it's very hard to debug call stacks with them!
             | RxJava call stacks are meaningless. This is the right
             | criticism. The wrong criticism is, "Bad developers can't
             | handle it."
             | 
             | How about "It's still indirect, it's very hard to debug
             | call stacks with them! RxJava call stacks are meaningless"
             | and because of that bad developers can't handle it ?
             | 
             | Context: Have worked with RxJava (1&2) for about 6 years on
             | different products and I agree that Rx is powerful but it's
             | incredibly easy to over-use and abuse to the point of being
             | a net-negative for a codebase. I think it takes a very
             | disciplined developer to work with Rx. I love/hate Rx
        
         | mwcampbell wrote:
         | > Or, frankly, reduce timeouts for HTTP calls to be closer to
         | frame rendering times (16-32ms), pay the extra pennies to serve
         | networked services better, and focus on low-latency remote
         | APIs.
         | 
         | To be clear, are you suggesting that network requests in an
         | Android app should block the UI thread, on the assumption that
         | everyone will have a good enough connection (and one close
         | enough to your server) to receive the response quickly?
        
           | an_opabinia wrote:
           | If you really want to achieve a great experience for an
           | _interactive_ networked application, you should engineer
           | things where everyone is close enough to your servers to get
           | a response quickly. Or design an experience that does not
           | need to be network interactive.
           | 
           | > are you suggesting that network requests in an Android app
           | should block the UI thread
           | 
           | I'm suggesting that if network requests over a cellular
           | connection could just be made within a frame (really, a tick,
           | nothing is that fast), like they are on Fortnite or Roblox
           | for Android, for example - if people applied the same
           | engineering practices and standards to GUI applications as
           | for realtime multiplayer games - yes, the apps would be way
           | better, and as a side effect, way easier to author. The
           | server and deployment story would get more complicated. But
           | maybe that's a good thing, to put the hard work where it's
           | easier to do.
           | 
           | For a concrete example of what that would look like, the
           | io_uring thing posted here just a bit ago was really
           | fascinating. It's probably the way HTTP should have been done
           | in Java from the get go - a request that returns immediately,
           | but you must poll in the GUI that actually needs its results
           | to render, and you must poll at the right time. Clunky, but
           | still, all synchronous and all direct.
        
             | Marazan wrote:
             | Err network games deal with latencies in the hundreds of
             | milliseconds.
        
             | mwcampbell wrote:
             | My understanding was that unreliable and high-latency
             | mobile connections are inevitable, especially outside of
             | major metro areas in the developed world, so we have to
             | design around that.
        
         | sgt wrote:
         | Will also need a lot of unit tests that would normally be
         | unnecessary.
        
         | ncann wrote:
         | Maybe I'm dumb but I've read your comments a few times over and
         | I still haven't quite understand what you were trying to say.
         | 
         | "Calling methods via strings where you control all the source
         | code to your own application " -> what do you mean by this and
         | how is it relevant to this library?
        
           | an_opabinia wrote:
           | EventBus uses an annotation processor and reflection to reify
           | a call. A ton of things look like this. Like that's also sort
           | of what a REST API is. It makes a ton of sense for crossing
           | boundaries from owning the code to not owning the code, and
           | back again.
           | 
           | But since you own the code, you own 100% of the source in
           | your GUI application, why would you need indirection? There's
           | no reason to hide part A from part B. That's why giant
           | companies who author all their stuff in house use monorepos.
           | I can't believe I'm saying this, but hiding stuff, like
           | trying to mark code as proprietary or "not maintained by my
           | team" (as Amazon would do), is a social construct.
           | 
           | This is relevant to the library because many times, people
           | who have the experience of using this library in real Android
           | apps and having a positive experience with it - they are
           | using the library for to do, "my team does this part, and
           | this other team does that part." "This developer is stupid
           | and junior, so must decouple their work." Toxic! Amazon:
           | extremely toxic. If I were a code anthropologist, DI and
           | EventBus would be, "Artifacts of toxicity."
           | 
           | When you look at how it's used by other apps, like Signal for
           | Android, with small teams, it just looks stupid, and they
           | work around its warts anyway, and use direct calling anyway,
           | just in a far more roundabout fashion.
        
             | ncann wrote:
             | > But since you own the code, you own 100% of the source in
             | your GUI application, why would you need indirection?
             | 
             | So what is your proposed non-indirection way? I'm assuming
             | you meant the traditional listener/observable way of
             | registering event producers and event listeners together,
             | in which case this FAQ explains pretty well their downsides
             | compared to an event bus:
             | 
             | https://github.com/google/guava/wiki/EventBusExplained#faq
        
           | wffurr wrote:
           | Instead of posting a string and a payload to the event bus,
           | which a listener picks up and unpacks to call method in the
           | receiver, just call the method.
           | 
           | It does introduce a direct dependency where it was indirect
           | before, but is otherwise much simpler and significantly
           | faster than all the string comparisons.
        
             | chris_overseas wrote:
             | There is no string comparison here, the subscriptions and
             | posting of events is based on the class of the POJO being
             | sent.
        
             | ncann wrote:
             | Ah ok I guess my confusion is from the fact that there's no
             | explicit "string" being passed around with this library,
             | but the concept of a payload makes sense.
        
             | void_mint wrote:
             | > It does introduce a direct dependency where it was
             | indirect before
             | 
             | Which is okay if you've used any amount of DI and
             | testability-focused thinking to set up your code.
             | 
             | The event bus pattern works great if you don't know (or
             | want to know) what's going to happen to an event once it's
             | emitted. If the only thing that happens is a different
             | method in your app gets triggered, you should really just
             | trigger that method and skip the event bus altogether.
        
             | hota_mazi wrote:
             | Introducing the direct dependency is _exactly_ what you
             | want to avoid and what event buses provide.
             | 
             | With your approach, you are coupling views and model with
             | n*m links, with an event bus, it's just n+m. Much easier to
             | decouple your logic.
             | 
             | I do agree with you that I'm not a fan of the loss of
             | static typing that event buses usually introduce.
        
               | an_opabinia wrote:
               | > Introducing the direct dependency is exactly what you
               | want to avoid
               | 
               | Why? It's a GUI application on Android. Everything that
               | listens to this event bus is a direct dependency
               | configured at build time. Every modern optimization, like
               | ahead of time compilation and code stripping, benefits
               | from direct dependencies. This is why I used the word
               | toxic, and not stupid.
        
           | Quekid5 wrote:
           | I think they might be referring to Stringly Typed
           | Programming.
        
       | tarkin2 wrote:
       | Edit. I shouldn't post on waking up!
        
         | EvilEy3 wrote:
         | This has nothing to do with JS.
        
       | happyweasel wrote:
       | What's the advantage of this eventbus over good ole' Guava
       | Eventbus from google? It's lean and mean .. and more-or-less
       | typesafe..
        
       ___________________________________________________________________
       (page generated 2021-06-19 23:01 UTC)