Misael Perez  retweeted
Hace mucho que no veía mi nombre en la portada de diario impreso. Dos cosas me quedan por ciertas, al papel todavía le queda algo de magia y uno nunca deja de ser periodista. Acá el link para lean la nota. 24-horas.mx/mexico/especiali…
3
10
76
1,090
Misael Perez  retweeted
The degree of rigor that I give to my professional projects vs my pet personal apps is...astounding.
2
2
42
2,137
Misael Perez  retweeted
Replying to @hubertlepicki
I guess that's one way to look at it :D On the other hand, I'd say this has been an excellent way to publicly show that we are not one bit ready to stop reading code. The specs are inconsistent, the initial one-shot of all languages were garbage, reliability is overlooked, and everyone agrees the code is below standards across the board. If someone is looking at this mess and saying "yeah, this means I can vibe in language xyz", then I don't think there is any amount of evidence that would convince them otherwise. Maybe we can stop reading code if we put effort into building solid practices and guidelines, but this "benchmark" also showed putting those in place require real work and we cannot just vibe our way through them.
7
24
244
5,788
Misael Perez  retweeted
with all the dunking on @elixirlang, a quick note from someone who bet on it. phoenix liveview is processes all the way down. that is what lets us build interactive ui without the overhead and indirection of client side state management. we ship and test interfaces insanely fast and nothing else has come close. and that is just liveview. @elixirphoenix is one of the most productive web stacks i have tried. the erlang runtime is the other half. agents can attach to it in dev and in prod and see the process tree, memory and cpu, not just symbols. it is a system you can interrogate. we have not used everything it can do because we have not needed it yet. when something does need to be fast we can drop into a nif and write that part in rust, and so far that has barely come up. we optimized for feeling productive so we could get the business off the ground. @marekfort and i say the same thing every time. best decision we made, and even better with agents.
9
29
194
14,496
Misael Perez  retweeted
Wow. They told me Goatmire was special. Now I understand. What @lawik and his team have created here is truly remarkable. A friendly, warm, welcoming gathering of like-minded people in an absolutely unique setting, with every detail crafted with love. From the mythic theme to the excellent talks to the evening in a bar listening to lightning talks, it was just perfect. So glad I could be there this year. Thank you for giving this wonderful event to the community. And, as a bowl of cherries on top of this cake: AshConf. Thank you @ZachSDaniel1, @joshprice and your team at @teamalembic for organizing a day dedicated to Ash, which I think is a critical enabler for building sustainable applications in the age of AI. I was so hoping for another Ash event, and you made it happen. Thank you! Now back home, and really grateful for the last week.
1
3
8
365
Misael Perez  retweeted
people are allergic to knowing what they are talking about.
13
8
130
8,196
Misael Perez  retweeted
Very exciting feature coming to LiveView: subscribe to a PubSub topic from any LiveView (or LiveComponent!!!) and LiveView will automatically manage the subscription for you. Simply: subscribe(socket, "user.updates", &handle_user_updates/2) PR: github.com/phoenixframework/…
14
47
435
14,332
Misael Perez  retweeted
To whom it may concern 🙃️ In abstract terms, I think of a software system (e.g. a web server, database, message queue, ...) as a collection of dynamic activities. Multiple things are happening: handling of requests, background tasks, periodical jobs, error handling, reporting, and recovery. Many of this things are completely independent, but some of them are working together. These activities have their lifecycles. We want to be able to start the activities in the proper order. We want to be able to dynamically start more activities. We want to be able to stop the activities in the reverse order. If Bar depends on Foo, we want to start Foo first, Bar second, and we want to stop them in the reverse order. Some activities will be decomposed into smaller subactivities. So if Foo internally runs Bar and Baz, we want to be able to stop the entire subtree. For example, if a user hits the cancel button, we want to be able to stop all the activities related to that task. And we want to be able to do this even if the task is stuck in some CPU processing loop. A software system has non-binary success semantics. Just because something fails, doesn't mean everything should stop working. But whatever is tightly coupled to the failing activity should stop too. However, the failing thing should not leave inconsistent mess (state, dangling resources) behind. BEAM & OTP is give us the primitives that address just that. The way I think about my systems in abstract maps very closely to the way I implement them. This vastly reduces the mental overload of thinking about the code. The conceptual view of the system maps very closely to the actual physical model (process structure). This is a power of a good abstraction. For more details, see my talk Soul of Erlang and Elixir, where I tried to explain the underlying ideas. The conceptual properties I mentioned above will have to be supported, because they are inherent to a software system. If you're building a software system without this support, these concerns will get entangled with your business logic. Whether you're doing it manually or vibe it, this work becomes more complicated. You or your agent have to deal with non-functional requirements together with the functional ones. This will make your job and the jobs of agents more difficult. Remember: code is the part of the context, perhaps its largest part. So in the age of agentic development, my position about BEAM remains the same. If you're building a software system, it is the tool that fits the problem, and it will simplify your life. You might bump into situations where some other properties will be more important (e.g. raw processing speed), but you can then implement these parts of your system in another language, say Rust, and manage them from a BEAM-powered system. As many of you know, I'm a long-time user of Erlang and Elixir. But I don't choose those languages for the syntax. For the record, I actually prefer C-style curly-braces syntax. I use those languages because of the runtime properties and guarantees, and because this technology reduces the impedance mismatch between the way I think about the system and the way I implement it. I also actually mostly prefer Erlang syntax over Elixir (minus some exceptions). The reason why I use Elixir is mostly tooling & some language features (e.g. macros). But the choice of the language was never a fanboy choice for me. If you're not building a system, BEAM langs are most likely not your hammers.
7
35
177
6,864
Misael Perez  retweeted
Replying to @bcardarella
"None of that matters" when discussing a "benchmark" that is nothing but lies. This has nothing to do with language tribalism, and everything to do with critical thinking and intellectual honesty. You chose to support and defend the opposite of that.
1
1
9
783
Misael Perez  retweeted
I’ll be speaking at WAWTECH in Warsaw next month! They gave me 5 discount codes for 50% off. First come, first served: VALIM50 See you there!
4
6
62
4,580
Misael Perez  retweeted
Last week at Goatmire I gave an extended lightning talk titled "The Emperor's New Clothes". It will be released as a four-part series, starting with this pilot episode. Special thanks to Iryna Kostiuk for recording it. Enjoy!
4
10
50
2,297
Misael Perez  retweeted
What frustrates me the most is the lack of curiosity. People saw the numbers they wanted to see and ran with the story. They didn’t ask about the process. They didn’t question the results. They didn’t explore the code. They didn’t look at the history. You could have even asked a coding agent to do an initial investigation. There has never been a better time to be curious, dig deeper, learn... but this is what we’ve got now. Oh well.
66
93
1,077
23,149
Misael Perez  retweeted
In programming, "speed" is not so simple to measure. There are a few measures you look at: Concurrency: The number of things your system can handle at once. Throughput: The actual number of requests served per second in real world conditions. Latency: How long it takes for any one request under real world conditions to complete. This includes queueing delay. Queueing Delay: How long a request has to wait at the front door before your system even starts processing it. You typically are playing a balancing act between maximizing throughput and minimizing latency on any single server, while increasing number of servers (capacity) to account for actual load. A system under load does not behave the same as a system with spare capacity. Raw speed doesn't save you under contention, because "just do the thing as fast as it can possibly be done" is just insufficient. Instead, you have to write your code in such a way that any one given thing can "yield" to other things. If you don't, the requests you're working on finish quickly, but once all of your threads/processes are fully utilized, you have no way to handle more load without introducing queueing (which eventually becomes failures/timeouts) on callers. This brings us to queueing delay. When the system is processing all of the data that it can, the callers have to all just sit there and either wait, retry or fail. If your system were able to accept more concurrent work, you can lower this queuing delay under heavy load. If you can't do that, you end up trading away too much of your goodput (requests that actually succeed within their deadline) in exchange for consistently low latency for the operations that you do handle. When building systems at scale, the general guiding light is keeping the queue delay low, and keeping goodput as high as possible. To do this, you accept as much work as the internal system can track (increasing memory usage typically), allowing latency to go up, in order to accept more concurrent traffic internally. You still need backpressure and load shedding, since no scheduler saves you from arrival rates that permanently exceed what you can serve, but within those bounds you keep goodput maximized. For this to actually work, your internal schedulers need to be able to do something called "preemption". This is where any given operation cannot take an entire CPU core for longer than some given period of time, or for some amount of operations. A "preemptive scheduler" balances work fairly across all of the operations that are asking for CPU cycles. (Work stealing, where idle cores pull queued work from busy ones, helps too, but plenty of cooperative runtimes have that. Preemption is the key part.) The BEAM is a powerhouse for this. It preempts processes by counting "reductions," so no process can hog a scheduler. Immutability and share-nothing processes make that preemption cheap and harmless: a process is never paused while holding a lock someone else needs, and every process has its own heap and garbage collector, so there are no global stop-the-world pauses. This allows BEAM applications to achieve maximal goodput, with very low failures due to queue delay, while spreading latency across all work fairly. Without that preemption, you would see a huge spread among the latency of your system. i.e some requests happening practically immediately, while other requests take pathologically large amounts of time to complete. I get that people want programming language not to matter these days, but at a very minimum you cannot escape the limitations of your runtime. The BEAM's runtime is built for operating at scale, and will always be smoked on benchmarks for tight loop operations where there is no resource contention. #ElixirLang
BEAM is not faster than Rust so something is wrong with the Rust code
7
45
274
8,266
Misael Perez  retweeted
I took a stab at improving the performance of Elixir. I used the PR for Elixir that @ZachSDaniel1 posted and worked some more on it. In the benchmark Elixir is now faster than Rust (ccece30 newest commit) for the Sidebar and Search benchmark.
Last conversion of the Campfire from my token stash goes to JavaScript/Express. As with the others, I'm sure you can find more to optimize. But this gives you a sense of what order of magnitude these options exist within with agent-led development. github.com/basecamp/once-cam…
47
46
581
106,637
Misael Perez  retweeted
Your rust implementation drops CSRF with an optimization you didn't add to the Elixir one, allowing HTML to be cached until the page contents change. You made the Elixir one use REDIS which literally no Elixir engineer in their right mind would do, and you replaced it with an in memory optimization for the rust version that is not present in the ruby *or* the Elixir one. This feels beyond disingenuous. Or just being fooled by your agents sycophancy to confirm your beliefs.
11
6
281
9,289
Misael Perez  retweeted
I have a branch with various performance improvements to the Elixir version, focused on specifically the websocket side of things. I didn't spend much time on the rest. The load generation code was flawed in overload scenarios because any socket that had an issue just stayed disconnected forever, so I assume no benchmarks were run in this fashion prior. Now those reconnect on disconnect and continue sending traffic (a more realistic scenario). Most relevant finding: In an overload situation, the rust implementation delivers a whopping 1% of messages to all connected clients, and the Elixir implementation delivers 100% of messages to all clients, applying natural backpressure to writes. Speed is cool. Rust is fast. Speed is not even close to the most important thing when building real applications.
I've had agents implement and optimize the Campfire web app in Elixir, Go, and Rust. Yes, Ruby is the slowest. I didn't care about that when the pay-off was huge in terms of productivity and developer joy. But if you're no longer reading the code? github.com/basecamp/once-cam…
Community note
The shown benchmarks use non-equivalent implementations: Elixir routes all DB queries through a single GenServer with Redis for jobs (retained from Rails), while Rust uses in-process queues, omits CSRF tags/fields, and applies other caching changes. github.com/basecamp/once-… raw.githubusercontent.com/basecamp/once-… github.com/basecamp/once-… github.com/basecamp/once-… x.com/zachsdaniel1/s…
26
64
599
34,279
Misael Perez  retweeted
Replying to @dhh
> If the agents can't write good Elixir without good steering Nah, that's not my point. Within "Rewrite this in Elixir", there are a bunch of non-Elixir decisions that will impact the results. Should you preserve session compatibility? Should you preserve Redis messages and payloads? If you didn't give the answer, it made the choice for you, and that will change the results. For example, the agent chose Redis compability and even documented so in the README. This is an architectural decision completely unrelated from its ability to write Elixir code but it will make it so Elixir now has to talk to an additional service, while Go and Rust doesn't have to. > Same as what was used for Go, Laravel, Rust, etc. If that's the case, why was Go ported from Rust but the Elixir one from Rails (according to their AGENTS.md)? Anyway, someone already wrote a pull request here: github.com/zachdaniel/once-c… - you probably want to look at the load testing benchmarks cause the Rust one seems to be dropping messages.
12
25
417
12,471
Misael Perez  retweeted
I don't feel bad, I feel angry that someone in a position with a lot of people who hang on his every word will confidently say wildly untrue shit based on entirely unvalidated vibes.
4
4
75
2,087
Misael Perez  retweeted
Come on. Your agents run all SQL queries through a single genserver, with all queries awaited via `GenServer.call`. This is a moronic Elixir implementation. I've staid fairly agnostic on the whole "rewrite everything in rust" thing but if this is the Elixir that your agents are writing, I'd hate to be a rust expert looking at their rust. github.com/basecamp/once-cam…
I've had agents implement and optimize the Campfire web app in Elixir, Go, and Rust. Yes, Ruby is the slowest. I didn't care about that when the pay-off was huge in terms of productivity and developer joy. But if you're no longer reading the code? github.com/basecamp/once-cam…
Community note
The shown benchmarks use non-equivalent implementations: Elixir routes all DB queries through a single GenServer with Redis for jobs (retained from Rails), while Rust uses in-process queues, omits CSRF tags/fields, and applies other caching changes. github.com/basecamp/once-… raw.githubusercontent.com/basecamp/once-… github.com/basecamp/once-… github.com/basecamp/once-… x.com/zachsdaniel1/s…
53
53
651
89,813
Misael Perez  retweeted
Made some massive optimizations to compile times and memory usage, and disk size of #AshFramework applications. 🎉 Benchmarks on my own large application. #ElixirLang
8
12
155
3,820