[erlang-questions] Complex state machines for complex telnet applications

Jesper Louis Andersen jesper.louis.andersen@REDACTED
Tue Jan 24 12:47:52 CET 2017

Here are some thoughts off-hand. They are not too fleshed out.

* I'd definitely run things via Ranch if possible. Some of the subtler
things in and around reconnect accept pools and so on happens to be solved
well by Loic in Ranch.

* It may be possible to generalize buffer handling from the user. Consider
a function handle(Data, BufferState) -> {Cmds, UpdatedBufferState}, where
Cmds is a list of the commands the user entered.

* Most modules in a BBS probably runs in a Request -> Reply fashion. You
send a command to the module and it replies with a new display state you
send to the BBS client. Since each module will keep its own state, you can
stuff that into a process.

* Modules may have their own state. They may also have BBS-global state
which enables communication between clients. Say you have a forum module.
It will have a forum_backend in which you store the actual posts in the
forum. When a client requests forum access, you spawn a helper which runs
the Request/Reply pattern proxying the data in the backend to the client.

* gen_statem is probably most useful in modules, and not so much in the
client itself, unless the interactions are complex and there are certain
things which can only happen in some limited states, etc.

* Be aggressive and link everything or use monitors. That way, you can
easily handle errors in parts of the system without taking it all down.
Also, you can probably handle a hangup by simply terminating the client
process and then have modules handle a 'DOWN' message and clean up.

* Old BBS'es did not really have it that much, but you could write a
general command parser and then supply parsed terms to modules. This
becomes yet another state machine, but it often kept inside the client

-record(state, {
    buffer_state :: buffer_state(),
    parser_state :: parser_state(),
    socket :: inet:socket(),

* A common beginners mistake is to want to process everything en masse. The
rule of thumb is to create a process for each truly concurrent activity in
the system. With that in mind, it may be that module state should not by in
a proxy process, as above, but rather be embedded directly in the client.
The forum_backend is truly concurrent however and warrants its own process.

* The counterpoint to the last remark: don't be afraid to use a process to
isolate parts of your system and keep complexity down. Juggling many states
in one process at the same time means you have to handle every complex
cross-interaction between them. If you push something to its own process,
then chances are there are less cross-talk and thus a system which is
easier to understand and handle.

* Finally: rather than focusing on the "behaviour", focus on the
interaction protocol. When you talk HTTP, you don't do that by inheriting a
HTTP-class. You do that by speaking the protocol. This is powerful because
you *don't* know the internal implementation of the HTTP server. REST was
only possible in the first place because HTTP was a protocol. In a BBS,
focus on the module interaction protocol. You don't care for the internal
implementation, but rather how you talk to it. Once established, it may be
that 80% of the modules can implemented via a generic callback framework,
as is the case for the gen_server (where the protocol is OTP). But there
are always 20% which are not fitting in, and you want that to be possible
as well.

Feel free to follow up :)

On Tue, Jan 24, 2017 at 6:02 AM Thom Cherryhomes <thom.cherryhomes@REDACTED>

> Would you, for example, build the ranch protocol as simple as possible,
> and link the other application servers, as needed, with a common protocol?
> -Thom
> On Sun, Jan 22, 2017 at 2:56 PM Thom Cherryhomes <
> thom.cherryhomes@REDACTED> wrote:
> Hello, everyone. This is my first post to the list.
> I’m a long time swiss army knife of a software and hardware engineer who
> has started to pick up Erlang, because I believe it and languages like it
> to be the future of software development.
> With that said, I am working on a personal project of mine that I have
> wanted to complete, a 21st century version of a BBS system, and I believe
> Erlang and OTP are a good language and toolkit to write it in.
> Code is being dropped here: http://github.com/tschak909/nakbbs
> I am experimenting with both Ranch and just using gen_tcp with my own
> socket pools, but I do have some design questions.
> The telnet ports need to present a definite series of states, broken up
> into seperate pieces:
> I have definite common events that can be stretched across multiple use
> cases:
> * Display
> * Wait for line of input
> * Wait for character input
> * branch to another menu
> * hang up
> But there will also be definite sections of the system, which could be
> thought of as states:
> * Authentication
> * Message Browser
> * Message Editor
> * Various Games
> etc.
> and I’m trying to think of an appropriate architectural pattern that will
> avoid me basically having to cram every conceivable state as a sort of
> hierarchy of tuples into a single gen_statem module. How can I approach
> this in a nice abstract and extensible manner, that I could for example
> push into a Behaviour and subsequently utilize for different terminal
> types? It would be nice to split up the different parts of the system into
> applications that would essentially be called from well defined APIs…
> I’m just trying to figure this all out, and would love a semblence of
> direction so I can do the proper research and deeply understand what I need
> to learn.
> -Thom
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20170124/a9228fa8/attachment.htm>

More information about the erlang-questions mailing list