
The Usefulness of Abstracting Over Time - maxhallinan
https://maxhallinan.com/posts/2018/08/17/the-usefulness-of-abstracting-over-time/
======
orf
I get why removing global state is a good thing in general, but here you are
replacing it with a whole lot of complexity for not a particularly clear
reason. Is tracking the user count with an integer dangerous _in this case_
(Have you run into problems with it)? Is your solution not using global state
anyway, just wrapped in a library?

All in all, are the abstractions (a bunch of new concepts plus a new library)
_worth it_ to just replace an integer?

    
    
       function timerFunc() {
          if (connectionCounter) get results();
       }
       socket.on('connect', function() { connectCounter++; });
       socket.on('disconnect', function() { connectCounter--; });
    

The real problem is you want to start and stop the timer when someone
connects. Just keep it simple and keep it going, but not doing anything if
there is nobody connected, like above.

~~~
s-shellfish
That always depends on whether whatever is contained within the abstraction is
something that might change. Sigh, humor.

Leaving it as a primitive basically says 'you may have to hack the programming
language or framework in order to modify code that depends on this piece of
the logic'. Global state is something you can manage in terms of modular
components. Allows for dynamic orchestration of components.

It's more the long term issue that keeps repeating (more humor) than it is
just replacing an integer. Being able to decide 'is this component something
that needs to be reasoned about in it's own independent logical layer from the
rest of the system or is it not' or 'does this component relate to other
components in a well defined way'.

Connect is an action, an observable action has occurred. An abstraction can
trigger a behavior to other abstractions through that predefined relation.
That's the point.

------
mpweiher
Hmm...

"The server always asks for new location data, every 30 seconds, even when no
one is listening."

...

"Our task is to pause the timer when there are no websocket connections and
start the timer when a client connects."

That sounds like asking for trouble. Maybe there's something I am not
understanding, but why not have the timer run continuously and have the timer
_action_ check whether it needs to request location data?

Yes, that will cause the process to wake up every 30 seconds even if there is
no action, but unless circumstances are very special that won't be a
significant problem.

~~~
maxhallinan
Thanks for reading! I like this suggestion.

The central problem of this post is not whether the timer is running
continually. The central problem is _how_ does the timer know when to
stop/start making requests.

It's a problem because knowing this depends on access to information that is
trapped in a different context. For example, the number of closed connections
is only knowable within the context of the connection event handler. So how do
you share this information with the timer?

One approach is to mutate global state. You move the information into a shared
context where it's accessible everywhere. A second option, which is the focus
of this post, is to look for better abstractions. In this case, those are
abstractions over time. And when you have those abstractions, you can
eliminate the global state.

~~~
mchahn
A question unrelated to your programming concepts: If you only query your
source when a request comes in, doesn't the first requester get old data? This
is a problem I have faced before.

~~~
marvy
Couldn't you make the first requester wait until you've made your query?

~~~
mchahn
Sure. But I assumed one goal was to offer low-latency access to a high-latency
service. I.E. Act as a cache.

~~~
marvy
Oh. That would be a tough spot to be in. I assumed that's not an issue here
though.

------
wilgertvelinga
Very nice explanation. Gives a good insight how you can "think in
observables". Two small things 1. instead of merging zero$ into
connectionClosed$ you can use the startWith() method. 2. Instead of using the
head method to pluck the first item of an array you could use array
destructuring. (But I can understand that you wouldn't do it in this to limit
the amount of "new" concepts)

------
fleitz
Send a message to a queue asking for refreshed data... ignore messages that
occur within a given timeframe.

Or put your server in front of a CDN / Nginx, set cache headers for 30 seconds
;)

