Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
marijuanamancer
Sep 11, 2001

by Jeffrey of YOSPOS

9-Volt Assault posted:

I would try the Scientific/Math(s) Computing: numerical/statistical analysis tools and CASs thread over at Ask / Tell › Science, Academics and Languages.

Aha, thanks

Adbot
ADBOT LOVES YOU

Mr Shiny Pants
Nov 12, 2012

I saw a talk once that talked about transforming OOP minded RFCs to Actor-Model architecture. Are there any resources that you know of that can help with translating OOP designed code to more of an actor based approach?

I find this part very hard.

Pollyanna
Mar 5, 2005

Milk's on them.


MononcQc posted:

Rather than making a very long post about this from scratch, I'll source a transcript of a talk I gave on 'The Zen of Erlang' that mentions what OTP can bring to system structure: http://ferd.ca/the-zen-of-erlang.html



With supervisors (rounded squares), we can start creating deep hierarchies of processes. Here we have a system for elections, with two trees: a tally tree and a live reports tree. The tally tree takes care of counting and storing results, and the live reports tree is about letting people connect to it to see the results.

By the order the children are defined, the live reports will not run until the tally tree is booted and functional. The district subtree (about counting results per district) won't run unless the storage layer is available. The storage's cache is only booted if the storage worker pool (which would connect to a database) is operational.

The supervision strategies (one-for-one, one-for-all, rest-for-one) let us encode these requirements in the program structure, and they are still respected at run time, not just at boot time. For example, the tally supervisor may be using a one for one strategy, meaning that districts can individually fail without effecting each other's counts. By contrast, each district (Quebec and Ontario's supervisors) could be employing a rest for one strategy. This strategy could therefore ensure that the OCR process can always send its detected vote to the 'count' worker, and it can crash often without impacting it. On the other hand, if the count worker is unable to keep and store state, its demise interrupts the OCR procedure, ensuring nothing breaks.

The OCR process itself here could be just monitoring code written in C, as a standalone agent, and be linked to it. This would further isolate the faults of that C code from the VM, for better isolation or parallelisation.

Another thing I should point out is that each supervisor has a configurable tolerance to failure; the district supervisor might be very tolerant and deal with 10 failures a minute, whereas the storage layer could be fairly intolerant to failure if expected to be correct, and shut down permanently after 3 crashes an hour if we wanted it to.

In this program, critical features are closer to the root of the tree, unmoving and solid. They are unimpacted by their siblings' demise, but their own failure impacts everyone else. The leaves do all the work and can be lost fairly well — once they have absorbed the data and operated their photosynthesis on it, it is allowed to go towards the core.

So by defining all of that, we can isolate risky code in a worker with a high tolerance or a process that is being monitored, and move data to stabler process as information matures into the system. If the OCR code in C is dangerous, it can fail and safely be restarted. When it works, it transmits its information to the Erlang OCR process. That process can do validation, maybe crash on its own, maybe not. If the information is solid, it moves it to the Count process, whose job is to maintain very simple state, and eventually flush that state to the database via the storage subtree, safely independent.

If the OCR process dies, it gets restarted. If it dies too often, it takes its own supervisor down, and that bit of the subtree is restarted too — without affecting the rest of the system. If that fixes things, great. If not, the process is repeated upwards until it works, or until the whole system is taken down as something is clearly wrong and we can't cope with it through restarts.

There's enormous value in structuring the system this way because error handling is baked into its structure. This means I can stop writing outrageously defensive code in the edge nodes — if something goes wrong, let someone else (or the program's structure) dictate how to react. If I know how to handle an error, fine, I can do that for that specific error. Otherwise, just let it crash!

This tends to transform your code. Slowly you notice that it no longer contains these tons of if/else or switches or try/catch expressions. Instead, it contains legible code explaining what the code should do when everything goes right. It stops containing many forms of second guessing, and your software becomes much more readable.



When taking a step back and looking at our program structure, we may in fact find that each of the subtrees encircled in yellow seem to be mostly independent from each other in terms of what they do; their dependency is mostly logical: the reporting system needs a storage layer to query, for example.

It would also be great if I could, for example, swap my storage implementation or use it independently in other systems. It could be neat, too, to isolate the live reports system into a different node or to start providing alternative means (such as SMS for example).

What we now need is to find a way to break up these subtrees and turn them into logical units that we can compose, reuse together, and that we can otherwise configure, restart, or develop independently.



