Some help on designing Elixir application based on "Data", "Behavior" and "Processes"

I think we kind of touched on this in your other topic - you may be getting caught up in the syntax (it’s a function call) while ignoring the underlying semantics (it’s an interprocess request/response).

This is why I like a clear demarcation between functions not requiring access to the concurrency primitives (spawn, send, receive), i.e. that use purely sequential code and those requiring the use of the concurrency primitives.

While not all “sequential” functions are pure functions, pure functions can only consist of sequential code - therefore their use will never breach the process boundary. So “pure” functions can only ever be used to effect transformations within the local process. However they can be used to transform the local process state - change which can affect how the process will interact later with other processes.

I simply think it needs to be obvious when a function has the potential to breach the process boundary - segregating functions into distinct modules is a possible approach, though I think it’s probably too heavy handed in many cases.

Does that mean my Foo module should be a GenServer?

No. It could simply play the role of a “utility script” for a frequently needed capability.

In terms of the “time” aspect I think you need to view it in it’s role with respect to a protocol (not the Elixir kind but the protocol defining an interaction between many participants (processes)). For example the registry’s API may consist of a number of functions to “access” it - but what is really important is how that API is used to implement the protocols of registering, querying, updating and un-registering of key/value pairs. So protocol dictates that Foo.get_pid/2 will return a pid provided one was registered previously for the specified key and hasn’t been unregistered since.

So in a sense process state should be “protocol state”.