Live data from Hacker News

Rationale: Or why am I bothering to rewrite nanomsg?

nanomsg.github.io

21–30 of 60 posts

Re: Rationale: Or why am I bothering to rewrite nanomsg?

#21
This is at least partially ill-advised. Comes off as an expertly done, but same old refactoring project that could be titled "I didn't understand this and would understand it better if I were designed based on my personal preferences". This is reinforced by the probably approaching 1 that nobody needs another "six of one half dozen of the other" message queue framework, and alluding to an belief that the C++ library is somehow too bloated for embedded environments. While that was at a time true, no reasonably modern embedded system that requires multi-threading to "100s" of threads, or uses 100s of live sockets for message queue I/O, has to avoid C++ for being too heavy. This is just ZeroMQ alternative #N - not anything objectively better, and certainly not "nano" for embedded systems. The "one true messaging framework" is a unicorn - everyone feels like it should exist but nobody can make it.

But for many cases this is not necessary. A simple callback mechanism would be far better, with the FDs available only as an option for code that needs them. This is the approach that we have taken with nng.

Replacing a state machine with callbacks... something something something you're gonna have a bad time. Esp. considering the gripes are about readability, following control flow, and race conditions. Callbacks are objectively worse for all of those things. Control flow is hard to read in state machine frameworks because the primary flow is dictated by something like "nextState(thisState, action)", so you can't follow it with code lookup.

The problem here (and almost always) is lack of documentation or visualization (or picking the wrong abstraction level for the formally defined states). The beauty is that the definition is almost by default naturally easy to parse (tables of states in a header file, etc.). It takes some extra effort, it is a one shot to write something that generates graphviz state chars or something similar from the state table definition. You could write a custom dot syntax generator from a C-style table definition in what, three hours? Doxygen already does this for much more complicated stuff. Googling reveals this is nothing new: https://gist.github.com/freqlabs/24d88ad8e687891c970a69f16f1...

All that said, State Machines are (currently) the one true abstraction for a given program because that is what a computer is, and every program is, to begin with. If you're not using them explicitly, it just means you have a poorly defined/documented state machine. Maybe someday there will be a better model of computing, or a better way to model programs. For now, the human brain isn't getting any better at keeping track of computer programs, and anything more than single-threaded functional-style code is almost certainly not any "absolute" improvement in readability.

I firmly believe that visualization has become necessary due to complexity, and it is past time to embrace it. There is some stigma that visualization is for fakers - "real programmers only use a bare text editor" - or that it is for children learning programming, or non-engineering folks that need pictures because they're dumb. To be a bit hyperbolic, if we want any chance at keeping up with "the machines", we're going to need a better general-purpose, more workable abstraction than text files. There is no more canonical example of this than the issues pointed out here - state machines are the right abstraction for complex systems, but complex state machines are incredibly difficult to follow in source code.

Re: Rationale: Or why am I bothering to rewrite nanomsg?

#22
post #9

