You might want to try this, one step ahead of Ctrl+K
Define the interface and functions and let the AI fill in the blanks.
Eg: I want XYZ class with methodFoo and methodBar which connects to APIabcd and fetch details. Define classes for response types based on API documentation at ...., use localLibraryXYZ for ABCD.
This is the way I found to work well for me. I maintain a tight grip over the architecture, even the low level architecture, and LLM writes code I can't be bothered to write.
I find tab completions very irritating. They're "almost" correct but miss some detail. I'd rather review all of that at once rather than when writing code.
(you can theoretically pass "reload": true (or similar option) in launch.json for auto reload, tho I haven't felt the need to use that in my workflows.)
I am no web developer but whenever I built the UIs, re-rendering a page by doing some big DOM change through JS as always led to stutter. So maybe its just inefficient and can't be optimised.
I fix it by micromanaging it. Which class, method, function, module - I dictate the low level structure and features. I dump my all my hard earned coding opinions in a profoundly crafted markdown file.
What helps me adjust is what I call Thanos-coding: trying to get AI to do the thing with contexts and agents and SDD and whateverthefuck, and if it gets tangled on its own shoelace say "Fine. I'll do it myself." Alternatively: making its mistakes disappear with a snap of my fingers and starting over.
UBO also let's you limit attachment size. Eg you can configure it to block anything larger than 100KB. Not sure what it does without Content-Length header though.
Never done much Spring, so I don't have a lot to compare to. But ...
I'm not a massive fan of using annotations in concept, because they obfuscate what's taking place. Unlike in (say) Python, where annotations are effectively functions wrapping the function they annotate, in java they're more akin to a customisable preprocessor. Obviously I do use them, liberally, because that's the way things are done, but I'm not a big fan. And using any modern framework relies on these a lot.
Micronaut gripes -
1. It works great until it doesn't, and you have a special case, and then you have to dig into source to figure out what on earth is going on.
2. Keeping up with latest isn't always easy, micronaut 3->4 was a huge effort.
3. For all it's called micronaut, the produced packages are pretty huge.
Serverless-specific gripes -
1. What I'm receiving isn't really an http message over a socket. It's an AWS gateway event with everything already read and packaged up. So there's no reason that (for instance) I shouldn't access the message body in a request filter, because I don't give a crap about the jetty server-loop being non-blocking.
2. Startup time is terrible. And when I managed to get a native compiled version to actually run, it got worse. A lot of this seems to be down to hibernate, but there's a big gap between startup and any logging from the framework at all. We've tried a bunch of stuff to remediate, so far with little success.
In general I think that serverless is such a different paradigm from a long-running server that approaching it from the point of view of "how can we make this the same so developers who've never thought outside of the spring-like box can still be productive?" was wrong from the outset.
> Unlike in (say) Python, where annotations are effectively functions wrapping the function they annotate, in java they're more akin to a customisable preprocessor.
I find that Python decorators can do as much magic as an annotation processor - due to the dynamism of Python. Annotation processors, in most cases, produce a new class based on annotations on existing class / interface. The injection of that class is done by the DI container (unless it's a standalone annotation processor like mapstruct).
> And using any modern framework relies on these a lot.
To be fair to language designers, it's hard to avoid code generators. And they're a compelling thing compared to building proxy objects / DI / decorator / dataclass etc.. kind of functionality in language and getting it wrong.
> ... then you have to dig into source to figure out
Agree. It's not a "boring technology" yet.
> For all it's called micronaut, the produced packages are pretty huge.
How huge? And jlink or graal vm? Just curious.
> A lot of this seems to be down to hibernate,
With micronaut atleast, I remember using Micronaut Data JDBC. Anything is better than hibernate.
> In general I think that serverless is such a different paradigm from a long-running server.
2. """You define Pydantic models for your API, then define separate ORM models for your database, then write converters between them.""" So you could've written something that let you convert between two. That would not warrant a whole new ORM.
3. """But infrastructure stuff like SQL generation, connection pooling, and row serialization is where a systems language makes sense."""
This makes no sense to me (except row serialization - maybe, but you're incurring a messagepack overhead instead). Unnecessary native dependency.
2. A converter still means maintaining two model systems. The point was to not have two in the first place.
3. MessagePack overhead is negligible compared to actual DB round-trips. And the Rust core isn't just SQL generation, it bundles the full driver stack (sqlx), pooling, and streaming, so you don't need asyncpg/aiosqlite as separate dependencies.
Define the interface and functions and let the AI fill in the blanks.
Eg: I want XYZ class with methodFoo and methodBar which connects to APIabcd and fetch details. Define classes for response types based on API documentation at ...., use localLibraryXYZ for ABCD.
This is the way I found to work well for me. I maintain a tight grip over the architecture, even the low level architecture, and LLM writes code I can't be bothered to write.
I find tab completions very irritating. They're "almost" correct but miss some detail. I'd rather review all of that at once rather than when writing code.
reply