OTP applications are what Erlang uses as a solution here. OTP applications are pretty much the code to construct such a subtree, along with some metadata. This metadata contains basic stuff like version numbers and descriptions of what the app does, but also ways to specify dependencies between applications. This is useful because it lets me keep my storage app independent from the rest of the system, but still encode the tally app's need for it to be there when it runs. I can keep all the information I had encoded in my system, but now it is built out of independent blocks that are easier to reason about.

In fact, OTP applications are what people consider to be libraries in Erlang. If your code base isn't an OTP application, it isn't reusable in other systems. [Sidenote: there are ways to specify OTP libraries that do not actually contain subtrees, just modules to be reused by other libraries]

With all of this done, our Erlang system now has all of the following properties defined:
  • what is critical or not to the survival of the system
  • what is allowed to fail or not, and at which frequency it can do so before it is no longer sustainable
  • how software should boot according to which guarantees, and in what order
  • how software should fail, meaning it defines the legal states of partial failures you find yourself in, and how to roll back to a known stable state when this happens
  • how software is upgraded (because it can be upgraded live, based on the supervision structure)
  • how components interdepend on each other
This is all extremely valuable. What's more valuable is forcing every developer to think in such terms from early on. You have less defensive code, and when bad things happen, the system keeps running. All you have to do is go look at the logs or introspect the live system state and take your time to fix things, if you feel it's worth the time.

In a nutshell, the Zen of Erlang and 'let it crash' is really all about figuring out how components interact with each other, figuring out what is critical and what is not, what state can be saved, kept, recomputed, or lost. In all cases, you have to come up with a worst-case scenario and how to survive it. By using fail-fast mechanisms with isolation, links & monitors, and supervisors to give boundaries to all of these worst-case scenarios' scale and propagation, you make it a really well-understood regular failure case.

That sounds simple, but it's surprisingly good; if you feel that your well-understood regular failure case is viable, then all your error handling can fall-through to that case. You no longer need to worry or write defensive code. You write what the code should do and let the program's structure dictate the rest. Let it crash.

OTP is pretty much instrumental to that.

...Huh. That's actually pretty loving cool. I've never really thought of programming that way. Web apps, where I've spent 99% of my dev time, don't usually match up to this kind of approach - at least, not the ones I've ever worked on. I feel kinda left out now.

It seems like all the interesting software stuff is kept away in places where Rails monkeys like me don't really get the chance to work on them and learn from it. I want to get more involved in cool stuff like this, so I've been making moves towards branching out and :yotj:ing my way into one of these kinds of projects. Teams are moving towards more functional and alternative coding styles now, so I hope my skills end up in demand.

MononcQc
May 29, 2007

Mr Shiny Pants posted:

I saw a talk once that talked about transforming OOP minded RFCs to Actor-Model architecture. Are there any resources that you know of that can help with translating OOP designed code to more of an actor based approach?

I find this part very hard.

Do you have any specific RFC in mind?

Mr Shiny Pants
Nov 12, 2012

MononcQc posted:

Do you have any specific RFC in mind?

Of the top of my head, the guy was talking about how you would implement a webserver in Erlang and instead of one process that handles the connections and kicks of threads you would have a process for every connection coming into the server.

Not in particular, no. I was just wondering about general guidelines.

I saw your talk, supervision trees look really nice.

MononcQc
May 29, 2007

Mr Shiny Pants posted:

Of the top of my head, the guy was talking about how you would implement a webserver in Erlang and instead of one process that handles the connections and kicks of threads you would have a process for every connection coming into the server.

Not in particular, no. I was just wondering about general guidelines.

I saw your talk, supervision trees look really nice.

The thing with the actor model is that it can feel like a better Object Oriented environment than actual OO languages, but that's not a great way to structure systems. That way leads madness and frustration.

The idea for Erlang is really to use processes to hold independent program units. That's the major difference with OO, where all pieces of data you have tend to materialize as objects.

If you have a program that operates on a data structure (they pretty much all do!), you don't represent the data structure as a process. Instead you represent them as regular pieces of data that you operate on functionally with the functional subset of Erlang, in a good old sequential/declarative program. The level of concurrency and processes will come around when you take a given data flow or continuous piece of living state, and want to give it its own place to run.

So yeah, for a webserver, there's two traditional designs depending on the server you use.

