Kweb: A new approach to building rich webapps, in Kotlin
kweb.io
kweb.io
From his perspective it seems that the "division" between frontend and backend are an implementation detail that accidentally became of defining feature of how we write software for the web. Websockets are a way to correct this by making the delivery channel dumb and universal while focusing application development in a single software architecture.
It reminds me of the principle of brutalist web design (https://brutalist-web.design/). Brutalist design, while not completely beautiful, makes me ask, "What were we trying for when we first made HTML? Does the tool really fit those goals anymore?" While I hope that KWeb grows up to be something big, at a minimum it asks a lot of questions about why applications for the web are architected the way they are.
This is because Kweb doesn't entirely abstract away the client/server separation in one important sense. When you attach a callback to something you normally do it like this:
button.on.click {
header.text("They clicked!")
}
This is less efficient than it could be because it is needlessly doing a server round-trip. So for situations where you're only modifying client state you can do: button.onImmediate.click {
header.text("They clicked!")
}
When the user clicks it will be instant, as the instructions to modify the DOM are "preloaded" to the client on page render.Does that alleviate your concern? If not, can you elaborate on where you think the bottleneck is likely to emerge?
> Kweb ... virtually eliminates the separation between browser and server from the programmer’s perspective.
In my opinion, we can't say the separation has been "eliminated" if I'm constantly having to ask myself "should I handle this event on the server or the client via `onImmediate`?"
What seems more likely to happen, is that inexperienced developers simply won't ask the question at all and months later the customer will ask why their dashboard page is taking 60 seconds to load. The senior engineers will be tasked to fix it only to find out that the page is making dozens or hundreds or thousands of N+1 round trips to the server.
This has been my experience being asked to come in to fix MeteorJS apps. Teams of web developers not understanding that the client/server interface is not free and that poor engineering practices have severe compound effects.
> In my opinion, we can't say the separation has been "eliminated" if I'm constantly having to ask myself "should I handle this event on the server or the client via `onImmediate`?"
Well, I said "virtually eliminated" :)
I think it's an exaggeration to say that the programmer must constantly ask themselves this, it's only relevant when adding an event listener. You'll get along just fine if you never used onImmediate, it just means your webapp may not feel quite as snappy as it could be.
To me this seems like a very small price to pay to avoid having to bifurcate your application across client and server - particularly given that it's not even compulsory, it's an optional optimization.
> What seems more likely to happen, is that inexperienced developers simply won't ask the question at all and months later the customer will ask why their dashboard page is taking 60 seconds to load. The senior engineers will be tasked to fix it only to find out that the page is making dozens or hundreds or thousands of N+1 round trips to the server.
An unnecessary roundtrip may add 200ms of latency across a typical internet connection to the speed with which the page responds to an event, but I can't think of any circumstances under which this would delay the page render.
Moreover, a website built without onImmediate should work just fine, it just might not quite match the performance of a well-written client-side app.
> This has been my experience being asked to come in to fix MeteorJS apps. Teams of web developers not understanding that the client/server interface is not free and that poor engineering practices have severe compound effects.
There is only so much a framework can do to save programmers from themselves. In this case the risk is that the app may feel a little more sluggish than it otherwise would, a difference that users might not even notice.
It may be possible to automatically identify candidate event handlers which don't appear to be modifying server-side state and provide a nice list to the programmer, but I'd likely only invest time in this if it proved to be a significant issue in practice.
- Instant feedback, no matter how bad is your connection: here if I click on something and there is no internet, I won't see a loading icon. You probably have to hack it. - I'm not sure how it will scale and if it scales will be way more expensive than just using rest api (sockets are more expensive)
probably more problems.
I'm the creator of this game http://bitplanets.com which has a lot of shared code that runs both on the client and the server side. Some validation is done on the client (so you don't even hit the server if it fails + get instant feedback that your action is successfull or failed) and the same validation is done on the server side as well (so you can't hack it).
Examples:
- When you send a ship it will show a temporary ship immediately even if the server didn't receive yet the ship. If the client validates most likely it will be a valid ship (unless you hack it, but server side will deny your ship). Then when the server comes back saying that the ship is valid then the ship is not temporary anymore.
If you had a java backend everything would be so much more complicated. This is what I mean by having agnostic code, this validation function doesn't really care if is run on your client or on your server.
Fortunately, that's not so - Kweb has a neat way to handle it - outlined here: https://www.reddit.com/r/programming/comments/a4dtp2/kweb_a_...
(Not that you should, imho: trying to bypass the fundamental architecture of the web is typically a way to end up in debugging hell.)
ASP.NET WebForms came along and is still supported, and tried to make developing web applications similar to developing desktop applications in WinForms. I did that, it worked.. it was clunky at times (but it worked). Of course, mostly this was all server-side with just HTML/JS/CSS interacting.
A long time ago the dominant model became ASP.NET MVC which is a typical server-side MVC architecture.
Recently, Microsoft offered a new "old" paradigm through Razor Pages which are a lot like old ASP was.
If you look at things like React (or the view layer in Angular, etc.), it turns out that the web component / control model used in WebForms (server-side) is quite similar to the client side model used in React. The main difference of course being, one running client-side primarily (React) and the other server-side (WebForms). It gets even more interesting as a comparison when you talk about server-side React view rendering.
You can debug all your logic on the server.
I'd guess a/the big drawback would be no offline capability. But if you're fine with that (many are), then why not?
You are correct that, since kwebsites are server-driven, there is no significant offline capability.
But then the requirements of many websites often rule that out anyway, my strong suspicion is that this won't be a dealbreaker for many people.
Wicket suffered because it straddled the transition from pure HTML to HTML+AJAX. It could do HTML+AJAX, and their solution was elegant, but it was an afterthought and Wicket wasn't really designed around it.
Kweb was designed from the ground-up for this world and this affords it many advantages.
The reason is it depends on some stuff like coroutines - and since Scala deprecated their delimited continuations plugin way back when, I don't believe Scala has any equivalent feature.
May I ask why you ask?
https://nim-lang.org/araq/karax.html
Working example: https://forum.nim-lang.org/
Here is kerax:
var lines: seq[kstring] = @[]
proc createDom(): VNode =
result = buildHtml(tdiv):
button:
text "Say hello!"
proc onclick(ev: Event; n: VNode) =
lines.add "Hello simulated universe"
for x in lines:
tdiv:
text x
setRenderer createDom
Here is the equivalent in Kweb: fun main() {
Kweb(port = 2734) {
doc.body.new {
button().text("Say hello!").on.click {
println("Hello simulated universe")
}
}
}
}
This compiles and works. for x in lines:
tdiv:
text x
Whenever the DOM gets rerendered, it iterates over the the lines (or the "model" in general), and creates DOM elements from it. At least it looks very similar to React and Angular code, and they do exactly this.https://github.com/kwebio/core/tree/master/src/main/kotlin/i...
Also, if you use IntelliJ IDEA then the IDE will do a lot of the work for you in figuring out the API.
That’s terrible.