svarlet
What's your approach to domain modelling?
Hi all,
Let’s assume we are all coding a poker game as a purely functional library (=> no processes at this stage). If you don’t feel comfortable with poker, any other familiar multiplayer game will do.
How would you model it?
How would you design user interactions?
How would you validate user actions?
Thanks
Most Liked
OvermindDL1
As a state blob that I pass around. I do exactly this in the languages I’ve implemented in Elixir, just passing around an env struct, threading it through every function.
Well in purely functional you cannot get user input other than before your code runs, so I’d do it via the repl with them calling the function with the current state along with their action as a kind of ‘event input’.
In reality you need some way to get user actions at runtime, a Haskell IO monad can do that functionally (by blackboxing using input and pretending it has been there since the start even if it has not) or via event passing between purely functional processes or so.
Depends entirely on what you want to validate, but you’d do it in that above process function.
This is not actually that hard. Given a language with Sum types (or tagged tuples on the BEAM) I’d just have each action be part of that sum type that they pass in with the state, and via simple pattern matching you only handle what is valid for a given state/event mix. With matchers it is trivial to just work on the valid actions and crash on the invalid (with perhaps a single wrapper to give pretty errors).
Likewise, I just implemented an FSM on gen_server anytime I needed a FSM, just by pattern matching states and such.
OvermindDL1
Crash back to the wrapper, which then returns the original untouched state and the error.
svarlet
Thanks for recommending Exceptional. I already had a look at it not so long ago but without context I didn’t give it enough importance.
That helped me quite a bit this time and put on a better track too. Essentially, I refactored a bit my code from something like this:
def user_action(state, param) do
cond do
validate_param() ->
{:error, :reason1}
validate_state() ->
{:error, :reason2}
...
true ->
# the actual logic
end
to
def user_action(state, param) do
param
|> validate_param()
~> validate_state()
~> do_user_action()
end
where validate_xxx function return either the param unchanged or an exception (return, not raise). You could say that it’s not much but the code is much more readable that way. Validators are defined as simple functions and I can now define them outside my module if I need to.
Popular in Questions
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