In either case, a process is started that will listen on a socket. Then the split takes place:

One one side (yaws, mochiweb), the server spawns a pool of processes that act as acceptors. Once a connection is accepted, the process itself becomes the connection: it will defer itself to custom code by the programmer based on a regular interface to handle requests and responses. A worker elsewhere receives a message asking to spawn a new acceptor, and the pool is maintained to a roughly stable size. There is a serialization point to spawn new acceptors

On the other side (cowboy), the server spawns a pool of process that act as acceptors, but whenever a connection is accepted, they hand it over to a new process that will handle the request. The pool remains fixed in size, but if you want to implement a limit on the number of web workers, you require more complex coordination with the process pool, and more calls to shift control of sockets to processes (any process can send to a known socket, but only one may listen at a time, so they have a concept of ownership).

In all cases, you end up using one process per connection. Pipelined or keepalive requests over a single connection can share the same local cache and state, though most servers don't make this explicit.

Pollyanna
Mar 5, 2005

Milk's on them.


So the common idea of "HTTP is stateless and you must assume the connection and requests are too" still holds, but individual connections are considered their own processes? What advantage does this have over the previous one-process model? I can see the obvious picks of parallelization, but there's also concerns like database access that could limit the benefits from that...I'm not a web dev genius, just a monkey, so maybe I'm missing something. As a general system architecture, too, I can see how it'd be useful, but I still need some practice and experience to really grok it.

EmmyOk
Aug 11, 2013

I hope this is the correct thread for this because I thought it was more of a general difficulty in understanding functions returning functions than a .NET thing or whatever. :shobon:

Hello everyone I am knew to functional programming after spending amost all of my time in Java or C#. A friend I work with mentioned F# a while back and I've spent an occassional afternoon looking at it over the bpat few months but not really much time at all. Eventually I reached a tipping point of being interested after seeing enough elegant solutions for problems that ire unavoidably bloated in Java. I bought a book (Beginning F# 4.0 by Pickering and Eason) after reading through introductory things online. Currently theres a code snippet I can't fully understand and I think it comes down to not understanding what happens when a function returns another function.

pre:
let calculatePrefixFunction prefix =
    let prefix' = Printf.sprintf"[%s]: " prefix
    let prefixFunction appendee =
        Printf.sprintf "%s%s" prefix' appendee
    prefixFunction

let prefixer = calculatePrefixFunction "DEBUG"

printfn "%s" (prefixer "My message")


This prints out [DEBUG]: My message

My current understanding of this is that
  • calculatePrefixFunction takes a string prefix as a parameter
  • calculatePrefixFunction then defnes prefix' to return a string "[prefix]: "
  • prefixFunction is defined with parameter appendee and returns a string composed of a prefix' (or what it resolves as I guess) and appendee
  • Finally calculatePrefixFunction returns prefixFunction
  • Then the program moves on and defines prefixer as calculatePrefixFunction with parameter "DEBUG"
  • Lastly it prints out the result of prefixer called on "My message"

What I don't understand is exactly what happens when prefixFunction is returned by calculatePrefixFunction. I don't think it's a function call because it's not given a parameter. However considering how it prints out when the program runs, prefixFunction must be run on the string "My Message". So after calculatePrefixFunction runs and prefixFunction is returned then it takes "My message" as the appendee parameter. I don't think this is correct though or if it is I don't really understand why it is. I'm just not able to divine the correct passage of information and method calls.

e: actually I guess prefix' is just a string not function, still confused by the rest though :saddowns:

EmmyOk fucked around with this message at 18:19 on Jan 17, 2017

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Not exactly sure of the source of confusion - when you say "I don't think it's a function call because it's not given a parameter", what do you mean specifically? (calculatePrefixFunction "DEBUG") returns a function, which is stored in the variable prefixer. This function is then applied to "My message", returning the prefixed message.

e: Maybe a translation into pseudo-C# could help?

