I'll definitely check this out, I have a microservice that I have rewritten in rocket, warp and axum that I'll port for comparison.
Rocket was nice but has stalled, I read the author has health problems to focus on, so my go-to framework is axum for now.
What I miss the most in the rust ecosystem compared to the kotlin+spring boot stuff I do at work is the dependency injection, I haven't found anything I like much in rust.
FYI Rocket has revived, and I heard recently he (Sergio) has made plans for a Rocket foundation so that the development team can be expanded and there is no longer SPOF
I respect Sergio but I’ve heard that like too many times in the last 3 years. Every few months it’s the same excitement whenever some activity is spotted on the repo. It always ends the same way - stalled yet again. The goodwill earned has been squandered.
I’ll believe in rocket when I see releases being cut. Until then I strongly recommend no one touch rocket.
So, the last time I asked on #rocket they told me the release was basically done, but they were not going to move past RC until the documentation was completed, which seems stalled.
No I actually can’t because during these hiatuses there were many PRs submitted. These weren’t merged in because the author didn’t review them.
Why does HN have this urge to write this template comment of “oh it’s free software, no complaining no matter how bad the governance is, you should pitch in even if there’s no conceivable way to do so”.
Like, did you even bother learning anything about rocket before writing this comment? Did you feel very virtuous when you wrote it?
I use rocket myself. There’s nothing huge missing, and nothing stops you from merging those PRs into your own repository (public or private) if you want them. How then is there no conceivable way to pitch in?
It's weird seeing this sentiment when Sergio is on matrix answering questions all the time and the contributor graph for alternatives like Axum is basically identical, one person making all the commits, another person doing a fair amount of work, and the rest are drive-by PR's.
Seems more like an entitled open source user issue rather than a repo issue, he's never slept on any security notifications as far as I know.
The 0.5 release was a big re-write, it takes time. I likely will still use 0.4 in future because not having to mess around with async is nicer and it's still perfectly fast enough for many usecases.
The issue is that in the past rocket author went missing and no one could take the lead to continue the development, axum in the other hand is under tokio org, so the community could take the lead in that regard.
I loved rocket when I first learned about it, now two years passed and it stalled because no one could pick up the project, there were (I don’t know it there still are) a lot of PR's from the community that were waiting for someone to review and merge it.
But if rocket is being migrating to an org, kudos to the project and hope it continues to innovate like in the past.
That's declarative. You're injecting code using the type system. You aren't directly calling any constructors with those classes -- they're added in code that you can't easily put a breakpoint in.
The result is that you're looking at a class with a dependency of "ISomething" and you can't click through to the class. You have to go back and find where the services were configured (which sometimes isn't intuitive, depending on how the original person wrote the code).
The worst is when there are entire behaviors added this way, and you just have to search your code base for keywords to figure out what's happening. It's awful.
.NET is a great ecosystem, but the ".NET way" of doing the architecture is insane and not ergonomic.
That doesn’t look ergonomic, it’s verbose AF, and the ugly use of f! is (like most crates that lean heavily into macros) going break tooling like the intellij rust plugin.
Does rust really need another web framework?
Does it need a compiles-to-rust meta language that means you cant easily see the actual rust code you’re using?
Does this feel ergonomic enough to make it worthwhile the downsides of the first two?
Metaprogramming/macros are my biggest gripe with Rust. Sure, they're cool, but they're annoying when they're thrown all over the place. Especially proc-macros. You have no idea what it's actually doing unless you hunt it down.
I suppose async web servers is the poster child of async, and drove a lot of the development. However, then _everything_ went async, adding the cognitive overhead of dealing with Rust async throughout the ecosystem, whether needed or not.
In short, it still feels like a leaky abstraction: marvelous to look at working code, but errors (both compile and run-time) expose the underlying machinery underneath the syntactical sugar.
This is probably heresy, but as a former Rust dev I'm enjoying web-services in Go more these days.
I love Rust but I kind of agree. It’s really, really rare for a web service to need the low-level stuff Rust provides. A garbage collected is going to be just fine.
I hated async for months. Refused to touch it.
Recently I tried it again. It (seems) way better now.
Just avoid weird libraries like diesel & rocket, and everything works just as expected.
I even wrote some generic code with async and surprisingly it works without me having to get a phd in type theory to please the compiler.
And if you want to make it async anyway, take a look at the abstractions a garbage collected language like Haskell can get you. (But well, the ones Go provide are probably more than enough already.)
Rust was not made for web development, and the fact that people keep creating frameworks and keep deciding they are good only shows how bad the usual practices are around the web.
There are other applications, e.g. trading, where async is a godsent (monitoring hundreds of financial instrument for changes) but any sort of GC is prohibitive.
And where you also need the fine grained control that Rust provides.
E.g. halting all async tasks immediately while keeping a single core free to execute a trade as fast a possible.
Is a thread per request scalable? Aren’t most of those threads just waiting for I/O? I guess thousands of concurrent requests via thousands of threads isn’t a big deal.
There never was any problem scaling things at the application layer. You can use almost any architecture there without issues. All the bottlenecks are elsewhere.
It's reasonably scalable. Operating system can deal with thousands of sleeping threads just fine. And I don't need more than that (on a single machine anyway).
Yes, you can run absolutely massive systems with very high throughput and high concurrency using only OS threads and "normal" synchronous programming, if done correctly. However it's generally a pain in the ass because most languages often have their own threading models that may have their own limitations or interaction-with-the-OS quirks, while in C or C++ you're typically on your own for like, all your dependencies including trivialities like thread pools and stuff. And all newer languages tend to instead design their I/O ecosystems around asynchronous stuff. So you have to choose your poison. But handling massive systems always requires a bit of special care anyway.
You will often encounter many other bottlenecks that hold your system back. There are other concerns like latency and utilization to care about. But assuming a purely "compute/IO" driven data plane, yes, you can scale synchronous APIs with threading quite far.
Ugh, Dependency Injection Framework. This will not be popular.
The blogpost itself is already shown what’s wrong with pavex. Adding so much concept and extra code just to be able to instantiate something. $1 abstraction cost for $0.05 problem.
Yeah, so many more leaky abstractions that will be hard to debug. Not even sure why? You're not saving anytime by doing it this way. Axum already has good DI that is somewhat ergonomic in rust (well, I hate how extensions aren't checked at compile time like in warp...)
I think the solution to "rust doesn't have DI like C# and Java" isn't trying to make DI like C# and Java (you won't be able without very heavy runtime cost), but make a DI that works well in rust and re-adjust yourself.
Not sure if author is the same as OP (I’m leaning towards not?), but if they are…
I’m curious what caused you to go down the route of transpiling? Do you think that this methodology will be a core facet of the architecture, and will it be able to be changed when rust gives you the tools you seemingly want? Do you think that the transpiling will be annoying to debug and update as rust continues to mature?
I disagree with other commenters here that dependency injection is not useful. I think it doesn't come across well in toy examples, but in my experience it is very useful for large services, which otherwise tend to accrue a big rats nest of instantiation in the startup code, which is difficult to modularize. I haven't built a service like that in Rust yet, so maybe other patterns work well, but I have noted these big instantiation entry points in rust code that I've read, so I'm skeptical that it is a solved problem.
I do agree that it introduces a significant legibility and debugging burden, but I think that can be significantly better with compile time DI. However, I think it does require good tools that would take quite awhile to be built for an immature framework like this.
But the thing I'm most skeptical of here is the implementation. Is there not enough information available in a normal procedural macro to figure out the dependencies, without using this trick with the rustdoc data? That approach seems very cheesy and likely fragile to me.
I'm always wary of tools that as an extra compilation step, because of the added complexity.
(Look at the common C workflow: cc was too hard to use on its own, so make was created; make was too hard to use on its own, so autoconf was created; m4; ...)
I hope the user experience makes it worth the complexity.
FYI: This framework uses rust doc-comments for essential functionality. It’s basically using the documentation tool’s JSON output programmatically during compile time.
Generally this kind of “too clever” programming tends to fail in creative ways, especially over longer periods of time.
It’s not using doc-comments, but compile-time reflection — it’s just that Rust‘s only reflection output is JSON. That doesn’t render the preposition of using a reflection API for transpiration invalid however.
As long as the output code can be verified by tests, I don’t see how this would fail in „creative ways“.
64 comments
[ 4.6 ms ] story [ 112 ms ] threadRocket was nice but has stalled, I read the author has health problems to focus on, so my go-to framework is axum for now.
What I miss the most in the rust ecosystem compared to the kotlin+spring boot stuff I do at work is the dependency injection, I haven't found anything I like much in rust.
I’m the opposite, I don’t find much need for “dependency injection” frameworks. It’s trivial to do DI without frameworks.
I’ll believe in rocket when I see releases being cut. Until then I strongly recommend no one touch rocket.
Is there anything else missing that you heard of?
Why does HN have this urge to write this template comment of “oh it’s free software, no complaining no matter how bad the governance is, you should pitch in even if there’s no conceivable way to do so”.
Like, did you even bother learning anything about rocket before writing this comment? Did you feel very virtuous when you wrote it?
Seems more like an entitled open source user issue rather than a repo issue, he's never slept on any security notifications as far as I know.
The 0.5 release was a big re-write, it takes time. I likely will still use 0.4 in future because not having to mess around with async is nicer and it's still perfectly fast enough for many usecases.
I loved rocket when I first learned about it, now two years passed and it stalled because no one could pick up the project, there were (I don’t know it there still are) a lot of PR's from the community that were waiting for someone to review and merge it.
But if rocket is being migrating to an org, kudos to the project and hope it continues to innovate like in the past.
Still looks very verbose. But then asp.net has had a decade, and this project is new.
You specifically define services and dependencies in one place in code. It goes something like this:
{ // Add framework services. }So when dependency injection happens, you know exactly which class is used, and where it was added.
The result is that you're looking at a class with a dependency of "ISomething" and you can't click through to the class. You have to go back and find where the services were configured (which sometimes isn't intuitive, depending on how the original person wrote the code).
The worst is when there are entire behaviors added this way, and you just have to search your code base for keywords to figure out what's happening. It's awful.
.NET is a great ecosystem, but the ".NET way" of doing the architecture is insane and not ergonomic.
You can. Jetbrains' Rider will happily show you the implementation (Cmd + Option + Click IIRC)
> The worst is when there are entire behaviors added this way, and you just have to search your code base for keywords to figure out what's happening.
Not in ASP.net in mu experience. But true for Spring in Java.
In ASP only the classes you declare in the constructor get injected. Only the classes registered in ConfigureServices get injected etc.
All in all ASP.net has surprisingly little magic compared to many other frameworks.
That's not to say it's without warts. There are definitely WTF cases and places where you can't properly stop a debugger.
That doesn’t look ergonomic, it’s verbose AF, and the ugly use of f! is (like most crates that lean heavily into macros) going break tooling like the intellij rust plugin.
Does rust really need another web framework?
Does it need a compiles-to-rust meta language that means you cant easily see the actual rust code you’re using?
Does this feel ergonomic enough to make it worthwhile the downsides of the first two?
Hm.
The pavex api looks way messier, but maybe it’s cuz I came to rust as an express and flask user
In short, it still feels like a leaky abstraction: marvelous to look at working code, but errors (both compile and run-time) expose the underlying machinery underneath the syntactical sugar.
This is probably heresy, but as a former Rust dev I'm enjoying web-services in Go more these days.
Rust was not made for web development, and the fact that people keep creating frameworks and keep deciding they are good only shows how bad the usual practices are around the web.
And where you also need the fine grained control that Rust provides.
E.g. halting all async tasks immediately while keeping a single core free to execute a trade as fast a possible.
There never was any problem scaling things at the application layer. You can use almost any architecture there without issues. All the bottlenecks are elsewhere.
You will often encounter many other bottlenecks that hold your system back. There are other concerns like latency and utilization to care about. But assuming a purely "compute/IO" driven data plane, yes, you can scale synchronous APIs with threading quite far.
It's just a pool of threads being used on demand.
The source of "complexity" according to the author is in using traits to make sure the middlewares are defined correctly.
The blogpost itself is already shown what’s wrong with pavex. Adding so much concept and extra code just to be able to instantiate something. $1 abstraction cost for $0.05 problem.
I think the solution to "rust doesn't have DI like C# and Java" isn't trying to make DI like C# and Java (you won't be able without very heavy runtime cost), but make a DI that works well in rust and re-adjust yourself.
I’m curious what caused you to go down the route of transpiling? Do you think that this methodology will be a core facet of the architecture, and will it be able to be changed when rust gives you the tools you seemingly want? Do you think that the transpiling will be annoying to debug and update as rust continues to mature?
Transpiling means you end up with two codebases and having to think about more abstractions.
I sincerely hate transpiling from all the work I've done in node.js / babel and other similar devilish spawns
I disagree with other commenters here that dependency injection is not useful. I think it doesn't come across well in toy examples, but in my experience it is very useful for large services, which otherwise tend to accrue a big rats nest of instantiation in the startup code, which is difficult to modularize. I haven't built a service like that in Rust yet, so maybe other patterns work well, but I have noted these big instantiation entry points in rust code that I've read, so I'm skeptical that it is a solved problem.
I do agree that it introduces a significant legibility and debugging burden, but I think that can be significantly better with compile time DI. However, I think it does require good tools that would take quite awhile to be built for an immature framework like this.
But the thing I'm most skeptical of here is the implementation. Is there not enough information available in a normal procedural macro to figure out the dependencies, without using this trick with the rustdoc data? That approach seems very cheesy and likely fragile to me.
(Look at the common C workflow: cc was too hard to use on its own, so make was created; make was too hard to use on its own, so autoconf was created; m4; ...)
I hope the user experience makes it worth the complexity.
https://zero2prod.com
Generally this kind of “too clever” programming tends to fail in creative ways, especially over longer periods of time.
As long as the output code can be verified by tests, I don’t see how this would fail in „creative ways“.