Sascha_Wolf:
Hey everybody and welcome to another episode of Elixir Mix. This week on the panel we have Adi Eingar
Adi_Iyengar:
Hello.
Sascha_Wolf:
and Alan Weimar
Allen_Wyma:
Hello
Sascha_Wolf:
and Sasha Wolfe, that's me. I'm back. Yeah, I was on a business trip for a few weeks so I kind of bowed out a bit. It's just a panelist episode this week. No guests, no special anything. But I heard a rumor which said that Adi is going to go on a rant. So Adi, what are you going to rant about?
Adi_Iyengar:
Yeah, yeah. So I was telling Alan and Sasha before we started recording that weirdly, recently I've had few instances where some really otherwise you'd think of them as established elixir companies have really weird patterns, way beyond what you would expect from a legacy, especially with storing, using processes in a weird way. And it starts to sing, wait, I'll give an example of one I had yesterday this company, they had these stack of function calls. And each function was doing something, and the last part of that was a change set call to create a struct eventually. They needed to change the entire pipeline such that some of those functions would depend on a user, which probably comes in the front end somehow. Don't know. So the solution for that, instead of changing the signature of all the functions to take a user as an argument, was to, before starting the pipeline, put the user in the process, using process output. So using the dictionary of the process. And functions that need users would use that process, this dictionary, to get the user's value and calculate whatever they need to calculate. It's pretty crazy. Big things, big reasons why I want to do it is if you run it concurrently, if you run it, if you paralyze it, what if you decide some of the functions need to be spawned into a task, process.get will not give you that. What if you decide to not link the processes? Then the leader itself might be a different process. There's no way for you to get the state without having the PID. Anyway, I was just like mind boggled by this. And there's a few other instances, like we can talk more about that, but would love to get Alan and Sasha your thoughts on this. I was like, I did not know what to say. I was literally trying to, because my instinct was like first trying to give people the command for the doubt, assume that they are smart people. Why would smart people make this decision? And I could not come up with a single reason.
Sascha_Wolf:
To be honest, the way you described it now, earlier it was a little bit different, but now I feel it smells like something somebody would do who is familiar with having a setup of a global variable or something, or a thing where they can put content and then say, okay, in this function, I'm just gonna access this thing over here and load it from there, right? It really looks like something somebody might buy. building who is really not familiar with the functional paradigm and also how you would usually build those things on the beam. I've worked with people which were very good at getting stuff done, but they really stopped there. Like they built something, it worked, done. And this smells like it, you know? And I'm not even putting any kind of like here evaluation on this and what seems as bad as this is good because depending on the task at hand is really good to have people who are comfortable they they know their tools they build the thing they're done if it's not a highly critical part of part of a product so be it right But sometimes you get stuff like that So, um, yeah maybe maybe to ask uh Give you a question back, Adi, where would you expect to see the process dictionary be used?
Adi_Iyengar:
Yeah, I mean, that's a good one. I mean, to summarize it, I don't ever use it unless I'm doing a one-time task debugging messages, debugging through storing states. Like one example,
Sascha_Wolf:
Hmm?
Adi_Iyengar:
a classic example of that is like, say you want to do IEXPRI or a breakpoint in your test suite. But the test suite runs in a loop. The same line runs multiple times. But you want to pry only for a specific case. But you don't know what that case is at compile time. But when you're running, you know what that case is. For example, if ID is something, but ID is generated at runtime. So what you could do is, all right, in the IEX, I will pry right away. Get the ID for which I need to pry. And in the compile time, I'll say pry if process state is pry. And I would set that state manually in IEX ID is what I need it to be to make it probably only once instead of 1,000 times. It's like
Sascha_Wolf:
Mm-hmm.
Adi_Iyengar:
weird cases like this where you might need some kind of global state runtime. Makes sense. If you need it runtime not in a one time scenario, I would use agents. But also only do that when it's a specific domain or gen server if the client-side architecture is a bit more complex than just state. But yeah, process.put is just something I just would never use.
Sascha_Wolf:
What about you, Ellen?
Allen_Wyma:
I was told never to use it and I just never use it. So
Adi_Iyengar:
Awesome.
Allen_Wyma:
I try to keep, yeah, I mean, a lot of the work I do is really request-based. It's not like long running. So I mean, you just assign it to the socket or assign it to the controller connection. And yeah, just let it be. Very few things I have which could be used. I mean, in that case, yeah, put it into some central gen server. I think I heard talk that they're going to be removing agents or something from Elixir. I remember Jose talking about this recently. Something about they're talking about agents really recently. I think they're or maybe they're going to revise their documentation that they're going to stop talking about agents so much and point you over to gen servers. Have you guys seen this? Judging by Adi's
Adi_Iyengar:
I have not.
Allen_Wyma:
disgusted face, I'm guessing not.
Adi_Iyengar:
No, agents, I mean, that's fine. Agents use Gen7 in the back end, right? But I just loved how simple it is to use agents to set up state. The reason I specifically brought up agents is because by using them, you're kind of eliminating the need to put it in a state in a random process. Right. And if you're making an argument against GenServer that it's too hard to set up, there's a lot of boilerplate work to do, agents help you do that. Right. But yeah, it's weird that Jose is thinking about that. I'm sure someone will write an agent's library.
Sascha_Wolf:
I'm... I won't be surprised. This sounds like a rumor to be honest.
Adi_Iyengar:
Yeah. Yeah.
Allen_Wyma:
It's not a rumor. It's not a rumor. I see the tweet. So excuse me. I think I said something, and then I was more correct the second time, right? So if you go to elixirlang.com, slash getting started talking about OTP, Jose specifically said this on the 24th of October. The current, well, this probably should be late on the 23rd, because earlier my time. The current plan is to remove the chapter on agents and jump straight into GenServer. And also remove the ETS bits and use the registry instead. Those are his exact words. I just read.
Sascha_Wolf:
But this sounds like in the context of a specific project, not as like a general thing.
Allen_Wyma:
No, not actually moving the code, but it's about removing the in the guides for getting started in Elixir, which is pretty interesting.
Sascha_Wolf:
Ah, okay. I can see that it might make sense to push people a bit earlier into the Gen Server land than into Agent land because I have observed that people who start out with Elixir, Agent becomes kind of the hammer and everything is a nail when it gets to process management. And there are use cases when Agent makes sense, but more often than not... you might actually be better off in building a GenServer. As soon as you have some level of business logic attached, non-trivial business logic attached to your state management and a GenServer is, in my opinion, always the better choice. There's not that many scenarios where an agent is superior to a GenServer. There are some, but general, I would say. The GenServer general is a more... solid choice, let's say that. It always depends, right? So I could see why that makes sense. It's still a useful tool though.
Allen_Wyma:
Yeah, I'd feel like I think the one thing I initially did not like and also didn't totally understand what's the point of an agent for some time because it's very strange, right? Because it is basically a gen server underneath. And you're sending the function to mutate the data. So it's definitely weirder. I just find it more clear if I write a gen server to begin with, because it's like You could start with an agent and then you'd probably want to upgrade to a gen server as time goes on. If you started this from a gen server, you would never need to upgrade to an agent because it's already a gen server and you can do whatever you want with it. And you get kind of more protection from that. You know, sending a function where it could do whatever it seems a little bit more dangerous than describing and sending out specific API for a gen server saying, okay, do this and do that. And you cannot do these other things. Does that make sense? The audio looks a little bit confused.
Adi_Iyengar:
Oh yeah, I don't quite understand the last part. You said creating a function that does whatever. Can you elaborate?
Allen_Wyma:
Okay. So if you look at it from, I haven't used agents for a while, right. But what I remember, let me know if I'm wrong, because I, it's really been a while is that you can set, you'd send a function to, to the agent, like get an update, right? Whatever you change in there, like you can just send a function that will just return a random number, like 42. But if I instead make an API where it says, okay, I don't want to directly mutate this, but I can send in a message, which in turn will do whatever action I want it to do. Like I can kind of restrict the API a little bit more. Right with the agent, you as long as you send a function doesn't matter what it does, as long as it obeys the rules, you can
Adi_Iyengar:
Yeah,
Allen_Wyma:
do whatever
Adi_Iyengar:
I mean,
Allen_Wyma:
you want.
Adi_Iyengar:
that's the whole point of agents. It's all about setting state and updating state, only for that. It's not about control, about any business logic or anything. That's not what it's meant for. I mean, I use it quite heavily because it's just convenient for storing states. I use DynService too when I need to add something simple. But yeah, agents are basically, it's a client. side of GenServer, the store states. That's what it is, right? So it's like if you write a root of GenServer store states and wrote the client side, not the server side, not the handle callbacks, that's what agent is. So I mean,
Sascha_Wolf:
Thanks
Adi_Iyengar:
it's
Sascha_Wolf:
for watching!
Adi_Iyengar:
simple. If you want to replace with a GenServer, just same module. You can still keep the agent functions. Add a handle call. Had like a add handle callbacks in the same module, and it'll still work. You can still use GenServer callbacks agent that you start because it's
Sascha_Wolf:
I mean,
Adi_Iyengar:
still the process
Sascha_Wolf:
under the
Adi_Iyengar:
with that
Sascha_Wolf:
hood,
Adi_Iyengar:
name.
Sascha_Wolf:
yeah, it's still an agent server under the hood, right?
Adi_Iyengar:
Right, exactly.
Sascha_Wolf:
The thing about, like, what I think Ailun is also getting at is that if the function, when you could say agent get, for example, you pass it a function, that that function is actually sent to the agent and then executed in the context of the agent, and then whatever response is sent back. And there are some foot guns there because anonymous functions capture the context in which they're executed. So if you, for example, buy, like, So one thing you might be doing is you have like a super big dictionary or whatever, or maybe even a big binary. And you want to do some of that work in the context of a function, like, hey, if it matches that thing, or if this field of this dictionary matches those things, then maybe do something else. And then basically you send alongside the function to the agent, also this captured state, this big dictionary. And that's the kind of a foot gun, which can happen.
Adi_Iyengar:
Well, then you're using agents wrong, right? Like
Sascha_Wolf:
Yeah,
Adi_Iyengar:
it.
Sascha_Wolf:
but you're using agents wrong. You say that so easily, but there are these footguns. People, especially who are starting out, they get nudged towards
Adi_Iyengar:
Sure.
Sascha_Wolf:
agents,
Adi_Iyengar:
Yeah.
Sascha_Wolf:
and they definitely don't know about this. I would never expect somebody starting out in Alexia to be aware of this footgun. So yeah, I can see why they're saying, why Jose is saying that they maybe, agents, I don't think they plan on roving agents, but maybe nudged newbies, not... as hard into the other direction. I think it makes sense. Okay. Maybe to
Allen_Wyma:
I think
Sascha_Wolf:
come
Allen_Wyma:
the
Sascha_Wolf:
back
Allen_Wyma:
registry
Sascha_Wolf:
to the process...
Allen_Wyma:
part is really interesting though. Sorry, I've actually used the registry only for dynamic processes. We're using like
Sascha_Wolf:
Me too.
Allen_Wyma:
the one for one. I've never used it for anything else, but I am aware that you can also use it as a pub sub, which is interesting.
Sascha_Wolf:
Yeah, you can do.
Allen_Wyma:
Yeah,
Sascha_Wolf:
As even
Allen_Wyma:
that's the only two things I know about.
Sascha_Wolf:
in the documentation, there's a part about Nerdistaria, they say, hey, you can use this as a simple PAPS app thing. I have not done it myself, but yeah, I can see it being useful for that.
Adi_Iyengar:
Yeah, I think it's got like dispatch, right? That's
Sascha_Wolf:
Yeah,
Adi_Iyengar:
what,
Sascha_Wolf:
exactly.
Adi_Iyengar:
yep, yep.
Sascha_Wolf:
How do we end
Allen_Wyma:
Yeah.
Sascha_Wolf:
up at the registry?
Allen_Wyma:
Well, because that's also what he talked about too, is kind of removing ETS, which is one of the high level chapters on getting started OTP, and put the registry there.
Sascha_Wolf:
Ah, okay.
Allen_Wyma:
That's why
Sascha_Wolf:
Yeah,
Allen_Wyma:
we're talking
Sascha_Wolf:
I
Allen_Wyma:
about this.
Sascha_Wolf:
see now. Also remove the ETS bits and use the virtual string set. I'm not sure if I'm a fan of that because ETS is really, it's really, ETS is nice. ETS is a powerful tool, but maybe I'm too much into the words to see the forest or trees.
Adi_Iyengar:
The reasoning seems opposite of agent's sense over here.
Sascha_Wolf:
Ya, ya, ya, ya.
Adi_Iyengar:
Yeah, it caught a rick start. So.
Sascha_Wolf:
Well, this is not meant to be a Jose Duncan episode. So maybe circle back to the... We kind of left process dictionary discussion up in the air, as if some state we never cleaned up. See what I did there?
Adi_Iyengar:
Like that. I like that.
Sascha_Wolf:
And because I actually want to give one example of where I did use process dictionaries. And first of all, I agree with Alan and Adi. So, number one of process dictionary, don't use it. Number two of process dictionary, don't use it. Number three of process dictionary. If you have runtime meta information you might want to drag along and you don't want to pollute your functions with it, then maybe use process dictionary. And that is the use case I want to mention because we were, that was way before open telemetry was a thing or telemetry in general. But that thing didn't, didn't, those things didn't exist back then. And we set up some tracing integration into our event-driven system. This event source system I already mentioned a few times on the show. And we wanted to basically pass along the tracing, the span IDs to the event emitting logic so it could. added as meta information so that the event consumers could attach themselves as like auto start spends and say, Hey, this spam ID is the parent, you know? And that's meta information. That's completely orthogonal to the actual business logic at hand. The business logic at hand doesn't care about tracing, like not at all. And so we were left at this point where we're okay, we have this information. We have this meta information and we want to pass it along to this event emitting logic. But we don't want to pollute our business logic because we would have to add it to every kind of business logic function to drag it along. So that is when we use the process dictionary. We put in the process, OK, put here this tracing span ID. Then we fetched it from there in the event emitting logic and said, OK, now add it to the metadata. And that worked really nicely. But it still feels hacky. It felt. It felt weird because it is kind of akin to like a global-ish variable, like on the process level state. But this is the one scenario where I would be saying something like that. Process dictionary usage in production is, is, is reasonable. And from what I've also heard, we had like one time at an episode with, I forgot his name, but like somebody who is building the Erlang. client for open telemetry. And he basically also said like, hey, this is kind of the main use. This is like the idea behind the process dictionary, this kind of information.
Adi_Iyengar:
Yeah. Quick question. I guess same problem, right? You're spawning multiple processes that are not linked. How would you ensure that the same trace ID goes into all those processes that you're spawning?
Sascha_Wolf:
At that point, you need to be explicit then. Like when you spawn them, you do have to send maybe as a metadata
Adi_Iyengar:
The trace
Sascha_Wolf:
thing.
Adi_Iyengar:
ID itself, yeah.
Sascha_Wolf:
Yeah, and say here, metadata, here's the trace ID. And then I would expect those process again to take it and put it in the
Adi_Iyengar:
All right,
Sascha_Wolf:
process dictionary. So like
Adi_Iyengar:
got
Sascha_Wolf:
that's
Adi_Iyengar:
it.
Sascha_Wolf:
like where you need to then
Adi_Iyengar:
So
Sascha_Wolf:
again.
Adi_Iyengar:
spawn link with trace. Awesome.
Sascha_Wolf:
Yeah, kind of.
Adi_Iyengar:
Got it.
Sascha_Wolf:
But
Adi_Iyengar:
Yeah, I guess I can see.
Sascha_Wolf:
the nice thing what happened then is like also like on our, we were using, I forgot, is this something with Z? Is this tracing visualization thing cause something with Z? Oh, I forgot it. But we could actually then see like the main span, right? For the web request that started, that ended. And then like these event consuming spans down there. It was beautiful, seriously. It was so useful also to sometimes when we had misbehaving events or things which were consuming over and over again, it was like, oh yeah, there you can see it in the span. It's like consuming and consuming and consuming and consuming. The span is just gigantic. The trace is gigantic. So that was, that was really nice. But yeah, like I said, first rule, don't use it. Second rule, don't use it. Third rule, maybe for runtime meta information.
Adi_Iyengar:
Yeah, so I guess let's try to like, I would love to like summarize that. So I think why is process dictionary a good thing to use there? Why can't we use agents? Because I guess it was state specific to the process, right?
Sascha_Wolf:
Exactly.
Adi_Iyengar:
It wasn't like a random state, a random variable that is storing that that's required for execution of the function. It's very clear that the trace belongs to a process. That association was very clear and that's why it made sense to use process dictionary over an agent. I guess you could still use an agent and or a gen server with a key hid to trace, but just be longer harder to maintain that way. And that's
Sascha_Wolf:
And
Adi_Iyengar:
why I guess.
Sascha_Wolf:
you also get into the risk of building yourself a bottleneck. You know, like, I mean,
Adi_Iyengar:
Right.
Sascha_Wolf:
the easiest thing would be to use
Adi_Iyengar:
Yeah.
Sascha_Wolf:
then one gen server, but then you're like a natural bottleneck in the system.
Adi_Iyengar:
Right, exactly.
Sascha_Wolf:
And.
Adi_Iyengar:
You'll slow it down. Yeah, makes sense. Easiest to get. It's also like easiest to get state from the current process. So yeah, totally makes sense. I think this is a good one. So like anything that's associated with the process, which also you won't be changing that often, that's also key. Something that you don't change that often is a good candidate for process dictionary.
Sascha_Wolf:
And also I would add, and we're just orthogonal to your business logic, like where your business logic doesn't
Adi_Iyengar:
Yeah,
Sascha_Wolf:
really care about it, because this
Adi_Iyengar:
right.
Sascha_Wolf:
is a purely runtime concern. This
Adi_Iyengar:
Yeah.
Sascha_Wolf:
is just like an observability scenario, which, which helps you when understanding your system. But the business logic really doesn't care about this. Like
Adi_Iyengar:
Right,
Sascha_Wolf:
not at all.
Adi_Iyengar:
right, right. Yep. Awesome. I like using process experience for that use case, actually. You said it doesn't feel right, but I actually think it might be the
Sascha_Wolf:
Yeah,
Adi_Iyengar:
best
Sascha_Wolf:
I mean,
Adi_Iyengar:
solution.
Sascha_Wolf:
I
Adi_Iyengar:
Yep.
Sascha_Wolf:
meant mainly like it made sense to do it, but it felt often the sense of like, this feels like I'm using global state. I feel dirty.
Adi_Iyengar:
Right, right, right. But I mean, there is a global state,
Sascha_Wolf:
Yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah
Adi_Iyengar:
right? Yeah, yeah, yeah, yeah. I mean, you could pass trace ID as a variable for every function, too. You could do that, too. But
Sascha_Wolf:
Yeah,
Adi_Iyengar:
yeah,
Sascha_Wolf:
that was the alternative, and that,
Adi_Iyengar:
yeah,
Sascha_Wolf:
that,
Adi_Iyengar:
but
Sascha_Wolf:
that...
Adi_Iyengar:
it's just too much work. Yeah, too much work, yeah.
Sascha_Wolf:
So any other anti-patterns you've seen and like especially in the OTP context and I think I already hinted at some other Things you ranted about earlier. So maybe Ellen do you have any seen maybe Legacy code bases or something where you feel like what the heck were they thinking like where somebody clearly Did not grok yet. What OTP is kind of trying to achieve because I've seen things like that I mean the classic one is this gen server as a bottleneck what it was one big gen server, but it's talking to Classic anti-pattern, but any other little tidbits?
Allen_Wyma:
Hmm. I wish I could come up with something specific at the moment, but I'm still working with a pretty young guy on our project. And he's very, he's very eager to code stuff, right. And I feel like he kind of codes things quicker than actually thinking about it, because he has like, you know, he's got the idea, right. But he doesn't have the syntax down. So he kind of gets these weird things that he does. And I get a little bit confused. Because I'm like, what is it you're trying to do? And sometimes I look at I know what he's trying to do. But I'm just trying to think about something that I saw recently that really like confused the heck out of me. But kind of made sense on his side. Yeah, I'm sorry. Nothing's coming to my mind, but I wish something would come. But I just think about that. Like, there's just some things that are a little bit weird in Alex or that it's a little bit hard to explain to some people. Um, I mean, I think kind of sticking to that new people topic, right? Live view is a little bit confusing to a lot of people, right? Because it's not very linear with like these handle events and, and mounting and all this kind of stuff. That's something that I try to explain to new people and they get really confused. Now with the HIC syntax and creating new components that are, you know, dumb components or non-live dead ones, or it's also gets a little bit confusing to some people too, because you can just make up attributes on the fly that in turn will generate new things. Do you guys know what I'm talking about? These, the new HIC style with the dead, the dead components or you call them, I call them dead
Sascha_Wolf:
Yeah,
Allen_Wyma:
because they're not like the live components, right?
Sascha_Wolf:
I have to admit, like, I've been keeping up to date on the developments there. I've not yet used any of those fancy new things. So shame on me.
Allen_Wyma:
Yeah, it's really cool. Like I like the idea. Like it's kind of like we're going from, you know, Oh, I have to do this. So I have to like paste boilerplate, right? Boilerplate HTML. Now we're at a point where we can say, okay, we put these not boiler. It's like semantic HTML now. Right. With these kinds of new styles. It's nice, but at the same time, it's like, maybe this page doesn't exactly work out that like, I don't want. this thing here. And so you kind of have to say, like, now we're back to the same thing that we were trying not to do, which is like, OK, I don't want to repeat. I want it to be clear what I'm doing. But at the same time, sometimes I don't want something that should be in most pages, right? So then you end up hacking your way in. Like, OK, if I add this attribute or if I set this thing to false, I want to turn off all these different things. You know what I'm talking about?
Adi_Iyengar:
Yeah, at a high level.
Allen_Wyma:
I don't have a specific example, but yeah, there's some stuff that I'm still a bit confused on like slots. Have you guys tried using Render Slot yet? Okay, slots are cool. So for instance, I made like a like a panel component. And when you mouse over it, it's gonna have like a tool tip that comes up. So I have a tool tip slot. But the only issue is that I haven't found an easy way to say like, okay, if I don't add a tool tip, what to do. So then I had this weird problem where like I'd mouse over it and the tool tip came up, but it was empty. But it's not really empty because it has like space. Because like when you have a slot and it's empty, it still has something there. It's not actually now. It's a little bit weird to explain, but
Adi_Iyengar:
What is this slot?
Allen_Wyma:
Yeah, a slot, yeah. So you have this render slot
Adi_Iyengar:
What is
Allen_Wyma:
thing.
Adi_Iyengar:
a slot?
Allen_Wyma:
What is this slot? It's kind of like. like optional HTML. So let's say that you have a, like I think the example that I often see is like a modal. And say that your modal could just have one phrase, like error happened. And then like you can say like, OK, press OK to close it, right? But then you may have another, you may want to reuse that modal template to maybe have like a paragraph talking more about what actually happened. And so you can have an optional slot that if you put in the put in stuff there, it'll be all styled up with whatever you want. Right. I guess maybe I'm not doing a very good job explaining it.
Adi_Iyengar:
No, I'm trying to understand. So it's basically another way you can make your Heaps dynamic on top of components and other stuff. It's just another way you can make it dynamic. I'm trying to understand where you would use that over.
Allen_Wyma:
Let me actually send you something, because I think this is a good example. I... You guys should be happy you always have to type in English. I keep having this stupid Chinese input pop up all the time. Uh, okay. Render slot. There's a nice example over here, basically. Um, I'll just send you the link. So for render slot, they show an example, right? So you have a high level component called table, and then you could add many columns and the colon cowl is basically a slot. And so within that slot, you would have a user.name for the first one and user.address for the second one. And so you could have many different slots and all these slots are, you know, start up a certain way.
Adi_Iyengar:
Got it. I will still have to understand this. I don't see where you're declaring the slot you're rendering as a column. I don't see that in the
Allen_Wyma:
Scroll
Adi_Iyengar:
elixir
Allen_Wyma:
down a bit
Adi_Iyengar:
part
Allen_Wyma:
more.
Adi_Iyengar:
up there.
Allen_Wyma:
You'll see that
Sascha_Wolf:
Do we want to continue talking about slots?
Adi_Iyengar:
No, no,
Allen_Wyma:
Okay,
Adi_Iyengar:
I'm
Allen_Wyma:
slater.
Adi_Iyengar:
so sorry. I have to control my curiosity. Thanks for sharing it out and I will definitely check it out and
Allen_Wyma:
Slots are a little bit annoying, right? Yeah, dude. I don't know. I
Adi_Iyengar:
I
Allen_Wyma:
need
Adi_Iyengar:
mean,
Allen_Wyma:
to get used to them some more.
Adi_Iyengar:
yeah, I feel like the new Phoenix Live View has so many things that I honestly just didn't need to use most of it. But I would, yeah, which is why I'm a little behind on some of the new stuff over here. But speaking of Live View and speaking of OTP, one of the things that I always, it surprisingly gets a good reaction from a lot of mid-level and junior engineers is like when you share your screen, click on the mount function, or click on any of the handle callbacks, it's so easy to figure out it's just a gen server. Right? Sorry, Alan, tying this back to the OTP in a very smooth way. But yeah, it's...
Sascha_Wolf:
Smooth Eddie, smooth.
Adi_Iyengar:
But anyway, I mentor a few people outside of my work and... Like every time one of my first instances, like if they have a question, how does this work? I share my screen, click on the code, and look at it. It's written there. But I think the reaction when they realize, oh, it's a live view is just simply a gen server. That's it. I mean, there's minor things going on outside of the callback, but the whole clients of architecture remains. And it just makes live view so simple for people to like, it makes it more accessible for them to look at the code and try to understand how it works. Because best way to learn how something works is just look at its code, right? So, Adam, you might want to try that with your new hire as well.
Allen_Wyma:
But here's the other thing too, is you also have to explain to people what is a gen server, which is not so simple to explain because you have to explain processes. Now what's the process right now? Imagine talking to somebody, all they do is procedural programming with Python or JavaScript. Okay. Let's just stick to Python only because I have an actual example with that one to explain to them. What is a gen server where events come in and you're sending messages. It just does not compute. It's really hard
Adi_Iyengar:
Yeah.
Allen_Wyma:
to explain.
Adi_Iyengar:
I think...
Sascha_Wolf:
So,
Adi_Iyengar:
Yeah.
Sascha_Wolf:
Ellen, wait, Ellen, Ellen, what's a GenServer?
Allen_Wyma:
Man, I don't even know what the hell is a Hello World program at this point, to be honest, sometimes. Yeah, I don't know how to even explain what a GenServer is. It's a process that waits for messages and can sometimes send back replies. I don't even know how to even say it. It's hard to say it because they're very complicated, yet they're also simple at the same time, right? Because all that stuff right into the hood is really amazing, right?
Adi_Iyengar:
Yeah, I think one of the things I do with new Elixir people, I mean, I ask them to read the Elixir in action. It explains all of the first few chapters of this. It explains it so well. Using spawn, using receive blocks, without actually doing gen server, makes them really understand how Elixir works and what processes mean in Elixir, or in OTP. that a process can have an infinitely recursive function running without stack overflow that literally just receives messages. That is what you've got to understand first. Because Den Server is a simplified version of that. It creates an interface for you to build a process that does exactly that, the whole tail call recursion optimization that allows a process just, I'm just going to run this function that just receives messages. That's a process in our line. That's what it is. It's not a logic, it's a logical process, not a physical process, right? That's something that not everyone gets right away, which I think Erlang, I can't remember if it was OTP inaction or it was Elixir inaction. I think both do a very good job explaining that, but that's like first two or three chapters of that, like creates like a good, you know, overall understanding of Elixir and Beam. And then I also recommend doing the little Elixir and OTP guidebook. which has a lot of exercises for them to understand how things work. If you understand how a process works in Elixir, it's not too long of a line to draw from a process to a gem server, which is like a standard where everyone has accepted. We're going to define a long-running process.
Allen_Wyma:
Yeah, but it's also interesting, too, to see how many other languages and frameworks do have a similar idea, right? So
Adi_Iyengar:
Golf?
Allen_Wyma:
I well, I mean, I go. Yeah, go is a good example. It's a great example.
Sascha_Wolf:
Sieht aus wie Scharpów Acker.
Allen_Wyma:
Yeah, OK. But that's basically, let's not count that one because it's basically the guy wrote Aka for Java because he couldn't do Erlang. That's what I understand where Aka came from.
Sascha_Wolf:
Yeah.
Allen_Wyma:
And C Sharp,
Adi_Iyengar:
and
Allen_Wyma:
I
Adi_Iyengar:
what
Allen_Wyma:
mean,
Adi_Iyengar:
I can see now.
Allen_Wyma:
they copy off of Java or whatever, whatever you want to call it. The Dart, which powers Flutter, they have an idea called isolate, which is basically a copy of also Erlang built into the language itself, not like an added in library like Aka. It's actually built into the language. Tokyo, which is the, which I think everybody here has been playing around with rust a little bit. Tokyo is basically the async framework runtime for rust has a very similar thing where they run also a schedulers with lightweight processes. So like, I don't know, I don't know if be necessary did all these things with everything, but a lot of languages actually have this idea too. So it's quite interesting to see. And I think even like GIL lock languages like Python stuff also do something kind of similar because you don't really have true threading so you don't get like multi core stuff but you do have things like g event which will allow you to like do multi multi processing multi threading but only with iO which is interesting
Adi_Iyengar:
I don't know half the things they've mentioned here, concurrency libraries. I do know that I think the logical processes, yes there are languages that do that. I think logical processes with the way Erlang does it with message passing, that's rare. That's why I think Go is very close with the communicating sequential processes part, right? But it's not quite what Erlang does, like they don't quite have a message queue that processes read through, you know. It's like, it's a... I think that whole I don't know of another another language that does it exactly like beam does you know I know there's like stuff written in Haskell that there are actor models but actor model doesn't necessarily mean the message passing logical processes right so yeah. Yeah, I have tried doing concurrency with Haskell, Rust. Rust is very weird, because it has so many ways of doing things, concurrency, right? But the one that comes with it, the thread, with send and sync, that's completely based on mutable state, right? The sync part especially, that's very different from Erlang. So anyway, I think that's where Erlang is so cool, where you have all these abstractions around things that can take a request for you, without even knowing the context of the request. And you also have a nice interface to load context into the request, right? Into them. I mean, you can make RPCs. You can pass messages between processes. But the way message will be processed within that process is completely independent of your overall program, overall application that's running. That's so cool. It makes the overall idea of process so lightweight. I, which is why, again, going back to the initial problem we started talking about, it was so weird that they used a process to store state that tied to the business logic, right? It's like goes against what you're supposed to use process in neural language.
Sascha_Wolf:
It basically binds the behavior of your program to the way you run it, right? Which is,
Adi_Iyengar:
Right. And
Sascha_Wolf:
it
Adi_Iyengar:
our
Sascha_Wolf:
is directly.
Adi_Iyengar:
language is supposed to be opposite of that.
Sascha_Wolf:
Yeah.
Adi_Iyengar:
Yeah.
Sascha_Wolf:
Well, so maybe maybe another question for you. I mean, maybe I kind of asked that just now, Alan, right? But what about some anti-patterns you've also seen? Uh, I maybe to elaborate on what I said earlier, I think the classic one really is this. one gen server to root them all. Like every program in your, every process in on your Beam instance communicates with the same gen server, which creates this natural bottleneck. So in the beginning it might be fine. I listened to it. It's like a classic scenario of like, if you run it locally, it works fine. If you want maybe in staging, if you have a number of users, works fine. Then you put it in production and it breaks because this process is not able to. handle the number of messages coming in. So that is something I've built that myself when I was learning Elixir and when I was learning OTP because I didn't understand the implications of this one process handling all of that. It was in this case it was not such a big deal because like it was in a part of a system which didn't get that much traffic. And one of our senior engineers also reviewed it and was like, yeah, you might not want to do it. But I think in this particular case, also because we want to ship it, but sooner or later, it's okay. But this is like one of these pitfalls, these foot guns. I'm not even sure you pick up on easily if you don't necessarily read a book, which specifically mentions that. Because I, correct me if I'm wrong, I can't remember any part of documentation talking about this particular anti-pattern. So maybe any other anti-patterns you have seen, Ali, that's from people who maybe I don't understand OTP
Adi_Iyengar:
Yeah.
Sascha_Wolf:
as well yet.
Adi_Iyengar:
Yeah, I think in general, I think it's for even senior engineers to keep the, think of GEN server, any processes in Elixir, anything that stores data as a database. CAP theorem still is valid. If you are building a high availability system that you were mentioning, it's actually want response from a GEN service quickly, you do need to have a high availability system. multiple GenServer. GenStage makes it quite easy for you to spawn multiple processes. And you can monitor a primary GenServer, the other processes monitor, and replicate the state. There will be replication lag. But it comes at the cost of consistency, depending on which GenServer finally gets a call. So I think that isn't very obvious to everyone. When working with GenServers, one GenServer to rule them all is, you write a very common pattern. Another one is using, I mean, honestly, replicating what GenStage would be doing, manually creating multiple GenServers and dispatching requests to multiple GenServers, because that's exactly what GenStage is for. So that's another common one. One that I mentioned, I guess, before we started recording was, I just don't, this is another thing, is that I don't know why maybe you guys can. figure out why someone would try to do this. If a process A wants to communicate with process B, all the communication was going through C. So process A was sending a message to C, and B was monitoring and replicating all these messages. I did not understand the reasoning behind it, you know? Like, yeah, I don't know if you guys can think of a reason why someone would do it this way.
Sascha_Wolf:
Not without more context. Maybe
Adi_Iyengar:
I-
Sascha_Wolf:
there
Adi_Iyengar:
I-
Sascha_Wolf:
was a good enough reason in the history of building things. You know, like the
Adi_Iyengar:
Right.
Sascha_Wolf:
system evolved and then it ended up at this point and nobody took a
Adi_Iyengar:
That
Sascha_Wolf:
step
Adi_Iyengar:
was,
Sascha_Wolf:
back and was
Adi_Iyengar:
yeah.
Sascha_Wolf:
like, wait, this doesn't make any sense anymore.
Adi_Iyengar:
Right.
Sascha_Wolf:
That's like a scenario I could see because I've seen my fair share of code which ends up looking and you're like, this doesn't make no sense, you know? But then you... understand how it came to be and you understand at least why it ended up being this way even if it's still nonsensical.
Adi_Iyengar:
Right, right.
Sascha_Wolf:
But
Adi_Iyengar:
Yeah,
Sascha_Wolf:
the part of that now.
Adi_Iyengar:
I think the whole, I think you might be onto something. I think the process B part was already built, how it would, the business logic wasn't process B. They wanted to separate which process reacts to the state changes. But that's what Gen7 is for, right? If process B has modules loaded that respond to state, you just build a Gen7 on the store state in process B itself.
Sascha_Wolf:
Wait, I can see one potential reason. Um, was process a waiting for responses from this process C or was it? Yeah. Okay.
Adi_Iyengar:
Yeah,
Sascha_Wolf:
And then, then,
Adi_Iyengar:
it
Sascha_Wolf:
then,
Adi_Iyengar:
wasn't, it wasn't, it wasn't,
Sascha_Wolf:
oh,
Adi_Iyengar:
it
Sascha_Wolf:
it
Adi_Iyengar:
wasn't,
Sascha_Wolf:
was,
Adi_Iyengar:
right? Because
Sascha_Wolf:
it was casting. It was casting
Adi_Iyengar:
it was just casting,
Sascha_Wolf:
it.
Adi_Iyengar:
yeah.
Sascha_Wolf:
Okay. Then then no, because if it was calling, then I could maybe see, okay, process C maybe does like something lightweight of a message is just cute. Like it's a poor man's cue, you know, like where maybe the operation of process B is like so long running. Then it's like, okay, we don't want to block process A, so we have this process C in between as like a buffer, kinda, you
Adi_Iyengar:
But
Sascha_Wolf:
know?
Adi_Iyengar:
you don't need that in elixir, you don't need that in beam at all.
Sascha_Wolf:
If you do call, then potentially.
Adi_Iyengar:
But sure, get it. I get it. It was it wasn't responsive. See, would be just OK anyway. So it's call is like effectively a cast at that point.
Sascha_Wolf:
Yeah.
Adi_Iyengar:
So I see what you're saying. But in our line, it doesn't make sense. So much more work for nothing.
Sascha_Wolf:
Yeah, like I said, it probably is something which grew organically over time, and ended up being this way, and nobody took the time or had the mental capacity to take a step back and say, wait, what are we doing here?
Allen_Wyma:
Or maybe you remove this thing. You know, you ever seen the line of code that says, don't remove this line of code you think is innocuous?
Adi_Iyengar:
Yeah.
Allen_Wyma:
You remove it, and then everything falls apart. So maybe there's something here. That's the matchstick that holds up the entire
Sascha_Wolf:
Hahaha!
Adi_Iyengar:
Yeah,
Allen_Wyma:
building.
Adi_Iyengar:
yeah, maybe, maybe. Again, I heard this story secondhand from an engineer who recently joined that company. But again, it's very surprising that these kind of things happen.
Sascha_Wolf:
But I guess it sheds some light on why the community also tends to say and push this notion of you have understood OTP when you start to think about the application in the context of like, how might the supervision tree look like, right? Because at that point, you're really considering, okay, what are some, what are things which need to run in separate processes? What can run together in the same processes? Do I need, do I need any? Do I need to spin up multiple processes for this thing over there? Or is one enough? Right. And if this way of thinking has not really yet, I don't know, been grok'd by somebody starting out, then I can see how somebody who might still have to deal with processes because it's maybe the system already did it before, ends up doing these things because they don't really understand the impact of the changes. And to be honest, I don't blame them. OTP is a really cool piece of technology and I really enjoy using it, but it takes a bit of... you have to wrap your head around it first.
Adi_Iyengar:
Totally, totally, yeah. And I want to give a very quick example of how cool OTP is. So the startup that I'm leaving, we scaled a suite of applications. Just simple Heroku deployment architecture would pay less than $1,000 a month for our entire architecture, entire infrastructure. We scaled 60,000 concurrent requests. Three horizontally scaled instances of Elixir application. If it was Ruby on Rails, if it was Node, it was anything else. You would need 20, 25, 60,000 concurrent requests, right? With an SLA of 300 milliseconds. Yeah, we did not exceed our P95. It was still 300 milliseconds. And we had some replicas going, obviously, because it was read-heavy. But from an application layer, we didn't have to create many horizontal skill instances. That's the power of OTP.
Sascha_Wolf:
That reminds me of this. I once was in an application process at this, like this German company, which also had like a fair level of scale. I'm not going to say any names here, but they were actually hosting all this stuff on like, not unlike on a classic cloud or Heroku offering, but they basically outsourced it to another company, which is like, Hey, this is our artifact with a Docker container, please, please run it for us and keep it back with us SLAs, right? And. This other company was usually running Ruby on Rails applications. They were, he told me that this guy, these guys were always like, oh, it's kind of laughing about the kind of scale their Elixir application was handling compared to all the other Ruby stuff they were running. So yeah.
Adi_Iyengar:
It's crazy, man. I mean, as long as they have your database and other external stuff taken care of, as long as they have proper replicas, a queue for rights, whatever, as long as they have other things external to it taken care of, it's crazy the scale of what it can handle. I think Discord said, right, like five instances, a million users, that's crazy. That's crazy. Now it's like 2018 is when they wrote that article. So yeah, it's crazy.
Sascha_Wolf:
Okay folks, any last words, any final remarks on how not to use OTP, I guess? Except for our
Allen_Wyma:
there's always
Sascha_Wolf:
kind
Allen_Wyma:
that famous
Sascha_Wolf:
of tangent.
Allen_Wyma:
famous thing where you we treat like objects like processes, etc. Right. But I think that one's been over talked about by everybody. Which I still never seen that in a while. But I always hear about this one.
Adi_Iyengar:
process oriented programming.
Allen_Wyma:
Exactly. Have you actually seen that before in the wild?
Adi_Iyengar:
I have not. I mean, I guess you can say the example that I gave is kind of that, right?
Sascha_Wolf:
Yeah, kinda. Like if you
Adi_Iyengar:
Yep.
Sascha_Wolf:
use a process dictionary, yeah, I can see it. I can see it, yeah, yeah. And I mean, Alan, if you want to do that, you can always use the OOP library, right? Like there's an OOP library for Elixir.
Allen_Wyma:
Oh yeah,
Sascha_Wolf:
I'm
Allen_Wyma:
this
Sascha_Wolf:
not even
Allen_Wyma:
is
Sascha_Wolf:
joking.
Allen_Wyma:
done by Jose, right?
Sascha_Wolf:
No, it's not by Jose, it's by...
Allen_Wyma:
I thought he did do something similar like that a long time ago when he first started working on Elixir. I think he was working because you have to understand he went from
Sascha_Wolf:
It's
Allen_Wyma:
Ruby
Sascha_Wolf:
by
Allen_Wyma:
where
Adi_Iyengar:
Yeah.
Allen_Wyma:
everything
Sascha_Wolf:
Void...
Allen_Wyma:
is an object
Sascha_Wolf:
yeah.
Allen_Wyma:
to
Sascha_Wolf:
But
Allen_Wyma:
Elixir, right?
Sascha_Wolf:
it's by VoidTechMach. So probably, probably brought up that name,
Allen_Wyma:
Oh,
Sascha_Wolf:
but...
Allen_Wyma:
that sounds familiar.
Sascha_Wolf:
So yeah, there's like this library where you can import OOP and then you can create a classes and you can do inheritance. You can do everything like that. You can do multiple inheritance because who wouldn't want to do multiple inheritance? Yeah. It's an obvious, maybe now for record is in joke library. I mean, at the very end, it basically says, please don't use this. But it's a pretty good joke if you ask me.
Adi_Iyengar:
Yeah, I mean, I think Elixir and Erlang is just like, I think the need for object-oriented gets minimized, obviously, with process and states, how easy it is to create. Yeah, I don't see myself using an object-oriented language for something, unless I'm forced to use it in a company, I don't see myself doing that with all the new languages existing. And I always, I'm sure you guys know this quote, like Joe Armstrong, right, creative Erlang, like it's like object-oriented. If it's functional programming, if you want a banana, you get a banana. But object oriented, if you want a banana, you get a monkey holding the banana and the entire jungle. Right. It's, it's,
Sascha_Wolf:
Ha ha.
Adi_Iyengar:
it's, I love that. I love that quote.
Sascha_Wolf:
What about the... also one interesting thing is like Joe Armstrong basically said that Erlang is possibly the only object-oriented
Adi_Iyengar:
Yeah,
Sascha_Wolf:
language
Adi_Iyengar:
the
Sascha_Wolf:
in
Adi_Iyengar:
true
Sascha_Wolf:
the...
Adi_Iyengar:
one. The true one, right.
Sascha_Wolf:
Yeah, if you consider what like Alan Kay kind of was thinking
Adi_Iyengar:
Right.
Sascha_Wolf:
of when he came up with Object-Oriented, then arguably Erlang is way more object-oriented than
Adi_Iyengar:
Yeah.
Sascha_Wolf:
any of the
Adi_Iyengar:
Yep.
Sascha_Wolf:
typical object-oriented languages out there.
Adi_Iyengar:
Right.
Allen_Wyma:
Um, damn, I had something I wanted to bring up. I forgot what it was now. Um, Maybe it'll come back to me after the show. I hate that.
Sascha_Wolf:
Okay, then I'm just gonna cut you off here, Alan. Brutal me. And transition us to pics. So, Adi, what are your pics for this week?
Adi_Iyengar:
Yeah, I guess since I've been unemployed, I've been playing some video games. Did I pick God of War Ragnarok? Even if I did, I finished it recently. It's a great game. It's the game of the year according to me. So. It's such an immersive experience. There's at least four or five instances where you get goosebumps because of the story. It's amazing. And it's such a great conclusion to the whole Norse mythology saga. So if you're interested there, go play God of War, Ragnarok. And second, another video game, Controversial. I fall in the category of people who actually do like the new Pokemon games. Pokemon Scarlet and Violet are awesome. If you guys are any spectrum of Pokemon fans, you should try it out. That's it for my picks.
Sascha_Wolf:
I mean, I haven't played a Pokemon game since Sapphire.
Adi_Iyengar:
That's a good game.
Sascha_Wolf:
Hahaha! But it's also really, really old now. 30 years maybe not, but kinda like that. Maybe it is 30 years.
Adi_Iyengar:
I think about,
Sascha_Wolf:
Bye!
Adi_Iyengar:
about, yeah 17, 18 years old yeah.
Sascha_Wolf:
Good gosh, I'm old. Hahaha! Alan, what are your picks? Any Rust books? Don't disappoint
Allen_Wyma:
I haven't
Sascha_Wolf:
me.
Allen_Wyma:
read a Rust book for a long time, but I
Sascha_Wolf:
Yes,
Allen_Wyma:
do have a couple
Sascha_Wolf:
it's
Allen_Wyma:
Rust
Sascha_Wolf:
why
Allen_Wyma:
courses
Sascha_Wolf:
I'm
Allen_Wyma:
I need
Sascha_Wolf:
kinda...
Allen_Wyma:
to take.
Sascha_Wolf:
I have this need and it's not fulfilled.
Allen_Wyma:
He went to Berlin. I think he did some interesting things there.
Sascha_Wolf:
Yeah, they involved leather and techno. That's what we already established.
Allen_Wyma:
They have no idea what we're talking about before the show. So I just
Adi_Iyengar:
Yep.
Allen_Wyma:
messed up with the language. So Dart is kind of like a weird language, because it's like, yeah, I don't even know how to say it. But people only use it for Flutter. But there is a really interesting web framework that came out by these guys called Very Good Ventures, called Dart Frog. The name is a little bit weird. But. What's really interesting is, I guess I can call it like a file structure, configured system, where you know, like in Rails, you have to put like files in certain places. So imagine that but basically, there's no router dot ex or dot rb. There's no like central point like of starting the application. There's just a single routes folder. And you drop a file in for every single route. And there's only one function, only one function, every single folder that just handles the requests is very weird. Uh, I don't know. Like I kind of like it, but I also kind of don't like it because it's not very explicit at all. You know, like an Elixir, like everything's a function. You can kind of follow what's going on. This one doesn't have something like that. So I just think it's very weird. Uh, and I'm kind of curious as to play with it. I've only been looking at it for like about a half hour and a half in total. I haven't installed I haven't tried it but just watch the video about it and read through documentation. I thought it's very interesting So I thought you guys should come and check it out It's it's it's pretty interesting right just how I describe it is basically what I said There's only a folder full of routes and that's it. It's very weird So that's
Sascha_Wolf:
It
Allen_Wyma:
my pick
Sascha_Wolf:
does
Allen_Wyma:
is dirt
Sascha_Wolf:
kind
Allen_Wyma:
frog
Sascha_Wolf:
of sound like the idea of serverless, but without serverless? Like, you know, if you know what I mean, like
Allen_Wyma:
Yeah,
Sascha_Wolf:
because there,
Allen_Wyma:
I
Sascha_Wolf:
there,
Allen_Wyma:
know what
Sascha_Wolf:
you
Allen_Wyma:
you
Sascha_Wolf:
also
Allen_Wyma:
mean.
Sascha_Wolf:
have like a one file with like a function which gets the request and then I don't
Allen_Wyma:
Yeah,
Sascha_Wolf:
have to consider...
Allen_Wyma:
exactly.
Sascha_Wolf:
Interesting. Let's say that.
Allen_Wyma:
Yeah, so but like imagine like, you know how you have like a folder, like blogs, right, or blog posts, and you have, you know, like slash ID, right? Well, you'd have a slide, you'd have a folder called blogs, and then a file called ID that dart, but the name ID would actually have brackets around it. So having brackets is what designates the variable name for that dynamic parameter. It's really weird.
Sascha_Wolf:
Okay.
Allen_Wyma:
Yeah, exactly. It's very
Sascha_Wolf:
You're
Allen_Wyma:
weird.
Sascha_Wolf:
into weird shit, Alan?
Allen_Wyma:
Yeah, you can say
Adi_Iyengar:
Not
Allen_Wyma:
that.
Adi_Iyengar:
as good as Techno though.
Sascha_Wolf:
I don't like tech, but to be honest.
Adi_Iyengar:
Hey guys, I have another pic. I just realized one of the places that I unfortunately could not accept an offer from, because I can only work at one place, was D.Scout. They're a research company. They conduct research using surveys and stuff. They have high volume. They have Uber as a client, for example. Great for Elixir. Great bunch of people. I posted a link here for jobs if you guys are interested.
Sascha_Wolf:
nice okay then it's my turn um i'm gonna pick what should i pick first like the the the like developer pick first the nerd pick or the self-promotion pick i'm gonna let you choose adi
Adi_Iyengar:
self-promotion.
Sascha_Wolf:
okay i'm gonna pick again because i can the ex uni library i built it's published it's out there it works uh i just pushed out a release which fixes some dialyzer issues because I knew I forgot something and that was it. So now the general type specs also work. Dialyzer is part of the CI pipeline now, so that should not happen again.
Adi_Iyengar:
I'm glad you reminded me. I have to open a PR for that 1% code coverage thing that needs to be addressed. So I'll
Sascha_Wolf:
Yet
Adi_Iyengar:
do that.
Sascha_Wolf:
happy to do that, man, because like, CoCavaroles kinda tells me, oh, sorry, I can't tell you. If I run locally, it says 100%, but if I run it in the cloud, it says 89%. I was like, what the fuck is happening?
Adi_Iyengar:
98.
Sascha_Wolf:
98%, yeah, it's so weird. But yeah, so that is out there. Please throw it out. It's just to summarize again, it's like union types for elixir in like the most elixiry way possible I could think of. So it really tries to get out of your hair. but gives you all the tools necessary to model your interrupts. I personally think it's a cool thing. You should try it out. Let me know what you think. Then I'm gonna go with a nerd pick. The nerd pick is I recently finished... No, I recently got a PS5. And I finished Returnal. And Returnal is, if you ask me, a great game. There is a lot of critique because it's basically a rogue-like, so like you die over and over and over and restart. And runs can get very long, like one, two, potentially even three hours long. So it can be very frustrating when you die. For me, it was perfect because I usually have these evening gaming slots, which are like two-ish, maybe a bit more hours. So I was like playing one run and I died and I was like, okay, done for today. Next, next day, next run. So for me that worked nicely, but if you're somebody who more binges, then I can definitely see how this might very much frustrate you. Um, so fair warning there.
Adi_Iyengar:
plus one for Eternal. Great game.
Sascha_Wolf:
I really enjoyed it. Also kind of interesting what they do for story, not spoiling anything. And, um, then I'm going to pick my, my, my businessy dev kind of career. A tip is a book or slash it's actually also web comic, the goal. And the goal is a book actually from the auto mobile industry and it's about process optimization optimization. Um, there's also a book which is more. focused with the same idea on IT, which is rolling rocks downhill. I have not read that, so that's supposedly also a good thing. Why I'm suggesting it, it's basically what kind of introduced the whole idea of theory of constraints. And theory of constraints is in its core very simple. It basically says if you have a complex system and you have value streams running through these systems, it doesn't really matter. You can optimize in a bunch of places, but as long as you don't optimize where the bottleneck of that system is, the output is not going to improve. That's the core idea. And theory of constraints is basically about figuring out where's the bottleneck. Then kind of I'm missing a word here, but putting everything under the bottleneck, making the bottleneck the number one thing to look at. and then elevating that bottleneck to improve your system and then rinse and repeat. And the goal is kind of a novel where they follow this idea and improve... I'm missing words today, good gosh. Where they improve a fictious process, but it's built, it's based on real world things. in real world stories. And it's, this whole fear of constraints thing has been like blowing my mind the more I learned about it because it's so simple and it's also at the root of a lot of what's, basically a root of what Agile is trying to do, a root of like what DevOps is trying to do. It's a very powerful thing to be honest and I'm really digging more into that at the moment. So yeah, the goal, that's my... dev slash career slash process, whatever pick. Okay. That's it for this week. Anything you would like to add, Alan, Adi, before we say goodbye? Everybody gives me a thumbs up, okay. Then thank you for listening, folks, and tune in next time when we have another episode of AlexiMix. Bye.