code:
public Function<string, string> calculatePrefixFunction(String prefix)
{
    String prefix' = Printf.sprintf("[%s]:", prefix);
    Function<string, string> prefixFunction = (String appendee) =>
        Printf.sprintf("%s%s", prefix', appendee);
    return prefixFunction;
}

Function<string, string> prefixer = calculatePrefixFunction("DEBUG");

printfn("%s", prefixer.Apply("My message"));  // C# treats function objects and functions differently, requiring a .Apply or whatever, while F# doesn't.

Asymmetrikon fucked around with this message at 18:36 on Jan 17, 2017

EmmyOk
Aug 11, 2013

Your explanation makes a lot of sense actually! I guess the fact that an entire function can be returned and then stored is just completely alien to me as a concept. So when calculatePrefixFunction is called it returns prefixFunction and prefixer is a function defined by the returned function i.e. it's no different than an int that is initialised as the result of a function that returns an int?

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
Yeah, that's exactly right. Functional languages are big on tossing around functions as concrete things (usually described as them being first-class constructs like any other data.)

spiritual bypass
Feb 19, 2008

Grimey Drawer

Pollyanna posted:

So the common idea of "HTTP is stateless and you must assume the connection and requests are too" still holds, but individual connections are considered their own processes? What advantage does this have over the previous one-process model? I can see the obvious picks of parallelization, but there's also concerns like database access that could limit the benefits from that...I'm not a web dev genius, just a monkey, so maybe I'm missing something. As a general system architecture, too, I can see how it'd be useful, but I still need some practice and experience to really grok it.

I'm under the impression that the database connection is actually an abstraction of a connection pool that works without programmer intervention. The process-per-connection allows a share-nothing approach that should, hopefully, make things just a little bit safer. FWIW, I think this is exactly how PHP-FPM works.

EmmyOk
Aug 11, 2013

Asymmetrikon posted:

Yeah, that's exactly right. Functional languages are big on tossing around functions as concrete things (usually described as them being first-class constructs like any other data.)

Okay that's starting to make a lot of sense to me. Is prefixer just a reference to the original function or a copy? I'm wondering because it seems like prefix' is still available to prefixer which is a string originally from the first-order function.

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!
I'm not super sure how F# handles it, but most functional languages (that I use, anyway) don't do references; they always copy.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

EmmyOk posted:

Okay that's starting to make a lot of sense to me. Is prefixer just a reference to the original function or a copy? I'm wondering because it seems like prefix' is still available to prefixer which is a string originally from the first-order function.

It's best to think of it as a new function that was built during the calculatePrefixFunction method. Yes, prefix' is still available to the prefix function (this is commonly known as "closing" over a variable, see wikipedia). How it *actually* works is heavily dependent on your language implementation, but the semantics should be the same as if you just created a new function.

It might also help to look at a similar example with numbers:

code:
let buildAdder x =
    let adder y = x + y   // define inner function
    adder                 // return function

let add2 = buildAdder 2  // add2 is a function that takes a parameter and adds 2
let add5 = buildAdder 5  // add5 is a function that takes a parameter and adds 5

printfn "%d" (add2 1)  // 3
printfn "%d" (add5 7)  // 12
Another way to look at the above example is by variable substitution:

code:
let add2 = buildAdder 2

// in the definition of buildAdder, let's replace x with 2
buildAdder 2 =
    let adder y = 2 + y
    adder

// so, we can replace buildAdder 2 above when defining add2:
let add2 y = 2 + y

EmmyOk
Aug 11, 2013

Thanks, Bognar and Asymmetrikon, these posts really helped a lot! The example using numbers are really clear and I'm much happier moving forward that I understand what's happening. Thanks again!

MononcQc
May 29, 2007

Pollyanna posted:

So the common idea of "HTTP is stateless and you must assume the connection and requests are too" still holds, but individual connections are considered their own processes? What advantage does this have over the previous one-process model? I can see the obvious picks of parallelization, but there's also concerns like database access that could limit the benefits from that...I'm not a web dev genius, just a monkey, so maybe I'm missing something. As a general system architecture, too, I can see how it'd be useful, but I still need some practice and experience to really grok it.

The process model for cgi and fcgi still makes sense, it's just that it's a ton cheaper to run in a VM like Erlang's. Database pools and access do represent a similar problem, except that now, the pool is usually a tweakable and configurable thing that lives within your VM along side the app. One of the benefits there is the ability to efficiently have bidirectional communication with the pool, on your own terms. That being said, the problems of contention, control flow, and back pressure don't change. They just take a different form, one that may be more explicit (I wrote on this at http://ferd.ca/handling-overload.html)

Overall you can think of a large Erlang system of the way you could build a microservice architecture, but with all the apps living within one VM under a single memory space in a single runtime. There's huge benefits from having the proper isolation and architectural divide, but you don't have to pay the cost of the network overhead in most cases.

Mr Shiny Pants
Nov 12, 2012

MononcQc posted:

Overall you can think of a large Erlang system of the way you could build a microservice architecture, but with all the apps living within one VM under a single memory space in a single runtime. There's huge benefits from having the proper isolation and architectural divide, but you don't have to pay the cost of the network overhead in most cases.

This also how I am imagining the system, so you could say the Erlang VM is kuburnetes? And a process is a docker instance?

xtal
Jan 9, 2011

by Fluffdaddy

xtal posted:

What is the best language to use on a Raspberry Pi? Haskell runs fine but lens has been compiling for over a day

Ralith posted:

If you can live without being MAXIMUM FUNCTIONAL, rust's nice, and has a pretty good embedded story.

Self-quoting for context. How much of a coding horror would it be for me to make a Lisp syntax for Rust using Haskell and parsec?

Pollyanna
Mar 5, 2005

Milk's on them.


I can understand why you'd want to write your systems and applications as a process tree, but I haven't yet developed a sense of what use cases those would be. I guess I haven't had a need to work on uptime critical systems before, but it sure sounds interesting. I got pretty far into LYAH, so maybe LYSE is up next.

Edit: I have to say, Elixir/Erlang, OTP and the BEAM are how I expected computer programs to work in the first place, so it's nice to see that I wasn't totally off.

xtal posted:

Self-quoting for context. How much of a coding horror would it be for me to make a Lisp syntax for Rust using Haskell and parsec?

As long as it isn't a security critical thing, :getin:

Pollyanna fucked around with this message at 15:46 on Jan 18, 2017

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!

xtal posted:

Self-quoting for context. How much of a coding horror would it be for me to make a Lisp syntax for Rust using Haskell and parsec?

Well, I'm doing this for C (with intent to create a lot of macros to automatically do generics/monomorphisation/better types/etc.,) so I'd be a hypocrite if I didn't say go for it :getin:

xtal
Jan 9, 2011

by Fluffdaddy

Pollyanna posted:

I can understand why you'd want to write your systems and applications as a process tree, but I haven't yet developed a sense of what use cases those would be. I guess I haven't had a need to work on uptime critical systems before, but it sure sounds interesting. I got pretty far into LYAH, so maybe LYSE is up next.

Edit: I have to say, Elixir/Erlang, OTP and the BEAM are how I expected computer programs to work in the first place, so it's nice to see that I wasn't totally off.


As long as it isn't a security critical thing, :getin:

What implications would that have for security? Do you mean it's just silly to make our own language?

Pollyanna
Mar 5, 2005

Milk's on them.


xtal posted:

What implications would that have for security? Do you mean it's just silly to make our own language?

I mean that anything goes really. Ignore what I said about security, I don't know anything about it.

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

xtal posted:

Self-quoting for context. How much of a coding horror would it be for me to make a Lisp syntax for Rust using Haskell and parsec?
Pretty horrifying from a long-term maintenance perspective, but straightforward enough.

One of the fun things about the Rust compiler is that it's pretty well factored into a bunch of distinct libraries--you might actually be able to just drop in a new front-end rather than doing syntax-to-syntax transforms. You'd need to write a parser in Rust to do that, but s-expressions are pretty easy and nom may not be parsec but people seem to like it. This will probably be even less stable than something that emits rust syntax, since internal compiler APIs change whenever they like, but would IMO be a way more interesting project.

Asymmetrikon posted:

Well, I'm doing this for C (with intent to create a lot of macros to automatically do generics/monomorphisation/better types/etc.,) so I'd be a hypocrite if I didn't say go for it :getin:
Not to be an evangelist or anything, but FYI Rust is basically what you get if you start with C and add all those things. Maybe have a look!

Asymmetrikon
Oct 30, 2009

I believe you're a big dork!

Ralith posted:

Not to be an evangelist or anything, but FYI Rust is basically what you get if you start with C and add all those things. Maybe have a look!

Oh, I've written a fair amount of Rust, and I would totally use it for any actual serious low-level work I'd want to do. This is just for my own curiosity - I have some ideas about macros and reinterpretation of Sized types that I want to test out.

MononcQc
May 29, 2007

Mr Shiny Pants posted:

This also how I am imagining the system, so you could say the Erlang VM is kuburnetes? And a process is a docker instance?

Ehhh... analogies like that can help make things click, but you can't program by holding them like a mantra or to that degree of precision. Erlang was made open 19 years ago, and existed for 30+ years before. It has grown in isolation from these things for the most part, and mostly came before them (OO has had many incarnations, so don't hold me to too much precision there). The patterns it uses and allows are disconnected conceptually and come from different motivations.

While it may help to compare broad properties to OO (encapsulation and message passing) and to microservices (isolation and separation of concerns), you can't really bring things much further than that, and sooner or later, it's easier to just abandon preconceptions and just dive in. The blog post / presentation I linked is as abstract I've managed to word things without losing too much, but nothing would beat getting some experience or looking at existing systems or libraries.

Mr Shiny Pants
Nov 12, 2012

Cool, I've watched some talks about Erlang and I think I got a good idea how it conceptually works.

What do you think of Elixir? It seems to have really gained some traction over the last couple of years. Especially with Phoenix.

MononcQc
May 29, 2007

Mr Shiny Pants posted:

Cool, I've watched some talks about Erlang and I think I got a good idea how it conceptually works.

What do you think of Elixir? It seems to have really gained some traction over the last couple of years. Especially with Phoenix.

Elixir and Phoenix seem to be going together the way that Ruby and Rails ended up an indistinguishable thing for most of their respective communities. Elixir has a few niceties and capacities it adds on top of Erlang (protocols are the biggest one), but by all means both maintain very similar semantics overall.

I think the divide that seems to happen now between both communities is that Elixir gets to be used for web and web-related stuff, whereas Erlang keeps seeing more usage at the infrastructure level. There's of course outliers in both directions, but I wouldn't be surprised if <10% of Elixir's usage was non-web stuff, and <5% of Erlang's usage was primarily web stuff (excluding bolting on HTTP APIs on an otherwise non-web service)

While the Elixir community is also still not on solid ground when it comes to OTP -- that stuff takes a while to internalize as a group and I'm not too worried about it -- it still entirely applies and remains valid as a set of design rules, so I'm pretty happy about that.

Pollyanna
Mar 5, 2005

Milk's on them.


I don't see Elixir lasting very long without OTP also becoming a valued asset. It's a functional Ruby otherwise and it would need more of an edge than that to survive long-term.

It helps that OTP is relatively simple in concept, at least.

Workaday Wizard
Oct 23, 2009

by Pragmatica
What *is* OTP anyway? A design pattern? A library? An API?

The little research I did didn't clarify any of that (maybe I'm looking at the wrong docs or at the docs wrong) and the name sure as hell doesn't make it any clearer. It doesn't help that some people mention Erlang/OTP as if it's a variant of Erlang. Well, is it???

