Your comment about scaling is on point. We're building on a system that not just enables but encourages a large amount of duplicated work because the substrate we've settled on is bytearray oriented. So all PLs and programs map their structures to 'bytes'. Could be worse - we could have different kinds of bytes (8-bit, 12-bit, etc.). But also could be better - the different processes could map their internal structures onto shared symbols or trees, and the substrate could provide a higher level of abstraction instead of clumps-of-bytes.
The interesting question to me is what kinds of composition models should a substrate provide? If we pre-share the notion of bytes, we end up share files and writing over sockets. If we pre-share more structured notion (e.g. graph) and share that it's another way. But there's more to it - how does meaning get transmitted via a message to a receiver? If we pre-share a grammar language, perhaps we can send a message that programs the receiver to extract useful info from itself? Whatever the structure of the message, there needs to be some sharing of 'tags' or 'identifiers' within the message for it to be usefully absorbed. How do we share these? Should this also be provided by the substrate?
To me the elephant in the room is how we use the heap and why there are 10k serialization techniques. Why are we serializing anyway?
Could be worse. We could be building stuff on top of an operating system based on DOS.
Unix provides a very spartan UI (the shell) with very spartan composition primitives (yay pipes? how many of you are still writing real programs in shell? regret not doing that little script that expanded to 5000 lines and tries to manage multiple processes, in a real programming language?) and a programming environment where you implement all the rest for yourself. Everything is a file, except when it's a process or a function or a thread or a file descriptor or an address or a socket or a ... you get it. We might be building lots of impressive products on top of Unix, but when looking at the code, it's more like we're mostly working around Unix (often trying to wish it away altogether by abstracting it out) because it doesn't solve our problems.
Files don't scale and lack transactions (i.e. are full of races, until you dump them and get a real database), pipes don't scale (and are too limited due to unidirectionality), text streams don't scale, shell scripts don't scale (and are full of races). Unix originally didn't even have a mechanism for waiting on multiple fds and then they came up with the hack that is select(2), which doesn't scale, and we still don't have a good API for asynchronous I/O (read the docs for e.g. libev for fun). Unix just makes you cross too many narrow one-way bridges, or build an island for yourself.