slouchpie
Associations, PubSub and live-updating - larger payload or enumerable iteration?
Imagine this familiar situation. We have a LiveView that renders a list of posts. Each post has an author (user) and multiple comments. Each comment also has an author (user). The LiveView process subscribes to some “new comment” topic. When a new comment is created on a post, this information is broadcast.
In this situation, it is clear that the PubSub payload should include the comment’s author preloaded. This could be a new user, who registered after the LiveView mounted. All is good.
Now imagine a different situation. We have a LiveView that renders a restaurant menu. A user can add items to their basket. A basket can be shared, so multiple users are using the same basket. The LiveView process subscribes to some “new basket item” topic. When an item is added to the basket, this information is broadcast. The LiveView is also subscribed to menu changes, e.g. menu item price changes. This means the LiveView process “knows” all the menu details.
In this situation, the basket item is associated to a menu item. My scruple is this: should the PubSub payload include the menu item preloaded on the created basket item struct? It seems wasteful, since, assuming our LiveView also subscribes to menu updates, the LiveView already “knows” the menu item details (not using streams here). Moreover, if, say, a menu item price changes, we will need update all assigned basket items that have this menu item preloaded.
With this in mind, it seems silly to trust/use a basket item’s preloaded menu item association. So I naturally think “OK, I will just find the menu item in the menu assign and infer details from that for rendering the basket item”. However, my menu items are a list, and iterating over a list for every basket item render is obviously very bad. OK, so maybe I should instead have a map of menu item IDs to menu items? Now the code feels very unwieldy, since I am perpetually transforming lists into maps, just for easy access of assoc details.
This entire train of thought has been a thorn in my side while doing LiveView development. I feel like no matter which approach I take, I am begetting obvious inefficiency.
Does anyone else feel this way? Does anyone have ancient secrets of efficient nested association assigns they want to share?
P.S. I love LiveView. It is awesome. I use it every day.
Most Liked
cmo
Obvious because you’ve measured it?
cmo
I merely intended to trigger the thought in you that maybe you should benchmark things instead of thinking you know what is and is not inefficient. I am sometimes surprised that my intuition about what will be faster is wrong when I benchmark different approaches.
Especially when you’re talking about a restaurant menu, which is not a large data structure.
slouchpie
Here is a pseudo-example
defmodule MyApp.Blurb do
@moduledoc """
BLURB = Brute Live Update of Rendered Basket
"""
alias MyApp.Baskets.NebulexCache
alias MyApp.Baskets.Basket
@topic "blurb"
def topic(basket_id), do: @topic <> basket_id
def subscribe(basket_id), do: Phoenix.PubSub.subscribe(MyApp.PubSub, topic(basket_id))
def broadcast(basket_id),
do: Phoenix.PubSub.broadcast(MyApp.PubSub, topic(basket_id), {:blurb, basket_id})
@doc """
A simple way of updating a displayed basket in real-time.
When a basket is updated in any kind of way, we broadcast just
the basket ID and a message like `basket_updated`.
Subscribers should then fetch the basket but ensure to do so using
Nebucache or whatever we are using to cache function results.
1. clear nebucache for a basket
2. broadcast the basket ID and message
"""
@spec clear_and_broadcast(Basket.id()) :: :ok
def clear_and_broadcast(basket_id) do
NebulexCache.clear_basket_id(basket_id)
broadcast(basket_id)
end
end
Then, if my basket changes in any kind of way at all (or even if something nested within basket, e.g. if someone changes the quantity of one of the items) then I just write a single line in the context function:
Blurb.clear_and_broadcast(basket_id)
I would love any feedback or criticism. I’m sure there are pitfalls with this approach that I am not seeing (such is life).
Popular in Discussions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