totally not baiting mononcqc :P

sarehu
Apr 20, 2007

(call/cc call/cc)

Shinku ABOOKEN posted:

What *is* OTP anyway?

Outlaw Techno Psychobitch.

The March Hare
Oct 15, 2006

Je rêve d'un
Wayne's World 3
Buglord

Shinku ABOOKEN posted:

What *is* OTP anyway? A design pattern? A library? An API?

The little research I did didn't clarify any of that (maybe I'm looking at the wrong docs or at the docs wrong) and the name sure as hell doesn't make it any clearer. It doesn't help that some people mention Erlang/OTP as if it's a variant of Erlang. Well, is it???

totally not baiting mononcqc :P

stdlib

MononcQc
May 29, 2007

Shinku ABOOKEN posted:

What *is* OTP anyway? A design pattern? A library? An API?

The little research I did didn't clarify any of that (maybe I'm looking at the wrong docs or at the docs wrong) and the name sure as hell doesn't make it any clearer. It doesn't help that some people mention Erlang/OTP as if it's a variant of Erlang. Well, is it???

totally not baiting mononcqc :P

OTP is basically the evolution of all the patterns that kept being rediscovered at Ericsson in their big products in the 90s, and then their continuous updating since then.

They found out common design patterns (how to do request/response, how to encode state machines, how to fan-out events, how to handle failures through supervision, and so on), and then turned them into core libraries for generic/specific components. So for a stuff like a 'server' pattern, where a process holds a bit of canonical state and responds based on it to a bunch of randos sending it messages, they abstracted away the common core: sending/receiving messages, maintaining and storing state in memory, handling debug messages, tracing, suspending/resuming workflow, the usage of hooks for introspection, and so on. They did all of that into a core 'gen_server' module (called a 'behaviour'), and what you specify is how to handle messages of various types.

