pragdave/component

Usage Guidance

Closed this issue · 5 comments

I'm a little concerned that this library to some extent, but more particularly the associated blog post could lead to Elixir new-comers thinking that software design in Elixir is always centered on the concept of user-developed servers, and that concepts such as encapsulation and separation of concerns dictate the usage of servers in ordinary application or business logic that wouldn't otherwise need its own concurrency mechanism.

This already happens - it is not hard to find examples in the wild where people use GenServer for what could be done without concurrency at all, or much more simply with Task.async.

Would it make sense to have some guidance on when a server is needed to begin with? For example, a web request in a framework such as Phoenix should almost never make a synchronous call to a GenServer, as this would single-thread all requests making that call and incur overhead in copying messages.

Modules should absolutely be used first before GenServer's, however I wouldn't quickly jump to Task.async for concurrency as tracing it is less... named, where a dedicated GenServer is named and you know what it's immediately doing when seeing it in :observer or other tools.

However, Task.async and a GenServer are not solving the same issue, GenServer is a synchronization point by serializing access through it, Task.async is a concurrency tool that if you run too much of can overwhelm the system as it has no associated pool (where the Pool strategy handles the same case but without worry about running out of system resources).

@OvermindDL1 Yes, they serve different purposes, which is sort of my point. I think a simple statement about when servers are appropriate in the introduction might solve this. Something along the lines of "Use servers when you want to serialize access to shared state.".

Jeremy:

I agree 100%, and I'm concerned that this library is coming across as the solution to all coding problems.

Last night, after chatting with José, I added this: https://github.com/pragdave/component#choosing-a-component-type

Does this help, do you think?

@pragdave Looks great! Couple notes:

If you don't to share your state with anybody.

If you don't need to share... (maybe want?)

The dynamic component section should probably also mention that's its for sharing state across processes and if state should be shared within a single process then that state should be passed directly instead (with raw module calls to separate out functionality, not a component).

Elixir also has the Flow library (built on GenStage), maybe the Hungry section should reference it some how as it is overall a more generic version of Hungry?

@pragdave Excellent, thanks! I'd looked at this yesterday and didn't notice the update this morning. I think that makes it much more clear what this library is intended to solve.