Remix.run Logo
Defletter a day ago

Kotlin can be fairly pleasant to write but it's so incredibly unpleasant to inspect. For example, Ktor is the Kotlin backend framework, but good luck figuring out how any of it works. It's a complete mess of "higher-order functions", extension methods, and other abstraction-hell as to make it extremely difficult to figure out what is executed when and under what circumstances. Basic Kotlin code is fine, great even, but once people stop writing Kotlin as Java developers, but as Kotlin developers, then it goes downhill fast.

Tmpod a day ago | parent | next [-]

Can't speak about Ktor in particular, but most DSLs I've used are essentially just syntax sugar for the builder pattern, stream-like APIs and so on. I don't think it's bad per se, you just have to think a bit differently when you're inspecting code.

But again, could be wrong about Ktor specifically.

jackpeterfletch 19 hours ago | parent | prev | next [-]

Interesting. Coming from Spring to Ktor, being able to easily inspect the internal workings has been one of my favourite bits!

It’s ‘advanced’ kotlin in there for sure, and takes some learning of the internal plumbing, but having everything not hidden behind annotations has been great.

Just a CMD+click on whatever Ktor DSL/plugin API your using and you can immediately start to follow along / debug what it’s actually doing.

Defletter 10 hours ago | parent [-]

Oh absolutely. I admittedly haven't used Spring beyond trying it out for a couple hours and deciding never again, but I can easily imagine Ktor being an improvement over Spring. When I wrote my comment, I was more thinking about it in comparison to Netty and Java-Websockets (relevant: https://news.ycombinator.com/item?id=43800784), rather than as a web framework, though I have used it as such.

Netty is also a struggle to inspect so perhaps I just struggle with deep abstraction in general? I find code to be far better documentation than actual documentation, particularly when so much of it is along these lines:

    /**
     * Gets the next string.
     *
     * @return Returns the next string, or null.
     */
    public abstract @Nullable String getNextString();
This documentation is entirely unnecessary because everything it says is present within the method signature. But say you have an abstract method that users override to handle incoming data, often documentation will not contain things like: whether the ByteBuffer is a slice or the whole buffer at a particular offset; or whether the buffer is a copy or a view; etc. So I end up doing a lot of defensive copying which is possibly unnecessary, but because it's very difficult to figure out where that buffer is coming from without first trudging through a seemingly endless forest of abstractions first.
qcnguy a day ago | parent | prev [-]

[dead]