They did this with the most common patterns, and wrapped it with the idea of supervision trees ('supervisor' is one of these behaviours). They took these supervision trees and put them into 'applications' (basically stateful libraries), and built a system of 'releases' around it that handle things like booting, restarting, shutting down, and doing live upgrades of these application and supervisor subtrees.

To make a short story of it, Erlang is a very small language with processes, links, monitors, message passing, and the VM. OTP is the general development framework that specifies how you organize code, write libraries, distribute and boot them no matter the kind of industry you're in.

the talent deficit
Dec 20, 2003

self-deprecation is a very british trait, and problems can arise when the british attempt to do so with a foreign culture





Shinku ABOOKEN posted:

What *is* OTP anyway? A design pattern? A library? An API?

it's the open telecom platform. how much clearer do you need?

(it's basically just erlang's stdlib)

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Ralith posted:

Not to be an evangelist or anything, but FYI Rust is basically what you get if you start with C and add all those things. Maybe have a look!

In the same sense that Sacré Coeur is basically what you get if you start with a primitive hut and then tear it down and build a basilica there, yes. I like Rust, but it is much fairer to say that it is a safer and more principled C++ with a startlingly different syntax. It is a language for motivated experts which yields great rewards for sophisticated use.

the talent deficit
Dec 20, 2003