> even so-called "modern" operating systems > like macOS 10.12 and Windows 8.1 simply > melted or failed entirely when creating > any non-trivial number of threads. (To > me, creating 100 threads should be a no-brainer This is nonsense. NT kernel happily creates thousands of threads. Just made a little test app to try. No issues at all.

Of course no offense, but the author does seem to be somewhere shortly after the first peak on the Dunning-Kruger curve. Even truly embedded systems with an OS like QNX don't "melt" with 100 threads. Obviously he "doesn't know what he doesn't know" in expertise terms, and blamed a mistake on the operating systems.

That combined with the other extremely dubious reasoning - e.g. (see my other very long comment) how replacing state machines with callback functions is a good idea (tm). There is also the comment RE: "how bad Windows APIs are" and how IO-completion ports are '_actually_ pretty nice'. This is the kind of comment someone makes if their worried the "real" coders won't take them seriously if they use anything but Arch Linux.

Makes you think he is reasoning about things that he just isn't an expert in yet (embedded systems, operating system APIs, long-term framework design). Nothing wrong with that though - everyone has to build up experience somehow - but maybe a bit early to be on the front page of HN.

Re: Rationale: Or why am I bothering to rewrite nanomsg?

#23
> OpenSSL has it’s own struct BIO for this stuff, and I could not see an easy way to convert nanomsg's usock stuff to accomodate the struct BIO.

It's actually quite easy to write a custom BIO to work with your own state machines and buffering. This could have been a 1-day project....

Re: Rationale: Or why am I bothering to rewrite nanomsg?

#24

This is at least partially ill-advised. Comes off as an expertly done, but same old refactoring project that could be titled "I didn't understand this and would understand it better if I were designed based on my personal preferences". This is reinforced by the probably approaching 1 that nobody needs another "six of one half dozen of the other" message queue framework, and alluding to an belief that the C++ library…

Aren’t there FST implementations that solve the problem of following the next() logic? I know I’ve heard of ones based on enumerated types but that is not the only way to solve this problem.

Re: Rationale: Or why am I bothering to rewrite nanomsg?

#25

This is at least partially ill-advised. Comes off as an expertly done, but same old refactoring project that could be titled "I didn't understand this and would understand it better if I were designed based on my personal preferences". This is reinforced by the probably approaching 1 that nobody needs another "six of one half dozen of the other" message queue framework, and alluding to an belief that the C++ library…

> There is some stigma that visualization is for fakers - "real programmers only use a bare text editor"

That stigma would have gone away long ago if the actually existing visual languages were less wretched. (I'm looking at you LabView!). No doubt there are better languages than LabView, but while I think a visual language can be good, creating one will involve many as-yet-unknown unknowns. So even good attempts will be toys at first.

A good stepping stone would be visual analysis of textual programs. I want a debugger for a data-flow graph where following edges answers the question "what caused this value to be what it is". And I want to visualise that graph as well as possible, so that I can get an overview of the different possible causes.

Re: Rationale: Or why am I bothering to rewrite nanomsg?

#26

This is at least partially ill-advised. Comes off as an expertly done, but same old refactoring project that could be titled "I didn't understand this and would understand it better if I were designed based on my personal preferences". This is reinforced by the probably approaching 1 that nobody needs another "six of one half dozen of the other" message queue framework, and alluding to an belief that the C++ library…

> Replacing a state machine with callbacks... something something something you're gonna have a bad time

Having written quite a few networking systems, I fully agree. Especially if it's coupled in this text with "replacing a single-threaded state-machine" with "a multithreaded system, which uses callbacks". IMHO the latter is almost guaranteed a recipe for all kinds of multithreading issues, from race-conditions over deadlock to memory issues. And even if the author of the library gets it right, the issues are often at library user level (didn't expect where the callback is executed and accessed their data without necessary synchronization).

The described model of nanopb sounds very sane compared to that. Pure multithreaded systems without callbacks (like in Go) also work reasonably well. But even those do not work without state-machines in all situations. In all cases where state is manipulated by more than one code-path it's mostly the most reasonable thing to handle this in some kind of state-machine which runs on a single thread, instead of trying to fight it with dozens of fine-grained locks. And just as an example: The HTTP2 implementation in Go uses a state-machine which runs on a goroutine per connection. And user code, frame reader and frame writer code communicate via messaging with that state-machine.

Re: Rationale: Or why am I bothering to rewrite nanomsg?

#27
Original author of zmq/nanomsg here.

After all those years dealing with the problem of implementing network protocols I believe that this entire tangle of problems exists because we are dealing with something like 35 years of legacy in two different but subtly interconnected areas: concurrency/parallelism and network programming APIs.

The area of concurrency/parallelism started quite reasonably with the idea of processes. But then, at some point, people felt that processes are too heavy-weight and introduced threads (I'm still trying to find out who the culprit is, but it looks like they've covered their tracks well.) When even threads became too heavy-weight people turned to all kinds of callback-driven architectures, state-machine-driven architectures, coroutines, goroutines etc. Now we have all of those gand we are supposed to make them work together flawlessly, which is a doomed enterprise from the beginning.

At the side of network programming, BSD sockets (introduced in 1983) are the only common ground we have. They are long past their expiry date, they don't adapt to many use cases, but there's no alternative. There are more modern APIs there, but, AFAICS, none of them provides enough added value of top to become the new universal standard.

It should be also said that creation of new universal APIs is hindered by a host of weird network protocol designs out there in the wild. The API designer faces a dilemma: either they go for sane API and rule at least some weird protocols out or they try to support everything and end up with one mess of an API. Not a palatable choice to make.

Then there's the area where the two problems about interact. Originally, you were supposed to listen for incoming TCP connections, fork a new process for each one and access the socket using simple single-threaded program with no state machines, using only blocking calls. Today, you are supposed to have a pool of worker threads, listen on file descriptors using poll/epoll/kqueue, then schedule the work to the worker pool by hand. This raises the complexity of any network protocol implementation by couple of orders of magnitude. Also, you get a lot of corner cases, undefined behaviour, especially at shutdown, weird performance characteristics and I am not even speaking of the increased attack surface.

All in all, it's a miracle that with the tools we have we are able to write any network applications at all.

These days I am working on attacking the issue on both fronts. On the concurrency side it's http://libdill.org -- esentially not very interesting, just an reimplementation of goroutines for C, however, what's worth looking at is the idea of "structured concurrency", a system of managing the lifetimes of coroutines in a systemic manner: http://libdill.org/structured-concurrency.html

On the other front, the network programming, I am trying to put together a proposal for revamp of BSD socket API. The goal is to make it possible to layer many protocols on top of each other as well as one alongside the other. It's a work in progress, so take it with a grain of salt: https://raw.githubusercontent.com/sustrik/dsock/master/rfc/s...

Re: Rationale: Or why am I bothering to rewrite nanomsg?

#28

From the article: > nanomsg has dozens of state machines, many of which feed into others, such that tracking flow through the state machines is incredibly painful. > Worse, these state machines are designed to be run from a single worker thread. Despite the negative tone, the author gives me the impression that nanomsg as a simple, consistent architecture that just needs to be documented better or perhaps refactored.…

I came to the same conclusion more or less. Does Go provide meaningful abstractions for writing and managing state machines? Using gen_fsm or gen_statem in Erlang is a critical tool in writing software in a way which _must_ follow some known protocol correctly. Likewise using Session-Types in Rust to go one better than what I get in Erlang (i.e. compile-time assurances vs. runtime ones). So I was left thinking that G…

> Does Go provide meaningful abstractions for writing and managing state machines?

Not really more than C. I think in Go the needs are somewhat reduced, since it hasn't the need to use state-machines for actually linear control flow (like making HTTP requests or reading data from a socket without being interrupted).

However there are still needs for state-machines, especially when the control-flow isn't linear (more than one event change trigger state-changes). In that case we are mostly back to things like switch/case statements.

There are some interesting patterns for running state-machines in separate goroutines, for letting threaded code interact with them. We can e.g. see those in Go's HTTP/2 implementation ( https://github.com/golang/net/blob/master/http2/server.go ). In this thing the serve() method basically is a giant state-machine that runs on it's own thread. However that's definitely not easy to write, understand and maintain code. A single threaded state-machine is probably much easier to grasp for an average programmer.

Re: Rationale: Or why am I bothering to rewrite nanomsg?

#29

This is at least partially ill-advised. Comes off as an expertly done, but same old refactoring project that could be titled "I didn't understand this and would understand it better if I were designed based on my personal preferences". This is reinforced by the probably approaching 1 that nobody needs another "six of one half dozen of the other" message queue framework, and alluding to an belief that the C++ library…

> There is some stigma that visualization is for fakers - "real programmers only use a bare text editor" That stigma would have gone away long ago if the actually existing visual languages were less wretched. (I'm looking at you LabView!). No doubt there are better languages than LabView, but while I think a visual language can be good, creating one will involve many as-yet-unknown unknowns. So even good attempts wil…

Ironically, some disassemblers (most famously IDA) offer a kind of graph view for visual analysis.

Also, IntelliJ - which is fantastic - has had data flow analysis for years: https://blog.jetbrains.com/idea/2009/08/analyzing-dataflow-w...

Re: Rationale: Or why am I bothering to rewrite nanomsg?

#30
post #9

> even so-called "modern" operating systems > like macOS 10.12 and Windows 8.1 simply > melted or failed entirely when creating > any non-trivial number of threads. (To > me, creating 100 threads should be a no-brainer This is nonsense. NT kernel happily creates thousands of threads. Just made a little test app to try. No issues at all.

Of course no offense, but the author does seem to be somewhere shortly after the first peak on the Dunning-Kruger curve. Even truly embedded systems with an OS like QNX don't "melt" with 100 threads. Obviously he "doesn't know what he doesn't know" in expertise terms, and blamed a mistake on the operating systems. That combined with the other extremely dubious reasoning - e.g. (see my other very long comment) how rep…

I think Garrett has been doing all of the things you're talking about for quite a long time. I'm not saying this experience makes him correct per se, but come on -- this is just poorly constructed character assassination on your part.
Post reply on HN