self-deprecation is a very british trait, and problems can arise when the british attempt to do so with a foreign culture





Mr Shiny Pants posted:

Cool, I've watched some talks about Erlang and I think I got a good idea how it conceptually works.

What do you think of Elixir? It seems to have really gained some traction over the last couple of years. Especially with Phoenix.

i like elixir but i think phoenix is sucking up all the oxygen and phoenix is ultimately just a rails rewrite. i could be wrong, but i think the era where rails style applications were the 'right' way to build an application is gone and things like django, rails, express and phoenix are on the way out

i also think they made some pretty bad choices early on that are going to hurt them longer term. they use key/value dictionaries pretty pervasively throughout the standard library (and even provide sugar for dicts that they call `structs`) when there were faster, safer, more idiomatic data structures available. they also have really fuzzy boundaries between compile time and run time that cause headaches

redleader
Aug 18, 2005

Engage according to operational parameters

the talent deficit posted:

i think the era where rails style applications were the 'right' way to build an application is gone and things like django, rails, express and phoenix are on the way out

Out of curiosity, what do you see as the next big thing in web dev?

the talent deficit
Dec 20, 2003

self-deprecation is a very british trait, and problems can arise when the british attempt to do so with a foreign culture





redleader posted:

Out of curiosity, what do you see as the next big thing in web dev?

i think it's only a matter of time before you see clients that effectively just make rpc calls to a backend service. whether this is negotiated via an sdk that uses graphql/rest or just uses something like gRPC or thrift over http2 i think application developers will stop having to care about the details of how their app talks to the server

on the server side i think it's inevitable that apis reuseable by multiple clients will replace server generated html completely. for web browsers i expect turning javascript off will soon be unthinkable

xtal
Jan 9, 2011

by Fluffdaddy
That's pretty much the status quo, as someone who uses w3m and surf with JavaScript off. Someone should have seen this horror show coming.

Adbot
ADBOT LOVES YOU

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



the talent deficit posted:

i think it's only a matter of time before you see clients that effectively just make rpc calls to a backend service. whether this is negotiated via an sdk that uses graphql/rest or just uses something like gRPC or thrift over http2 i think application developers will stop having to care about the details of how their app talks to the server

on the server side i think it's inevitable that apis reuseable by multiple clients will replace server generated html completely. for web browsers i expect turning javascript off will soon be unthinkable

Just to pick a nit, I don't think server-side rendering is going away anytime soon because people are paranoid about getting something to display ASAP and I don't think those people are going to trust networks to deliver their front-end code fast enough. Granted, this'll probably take the form of running a headless client against the API and shoving what it renders into a cache, so, yeah, agreed that stuff like Django and Rails are going away.

xtal posted:

That's pretty much the status quo, as someone who uses w3m and surf with JavaScript off. Someone should have seen this horror show coming.

Yes, this world where there's a viable solution for a write-once-run-everywhere client UI that can be made to look like not-poo poo, is safely isolated from other programs and is Good Enough for most requirements is truly the stuff of nightmares.

  • Locked thread