I was going to say that I was surprised htmx wasn't mentioned in the article. It's backend-agnostic and extremely easy to use. Drop in Alpine.js and I think you have a really powerful setup without writing any JS. I've been using this with Go[0] and enjoying it.
If someone took blazor away from me tomorrow, I'd probably consider PHP for a while. The most important part of the programming model is very similar in my experience. I could take a Razor component and convert it directly to a PHP partial pretty quickly.
> What is old is new again I suppose: we used to do this with PHP and jQuery once upon a time too — though LiveView and similar are far nicer of course.
I used to do the same with PHP + Prototype.js back in 2006-2007 before jQuery existed, including pretty weird hacks for non-AJAX supported browsers (using JS to append <script></script> from server-side to the DOM).
PHP, Django, Rails, whatever generates HTML, basically. I also slightly prefer Unpoly.com, because it takes whole pages instead of fragments. This means that if JS is disabled the site just keeps working, though with reloads.
You can achieve full support with JS disabled using HTMX as well. It takes a little more work but HTMX provides headers[0] which you can evaluate on the backend to determine if you should return a partial or not. If JS is disabled, the HTMX headers will be missing and you know it's not an HTMX request.
I think my next site is going to be php+Laravel. I had a lot of fun doing web dev in php. Nothing has matched that since. I never tried rails though. If I see another bumblefucked SPA I'm gonna cry.
So, I have only been working in htmx for about a week on a multi step checkout app, and while it's been mostly awesome, I think I ran into the Achilles heel of htmx, form state and the back button.
In short of you enter data into a form then htmx push navigate away, when you click the browser back button you get the dom as it was originally delivered from the server, without any data the user might have entered into text boxes. This is a show stopper problem and been working on work arounds, not sure any is good. Basically we have resorted to plain old full page reloads with client side redirect to resolve this.
The thing about HTMX is that the mental model about state should tend towards "the server is aware of everything". With the added benefit that you can achieve better RESTful URLs that respect the navigation actions. Without having tried this (but having used HTMX quite a lot), I would try the following (let me know if I didn't understand the problem correctly):
Checkout has the following URLs, one for each step:
1) Making sure the server knows how to render all those pages independently (like if the user does a hard-refresh or if they open that URL directly, without navigating to it through a link). Note: I believe this should be the default in any website if you respect the concept of a URL (whether client or server-side rendered).
2) If there's a form input at each step, the server needs to store that info and be aware that the user has an incomplete checkout.
Now the user is at step=2 and presses the back button, or clicks on the step=1 link. In that case, the server should know the information stored in the point no. 2 above, and return an HTML form with the data pre-filled based on the last state. E.g:
1. You need different URLs for each step.
2. Each URL should work both with HTMX (maybe using hx-push-url or the HX-Push header) and *without*. That is, any navigation to that page should also render the same HTML.
3. The server needs to be aware of the state. When a user requests page.com/checkout?step=2, the server should know if the HTML form requires pre-filled values.
This increases a bit the complexity on the server, but I believe it reduces the client-side complexity a lot more.
> 2) If there's a form input at each step, the server needs to store that info and be aware that the user has an incomplete checkout. Now the user is at step=2 and presses the back button, or clicks on the step=1 link. In that case, the server should know the information stored in the point no. 2 above, and return an HTML form with the data pre-filled based on the last state.
The problem is that when you press back button in the browser, it doesn't make another request to the server. It reloads the page from browser memory. A link back can be made to work, but that's not what I was speaking to.
I tested the most trivial case, when you return a response, and push navigate to next step, then press browser back button, form state is not retained. Both chrome and firefox do not restore the form state on navigation back after a url push navigation.
I don't think that without some client side JS that saves/reloads prior form state this is a solvable problem because of browser behavior. Either that, or perhaps use different divs for each step then have js hide/show them which is what I will try next but involves writing js to do so.
EDIT: tried multiple divs on same page, same behavior so that will not work.
It's pretty clear that htmx hasn't considered back button much at all, it also clobbers the page titles in history as well (https://github.com/bigskysoftware/htmx/issues/746), but that's a fixable problem.
What about using hx-trigger="load" for the form? Maybe that makes the browser reload it even after hitting the back button? (Sorry I can't check this right now, just a random idea).
Edit: I quickly tried it (mixing hx-from="#some-other-element" and hx-trigger="revealed", and it seems to be doing the request, but I haven't looked a lot.
Ok, so turns out default chrome/firefox on windows/android were not issuing the history refresh request on back button click. Turns out you need to add some additional config to make that happen. It's now working, and it's excellent.
Set htmx to not cache prior pages by setting `htmx.config.historyCacheSize = 0` in window.onload.
Also set the http caching header `cache-control: no-cache`
One approach you can try is using the localStoeage API to temporarily store the form data of the user. I have done something similar in the past. You can use a light library like Alpine JS to make this work nicely. When the form renders, check if there is any temporary form data in localStorage, if so initialize the form with that. When the user saves the form remember to clear localStorage. This works nicely because even if the user closes the browser or something by mistake it is all there, and you don't need to keep temporary data around in your database.
I do dearly hope Blazor works out - I would be so happy to never have to deal with the Javascript/Typescript tooling hell ever again - but I'm not holding my breath. Political shifts inside Microsoft could leave it dead and unsupported like Silverlight tomorrow...
I've seen the cycle too many times over the past decade or so. It's really bad with the various desktop UI frameworks, but it happens with most everything they put out. If something doesn't get immediate traction, and doesn't have strong champions inside of Microsoft, things all too often wither on the vine and go by the board. Big bang initial rollout coinciding with Build, showing off some fancy capabilities that never quite actually are realized in the version released to general availability.
Experience, many of us have been on the PC platform since the MS-DOS, and have seen how Microsoft politics play out, killing cool technologies because politics.
> Political shifts inside Microsoft could leave it dead and unsupported like Silverlight tomorrow...
I honestly don't see this happening. Beyond the open source arguments, blazor server-side mode is uniquely compelling specifically for organizations like Microsoft where there are thousands (tens of thousands?) of internal business systems that need some way to interact with, but don't necessarily need to serve 4k video traffic to the entire planet.
Compared to the Blazor tooling, the Typescript tooling is miles ahead imo. We did a Blazor app during a hackathon and I was pretty frustrated with how inconsistent the build errors were with blazor components.
What makes me most skeptical about Blazor though, is that it's shifting a huge burden to the client just to make developers happy. Even if the runtime is stripped down and compiled to wasm, it seems kinda wild to send a whole runtime just so you can run C# code, especially when there's alternatives like Rust that require no runtime.
What's funnier too, is that it's been possible to write F# on the frontend for a while now, compiling down to javascript (like clojurescript). It makes me wonder why this approach was never done with C# too, even if there are pitfalls in compiling to javascript.
I'm already seeing a lot of enterprise companies gearing-up to go all-in on Blazor. Having a single language (C#) for web, mobile and all other back-end services must be huge draw for them.
> What's funnier too, is that it's been possible to write F# on the frontend for a while now, compiling down to javascript (like clojurescript). It makes me wonder why this approach was never done with C# too, even if there are pitfalls in compiling to javascript.
There have been several initiatives which allowed you to do that. None of them really successful. I've worked with one specifically in the past (can't remember the project's name though), which even had C# types/bindings for Knockout.js.
There were a quite few independent efforts to bring C#/.NET to the web the proper way (JSIL, SharpKit, WootzJz) but Microsoft was never interested in them and for some reason chose the invest in the worst and most wasteful technical solution.
Even if it doesn't work out because of Microsoft politics, I think using one language for both will be the future. In my opinion, every language will have something like that.
When is the world of software going to wake up? All programming languages suck, in one way or another. All frontend/backend paradigms suck, in one way or another. This constant churn of new, new, new is a waste. It gets replaced every few years, meaning all the time, effort and money sucked into it is gone. And engineers re-learn the same lessons over, and over, and over again. All so software engineers can be happy, because they just like doing new things in newly complicated ways. It's like changing how we build houses every few years just for fun, with no benefit to the people eventually living in that home. We're definitely not saving them money or building them any faster.
I don't think this is the case at all, maaaaybe it's a tad cynical in tone, but I think overall it's a pragmatic and realistic view of software engineering, ESPECIALLY web development.
I say that as someone who is been in the industry since just before the first .com bust, and have seen a lot of this cycle.
No offense, but you have probably not been in software development for 25+ years.
I've been doing web dev for 30 yrs and it's kind of funny to see everyone inventing server side rendering, plain old html and php again. It's a spiral, not a circle and we're a bit wiser and performant this time, but much of it has been done and gone in some way or another.
> No offense, but you have probably not been in software development for 25+ years.
You're wrong about this.
You and I see things differently.
You see things as never being new and "plain old X and Y again".
I try to see things with fresh eyes, yet still with the benefit of my 25+ years in the industry. I try not to make assumptions that limit my thinking about something. Some might call it a beginner's mindset, and it has served me well.
That would be impressive, since Mosaic is only 29 years old at this point :)
I don't thinking people are reinventing server side rendering. Rediscovering it, perhaps. It has always been here, along with plain old HTML and PHP. The modern toolbox of JS-based toolboxes exists for a reason: all the things that you can't do (or can only do very clunkily) with server-side implementations. That hasn't changed.
What people wanted from a web page in 1994 is so utterly different than what many web pages are expected to do now. If it's a spiral, it's one that is spiralling out, not in, as the scope expands significantly.
After having been in this industry for 20+ years, I can pretty confidently say the world of software will never wake up. It's just been an endless cycle of adding abstractions, removing them again, using back end languages on the front end, using front end languages on the back end, using relational databases instead of a key value store, using key value stores instead of a relational database, unit tests over integration tests, integration tests over unit tests, silver bullet framework after silver bullet framework.
My feeling now is that in the greater scheme of things none of the technology choices really matter all that much, the main thing is if the software is written in a clear, documented and maintainable fashion. Unfortunately people will still throw that away and pointlessly rewrite it in a few years, so making the choice to contribute in that fashion is more a matter of professional pride than practical utility. Arguably it's better for your career to let go of that pride and just embrace the constant unnecessary rewrite process.
I do wonder if there are still some corners of software development which aren't like this. Perhaps in public universities or government?
Unfortunately in practice, there is so much ruby/rails magic going on that most Rails projects end up in terrible shape.
It's kind of a catch-22, and tons of companies have overcome it, but rails by far has the "least long term maintainable" defaults. Good for quick prototypes/small teams but bad for large and scaling teams
This was my experience with rails (to be fair, some years ago). Each new version reinvented some huge chunk of the previous version with magic all the way down. Basically why I stopped using it despite having invested lots of time.
This I think shows how "clear, documented, and maintainable" can mean different things to different people.
I specifically left Rails and Ruby because I failed to see any production Rails code actually meet any of those criteria. All of the metaprogramming, OOP, inheritance, and DSLs just made the code more confusing than it needs to be. Ruby is a cult of "the code documents itself", but code can never document itself, because good documentation includes the how and the why and some examples. Code is a horrible at describing how it exists, and no, unit tests are often not sufficient examples. And then there's the issue of Rails apps taking way too long to boot up despite their only job being to serve webpages. Debugging serious issues is a pain when the Ruby code takes minutes to actually run, and having neither clear nor documented code doesn't help. It's always abstractions upon abstractions upon abstractions.
But some people like Ruby because it's a beautiful language and Rails gives them an opinionated structure, and maybe that matters more to them.
I'll take simple functions and primitive data structures with detailed comments any day over design patterns with a bunch of classes to describe abstract ideas that inherit from one another and fail to self-describe.
I think it's a maturity thing. I've found myself going from wanting to use cool technology to build whatever to wanting to use boring technology to build cool software.
A few decades of programming has taught me that cool technology inevitably turns out to be janky and annoying and half-finished.
I agree it's a maturity thing, but I wouldn't say the cool technology 'inevitably turns out to be janky and annoying and half-finished.' I think it's more that the cool technology is developed for a certain use-case and, developers being the way we are, we pick up our new hammer and proceed to test if every object around us is a nail.
We also won't accept other people's test results. Sure, 80 other devs have said this isn't a nail, but are they SURE?
Maybe not inevitably, but the vast majority of of yesteryear's cool technology is obsolete and forgotten today. The remaining became mature "old" technology.
There was a time Java used to be cool new technology.
20+ years here too, and I agree to a large extent.
The conclusion I've come to is that we're making expensive sandcastles. I don't know when I start a project how big the sandcastle will need to get, or exactly what it will end up looking like. I also don't know when the tide is coming in. Some of them were pretty good, others were disasters, but they've all washed away now.
I do quite like building sandcastles though, so I don't worry too much about it.
I think no one is going to necessarily disagree with what you’re saying, but I’d also ask what is the point? It’s almost tautological.
Of course this is the case, so does that mean new things shouldn’t be made because it’s been pre-decided it would be a waste? I can’t say I agree with that, even though I agree with the premise that all PLs suck.
Maybe this stuff is just hard, and also maybe part of that is because as humans we’re pretty limited. So I think we just have to deal with it and try. I don’t love front end stuff, for example, and it kind of annoys me at times that everything gets reinvented over and over, to great fanfare no less. However at the end of the day, I realize it’s because we’re limited and one of those limitations is not being smart enough to do everything right the first time. That makes sense and isn’t like a knock on people, just the truth.
And these new frameworks and paradigms that keep getting made indicate to me that things are reaching some stability, but aren’t there yet. Like, a lot of native stuff has been literally miles ahead for years, which is why you don’t really see a ton of innovation in that spaces, aside from adding new frameworks to support new sensors. But you still see stuff getting made to support more privacy aware stuff, which is a shame because it could have been that way from the beginning.
Anyway, I think it’s fine for both to be true: PLs suck because tech is hard and people are limited, and we keep trying new stuff because it’s just both there yet.
(Note: wrote this on my phone so maybe it rambles and is incoherent or has mistakes)
It's better for new people joining, each cycle brings some improvement over the last typically.
It also equalizes the playing field every few years, you become an expert in the latest new thing as there isn't an old guard. Some new web framework comes along, you can invest in that and become leet, where its very difficult to start new in react today and achieve that.
This isn't to say past experience isn't valuable or helps you adopt things more quickly, can make you cynical about the new shiny and sometimes miss out on the actual improvements, even if small. I
Maybe once we lift the abstractions from the clutches of the Von Neumann architecture and reintroduce spatial and sensory mechanisms to our programming environments? Especially with server-client applications, the underlying topologies are often ad-hoc and brittle, which contributes to the complexity in sneaky ways. Jaron Lanier, a pioneer of VR, has a concept of "phenotropic programming" which is almost like OOP taken to the extreme - objects can only sense and act on each other in a virtual world akin to the real one [0].
If you want to really fall down a rabbit hole, Alan Kay has been espousing similar themes for years. He of course was the driving force behind Smalltalk, which did things in the 70s that still seem hard to do. Look at the examples built by middle schoolers in [1] - super impressive stuff! I personally believe OOP got a really bad rap by the bastardizations of C++ and Java, and a principled reframing of it may be what takes us to the next level of programming.
1. software is a VERY new discipline. its also one of the most malleable. I doubt we'll ever stop seeing churn in this space.
2. we don't reinvent the how we build houses each year. you can safely ignore all this new fangled web things if you want.
3. churn is also domain specific. we've more or less stopped inventing drastically new APIs at the OS/system level.
4. software for UIs have never been great. we are still learning how to build them. most of the major players in UI software still exist, windows, java, macosx (cocoa?), QT, GTK, Enlightment, and HTML/CSS/javascript.
finally software will continue to evolve as base layers add the ability for higher layers to do things differently. for example as CPU get more and more vector operations that can dramatically change how we write code.
this churn is a positive not a negative on the industry.
This. So much this. Futhermore - does it all really matter that much when most of us are stuck with delivery managers screaming: FEATURE, FEATURE, FEATURE in our faces, such that there is never enough time to use any toolset in an optimal way.
Initially, I thought this was going to be about WASM, based on the title.
//
The thing about rendering and processing things server-side and relying on very little, if any, JavaScript is that it makes it possible to send very small amounts of data to the client but still handle demanding tasks.
There's something to be said for making a website usable for even the most anemic of client hardware.
I don't think this is really about programming languages. The world of software (and specifically everything network based) is oscillating between fat servers and fat client every few years or so. To me the innovation seems to be orthogonal to this cycle and may actually be accelerated by this continuous change in perspective. Which is good!
if the hardware landscape settles for a while (in terms of the capabilities of devices and networks - which is not a crazy precondition given Moore's law has run its course) then it may be that these server/client pendulum oscillations get damped around an "optimum" of sorts.
An optimum defined both in terms of what it enables users to do with software but also how easy it is for developers to deliver it. Since simple is better than complex it feels that any architecture that does not require two distinct ecosystems might have an advantage (all else being equal).
for liveview, it's not at all about "fat servers"; the overhead of maintaining a socket over erlang is not that much (maybe a few K -- the base erlang process overhead is ~400 words), so you're going to almost certainly be doing better than, say ruby (via hotwire) which isn't really designed from the ground up to hold onto the websocket. By persisting the connection with a stateful system, you're going to be avoiding a whole ton of computation that just gets thrown away with stateless HTTP requests. So it's probably in the end a lighter server than most web backends.
This is the irony, Erlang/Elixir, despite being functional language with less and highly restricted access to stateful side effects, is really FANTASTIC at safely holding onto state and persisting it for the user, and making that model digestible for the developer.
I think it is catchy and saying "I tapped danced my frontend" seems to work for me and reflects the speed of development that CLOG and Common Lisp offer. https://en.wikipedia.org/wiki/Clog_dancing
Either way, I'm receptive to the "LiveView" model, but until such a time a server can deliver both HTML and server driven native UI for mobile interchangeably, I prefer the RPC approach.
I don't want to develop:
1. Both an API for mobile and LiveView for web.
OR
2. Create my own server driven UI paradigm for mobile.
I find maintaining one architectural pattern simpler. I do want to support users with the best technology fit, but I don't see why I have to make this tradeoff. The platform holders are (and always have been) jerking us around.
I want to see a LiveView that can deliver both HTML and equivalent native UI markup. This is needed to sell the vision end to end - the world is not just web.
I feel like this would enable a more sensible choice:
Offline (first)? Use RPC with sync.
Online-only? Use the LiveView paradigm and it'll work with native or web.
> until such a time a server can deliver both HTML and server driven native UI for mobile interchangeably, I prefer the RPC approach.
I really think this is such a key point and is the main blocker to this sort of architecture for cases where you need to support all the platforms.
That said there are a lot of web applications that just need some form of UI and don't need full multi-platform support and LiveView type systems involve many fewer pieces to get going with. I'm thinking more here about company internal tooling for whatever purpose, rather than web services provided to customers which are more likely to need mobile apps.
Also, let's say you've already created your backend in Elixir (e.g. using Phoenix for GraphQL or JSON), and have built your mobile app against it. To implement your web frontend, is it easier and better to roll a whole JS app from scratch or just interface with the APIs that already exist locally to produce a LiveView app? Obviously there are some app characteristics that dictate this, but for a lot of things LiveView is still going to be easier. But then, maybe I'm biased because I dislike frontend programming!
I'll also say, one of the key lifts for LiveView is specifically (unsurprisingly) live updates. That is, server pushes.
Websockets don't really make sense to use as a broad bidirectional communication tool; they're overly complicated for situations you can just open a plain TCP socket to communicate over, and making them a requirement for clients that have no need of them is a poor ask. So as soon as you're supporting a client other than a browser, while still supporting a browser, you already are going to likely want to support two APIs.
Good design will allow you to share your model for bidirectional communication regardless of the connection type, and you can then bake in any updating JS into the Websocket connection via LiveView or similar, while exposing a more normalized socket endpoint for other servers, mobile clients, etc. Even if you end up having to support multiple connection assumptions at a later point (i.e., a Websocket connection for your web client that contains JS, a Websocket connection for a web client being developed by a different team that should just return data, and a plain socket connection for non-browser based connections), the lift should be pretty small.
As always, this depends on the use case. For in-house applications it is often far simpler to keep a lightweight frontend and mobile app is often of no concern. For these kinds of web application a server-heavy architecture was always a good choice.
Of course, this is true. But I prefer architectural patterns that are flexible for future use cases, especially when there's no logical reason why it shouldn't be supported.
You can start this way, but if you have a new requirement, you might reach a technological crossroad and ask yourself "why do I have to add a new paradigm? If the thing I'm already using could just do X, I'd save a shit load of time and/or money."
You can always add, yes. But why do I have to?
The world has treated web and native as separate for far too long. We're really just squabbling over UI toolkits, so why can't we come up with something that just says "Fuck it, we're supporting both native and web as first class in every server framework because that's how it should be. And we're also going to let you use any language in the browser because that's how it should be"
Yes, but as engineers we should strive for the simplest possible approach that solves the problem in a maintainable way. Always choosing the most flexible / the most scalable / the most modern approach is often a waste of resources.
> why do I have to add a new paradigm?
The answer to that question also depends on which paradigm you are using currently, not only on which you are choosing for the future.
I hope one day we can. Though the incredibly tightly coupled server-side-logic nature of LiveView is, I think, a bad fit for the intermittent network architecture of mobile devices.
But in theory I see no reason why you couldn’t deliver LiveView to some mobile runtime that controls its native UI via some abstraction layer. Hell, some of the React Native stuff I’ve seen gets close already.
I think this is just poor phrasing on my part since mobile was top of mind. I'd like to see this work with any native UI that supports an online feature set.
I'd like to see the technology work with HTML or server driven native UI, and let developers decide which UI toolkit is best for their app market.
Since it would theoretically support both, you could incrementally transition as well.
I am currently developing sites with Django and DRF, where the client requests what format it wants and the server sends it in the format of the clients choice- a browser would request HTML, in which case the server sends HTML- using htmx. A mobile app might request JSON, or XML or CSV or any other supported format. No need to develop a separate API for web and mobile- its all the same API. DRF makes it very easy.
Now, I haven't dug into Apple iOS dev yet, I know they have some artificial limitations on what an app can receive, but thats an Apple limitation, not a technical one. I'm pretty sure Apple allows an iOS app to receive data over the Internet and render that data within the app? I just need to figure out what format it can be sent it for the app to render it.
Your app can certainly request whatever data in whatever format from whatever server it wants. Making substantial changes to the app's functionality using this channel is disallowed.
I'm happily using Phoenix+LiveView for a website that works as a PWA. This also includes offline mode with sync-when-internet-is-available functionality (thanks PouchDB!). This covers online/offline/mobile usecases, with no explicit RPC, and no requirements for the end device that the app would run on, other than a _capable_ browser.
(Admittedly, browsers on iOS are gimped, but that's part of the Apple tax).
I don’t understand. How is the app working in offline mode when the Phoenix server is not reachable, since the interactions are managed server-side with LiveView?
Sorry, my statement indeed got confusing. I'm using LiveView for online interactions. I'm using PouchDB + JS for data synchronization and enabling offline work. You are right that LiveView itself does need to be online, since it's whole point is to move (back) the UI logic to the server side.
The applications developers publish native, Swift applications, where Swift have the full access to the Webkit/Blink api the same way Javascript does and even more with the patterns from the Chromium renderer (for instance, access to lifetime events, OnDocumentLoaded, OnVisible, OnFirstPaint, etc..).
The offline first comes from the fact that every application runs first as a daemon which provide a gRPC api to the world of the services it offers, where the web-UI application process might also consume this same api from its daemon -process manager or from other applications.
Note that the daemon process who is always running give access to "push messages", so even if no UI app are running things can still work, like syncing into the DB, or even launching a new UI application given some event..
This service process also is pinged back by the web-UI process for every event, so the daemon process can also act when theres a need (when everything is loaded on the UI, do this..)
Also about the article, note that with this solution you will code in pure Swift (not WASM) just like the article is pointing out the web applications that can be built without any javascript.
Other languages like Rust, C++, Python can be added giving the Swift applications are talking to the runtime through a C api. (And i could use some help from other developers who also want this in other languages)
If you want to ship your applications with this, you will get a much better environment than Electron, using much less resources, as things are being shared to every application, and the cool part is the applications can consume one another services (for instance a Mailer application) forming a network, and depending one-another (the magic here is that they are all centrally managed by a core process that is always running)
In the other/current model you're building total 3 components: web frontend, mobile frontend and the API and in the liveview model you're again building total 3 components: LiveView for Web front/backend, and mobile frontend and API for mobile backend.
If done properly, the LiveView backend can share a lot of code with the API backend. Moreover, an added advantage is that the Web codebase and Mobile codebase can be different depending on the requirements of the two platforms, except where, as noted above, it makes sense to abstract it out and share. So, IMvHO better software engineering in general.
It's not a hard problem, but I consider it to be a dumb problem.
Let's say I have absolutely zero business purpose for an API - like zero. Neither general purpose or single purpose. I now have to make one to serve a native/mobile app. I have to pick language, I have to design API surface, pick an RPC framework, REST or GraphQL, I have to adopt a different testing strategy for it, etc.
When all I really wanted to say was: "Hey server... can you serve a slightly different template connected to all the logic I've already written that a mobile app can understand as long as the app contains a component library?"
As for the opposite model where you are API first, at least you have the language, API contract / technology, testing strategy in place. And it will work regardless of what your clients are! The clients then implement their own UI, ideally on top of some shared, headless client (maybe a native module?) and you have maximized code re-use. Only the UI tech is different (and that's a maybe, since you could use flutter or RN), and is tailored to each device nicely.
So I do think the second is VERY desirable because it's single paradigm and you can go pretty far to reduce duplication of effort, almost entirely.
There is no such possibility in the server-driven paradigm, and I'd like to see it because it would give me all the re-usability benefits of the second approach, with a huge advantage of making the clients leaner.
It's a personal thing, but I personally don't want to smash my web-app backend into the same service as a general purpose API. It requires a lot of discipline to keep the concepts separate, and it fails more often than I've seen it work. I do appreciate your comment here of "better engineering" because I so very much wish for that. I wish that the average Django/Rails/Phoenix/whatever framework would not turn into a swampy piece of junk when you keep both responsibilities in the same codebase, but they often do.
The options we have are pretty decent - I just think something like LiveView could be better. Its only promise is a (admittedly slicker) take on SSR for the web. That doesn't move the needle far enough to be revolutionary to me, and doesn't solve a problem that most people have. The problem we have is that the server paradigm is way, way behind where it should be when it comes to serving different types of clients.
Funny to see these new incarnations of the old ASP.NET UpdatePanel. I despised WebForms back in the day, but always had a soft spot for the UpdatePanel, seemed like a great idea. Especially when the alternative was manually building and managing UI on the client using ASP.NET AJAX.
Javascript on the server-side has gone from something that was advised to never be used in production. Now it is so ubiquitous that people are trying to replace it with something new and more strict and less freedom... I am fan of modern javascript, I don’t complain or mad about the fast rate of change and improvement in the language. I kept up with all the latest javascript tools and now can build full-stack applications on mobile and web with very similar codebases faster than ever.
What does that bring to the table though? You'll still need to write html, css and javascript (or some dsl).
As a hobbyist Python dev who doesn't want to deal with frontend bs more than absolutely needed, I found my perfect stack - fastapi, svelte and tailwindcss.
With a similar outlook to yours, I landed on django, htmx and tailwindcss.
I had started down the path of fastapi, svelte and tailwindcss, but when I figured out that htmx let me use server-rendered templates, getting rid of the api and the packaging toolchain felt more ergonomic.
And if you're doing server-rendered things instead of APIs, django has a few more batteries included. (But I really like fastapi for APIs.)
Modern X applications render bitmaps which get shipped over the compositor and the X server to the graphics card driver. That is not a good model for the web, because it would mean the web server has to produce rendered bitmaps, specific for the fonts, window size, and display panel led configuration over the web. The browser cannot even select text or provide a search dialog. That is almost VNC.
But originally, X applications didn't render bitmaps but submitted drawing calls. Sun used to use Postscript for that. So using that approach, it would be possible for the browser to select text, to scroll, to copy text, to search text etc. A clear improvement. But resizing the browser window would still need a complete re-transmission from the server.
But if the web server sends static html, css, and a fixed JS library, which is used to replace parts of the dom, the browser can do a lot more locally. And still the whole application logic resides on the server.
> because it would mean the web server has to produce rendered bitmaps, specific for the fonts, window size, and display panel led configuration over the web. The browser cannot even select text or provide a search dialog. That is almost VNC.
So not much different than "modern" <canvas> based apps.
The gist I was able to glean, specifically about Pheonix Liveview, is that all updates on the Frontend and Backend are pushed to the other side via websockets. For the Frontend, this means sending some json payload to the Backend. For the Backend this means either responding to a request or sending out a new update both of which involve sending out a snippet of pre-rendered HTML to replace/update an existing element that was already on page.
The benefit here is that we can get to a place that is almost a SPA without needing to do a whole lot of JavaScript for the Frontend. It also helps that Elixir is built on top of Erlang which gives it a boon to be able to handle a lot of users on one server.
There is also a bundle of clever implementation which means the templates are aware of what parts are static and what parts are dynamic. So they can send optimized changes, essentially small diffs, for the dynamic parts as they change. Often this means only sending the values for your text input field, not any of the markup for the field.
After reading the article, Clojure would probably be better suited to be mentioned than ClojureScript. The point of it all looked to be speaking to the new paradigm that Phoenix LiveView brings which is server side rendering of subsections of a page. ClojureScript, while being Clojure in a Javascript uniform, doesn't look to be used in that manor.
It's all good. Everything being said, I appreciate efforts like ClojureScript. There is just so much power in being able to use the same language and share the same models on the front and back end, but not all of us want to use JavaScript/Typescript.
I am surprised that there are no browsers that can support other languages. My ideal architecture is to have a browser where you can select your front-end language interpreter, as in a Chromium + V8 + CPython + Whatever front-end processor you might want (Brython[0] achieves this, but transpiling to JavaScript).
What doesn't make sense to me is that JavaScript has genuinely been the only language for the front-end, and it has been a monopoly for many years. Of course, there are other great languages like TypeScript, but these end up anyway transpiled to JavaScript, which to me feels like mounting your skyscraper over dunes. Not to hate on JavaScript, but JavaScript has grown too quirky for my tastes and that's why I've been away a lot from front-end development.
There are efforts to fix it, with the new ECMA standards, but I don't feel it's going anywhere unless breaking changes are introduced to modernize the language. The fact that you have to "patch" your scripts with 'strict mode' on the top of the file speaks a lot of being defensive with programming.
WASM is a solution to this, except you're not supposed to write WASM yourself. I want web development to be more straightforward, like the old days, where you didn't have to "compile" or "package" anything, and you just did your thing, and that worked.
In a period where most languages are experiencing a "rebirth" as a well thought out modern language, Dart feels like the "before" waiting for an "after".
I'd be deeply disappointed if we had progressed from Js to Dart, and it's why I'm not a fan of Flutter
Groovy was never really in the building and is just awful.
Scala is like a reimagining of the building that happened to find the old foundation useful.
Clojure is like a skybridge from the Lisp skyscraper across the way.
Kotlin is the only JVM language that's gained traction while aiming to be Java but better, the rest just happen to use the JVM, but calling them "evolutions" of Java would be deeply misleading.
It gained traction on Android thanks to Google pushing it over their creptic Java implementation, while pretending anything beyond Java 8 never happened.
It will follow the path of every other JVM guest language.
I will care when the JVM gets a single line of Kotlin commit.
Google should just buy JetBrains and rename ART into KVM.
This is being too charitable to Java imo, after all we had stuff like Retrolambda at the time.
Kotlin exists because Java moved like molasses for years
If Java had moved like C# it'd be a much nicer language today, and Kotlin wouldn't be needed.
Even comparing Kotlin 1.0 to today's Java nearly 6 years later would favor Kotlin for ergonomics with stdlib, nullability, reified generics, and syntax
Retrolambda, yet another kludge, instead of invokedynamic calls.
Kotlin exists because JetBrains wants your money, that is all.
> The next thing is also fairly straightforward: we expect Kotlin to drive the sales of IntelliJ IDEA. We’re working on a new language, but we do not plan to replace the entire ecosystem of libraries that have been built for the JVM. So you’re likely to keep using Spring and Hibernate, or other similar frameworks, in your projects built with Kotlin. And while the development tools for Kotlin itself are going to be free and open-source, the support for the enterprise development frameworks and tools will remain part of IntelliJ IDEA Ultimate, the commercial version of the IDE. And of course the framework support will be fully integrated with Kotlin.
Outside Android, I will care about Kotlin when KVM becomes an unavoidable reality, until then, it can party with Beanshell, jTCL, Jython, JRuby, Scala. Closjure, Groovy, Frege, and plenty of other ones,
To elaborate a bit more, and in my opinion, a web browser provides an essential service, much like the water from the mains or the electricity that powers your home.
Without the web browser engine, no matter which HTML, CSS and JS you write, the fact is it cannot run without it.
What would be great to have is choosing which programming language runs in your browser. It'd be great for me to move away from JS engines like V8 or SpiderMonkey, and be able to run CPython (directly, not transpiled to JS) as my interpreted language. The stack could be HTML, CSS and Python, for example. WASM came to solve part of this, fortunately.
We are missing an excellent opportunity for more powerful web technologies if we don't embrace WASM.
Agreed, no reason <script type="text/javascript"></script> couldn't be <script type="text/python"></script>.
And then all the native APIs would be exposed in a lowest common denominator kind of way.
That's actually not what the article is about. It's more about the backend server managing all or most of the application state, and sending slices of JSON or even fully-rendered HTML to the browser, which is responsible only for swapping in these new slices of UI with a thin layer of JavaScript.
In other words, it's about creating a SPA-like experience with little or no custom-written JavaScript.
It's almost like what some of us did 15 years ago, use just enough JS to load things into the DOM fetched from the backend via XMLHttpRequest, is news now. Having a Websocket open to the backend and using a front end that's aware of that instead of using HTTPS seems to be the major difference here. That difference is more about WebSockets existing now than about the choice of backend language or the server-rendered, frontend-refreshed display model.
We wrote a framework 15 years ago (almost exactly) that took rendered snippets from the servers and plugged them into the DOM; https://flexlists.com is 15 years old and uses that. It's really fast and was far easier to build with than all the manual jquery stuff. Fun times :) I should rewrite it in Liveview, seems a good fit.
The biggest difference (at least for Phoenix LiveView) is having a stateful backend represent the UI and we do away entirely with HTTP APIs/serializers/resolvers. So you get both interaction and push updates from the server at any time, without HTTP glue layers. And it actually scales. So think React's functional-reactive-templates on the server, pushing minimal diffs over the wire better than if you'd carefully written an efficient JSON API or GraphQL endpoint. Elixir is also a distributed programming language so you also get things for free like sending an update to everyone's UI across the entire cluster.
I think you're the only one to mention JSON or serialization at all. I do believe I already said websockets were the innovation, but they really literally did not exist 15 years ago for us to use. Elixir being distributed is nice. You still need the logic to get the change into everyone's session. You're just not using an external DB, cache layer, or work queue to do it.
It's amazing, really, how people feel comfortable condescending to others who explain how we did things before the current technologies existed as if we could never grasp how the new technologies improve things. Yes, this is nice, but it's evolutionary, not revolutionary.
Chris McCord, quoted in the article, explains extremely well the absurd state of stateless http requests, from a perspective that is not appreciated in the article (queued to 40m50s):
The programming model (in liveview, don't know about blazor or hotwire or livewire) really lets you get better performance by doing less. A part of me sarcastically thinks wow, damn, deleting data is irreversible data transformation and therefore increases entropy, every stateless http request is inching us closer to the heat death of the universe.
He just glosses over the "you can use a websocket API", which would solve most of the issues he's describing. There are a ton of websocket libraries that are easy to use. Do all the auth and session establishment once, and then communicate over websocket if you hate sending cookies and session data back and forth.
No, you missed the point. Liveview works because there’s a stateful Elixir process on the backend for each open ws connection. This model doesn’t work in nearly any other backend option in any other language. If he glossed over the web socket option you’re glossing over the uselessness of the ws if the backend has the memory of a goldfish.
Can anyone clarify what this quote refers to: "what really sets Erlang apart, for McCord, is its ability to preschedule processes so that the CPU doesn't get hung up on any single thread."
What's this concept called? Is it simply a matter of setting a priority level on a certain task, that way the scheduler can make sure it doesn't block?
Preemptive scheduling, as opposed to cooperative scheduling.
Basically: the scheduler can interrupt an erlang thread at any time, instead of a depending on threads to cooperate with the scheduler to see if they should stop. In go, for example, goroutines will only check with the scheduler at function calls, selects, and a few other things like that.
I believe the BEAM only interrupts after "reduction" limit is reached, and is after function calls end. The big difference is that everything is a function call, so there's frequent opportunity to be interrupted. There's no functionless for-loop iteration, for example. I think having that would be a big sticking point for scheduling
There's a really neat demo of a machine at 100 CPU% but that's still responsive because of Erlang's preemptive scheduling. There's a ton of other goodies in that video if you're interested.
327 comments
[ 8.6 ms ] story [ 270 ms ] threadThe race between web C#/python and local javascript could make becoming a "full stack" dev easier at least.
Tiny amount of glue HTML attributes, a heap of partials that are your PHP files and you’re good to go.
What is old is new again I suppose: we used to do this with PHP and jQuery once upon a time too — though LiveView and similar are far nicer of course.
I’ve been working on some personal tools with nothing more than Deno and htmx. Works quite well for my needs!
[0] https://htmx.org/
[0] https://github.com/mikestefanello/pagoda
I use it with lisp-like languages (Clojure, Janet). Those have html libraries that transform datastructures into html.
So it doesn't feel like I'm writing html, while I'm pretending not to use JavaScript. It's glorious.
I used to do the same with PHP + Prototype.js back in 2006-2007 before jQuery existed, including pretty weird hacks for non-AJAX supported browsers (using JS to append <script></script> from server-side to the DOM).
Surely what is old is new again...
[0] https://htmx.org/reference/#request_headers
In short of you enter data into a form then htmx push navigate away, when you click the browser back button you get the dom as it was originally delivered from the server, without any data the user might have entered into text boxes. This is a show stopper problem and been working on work arounds, not sure any is good. Basically we have resorted to plain old full page reloads with client side redirect to resolve this.
Checkout has the following URLs, one for each step:
Now you need 2 things:1) Making sure the server knows how to render all those pages independently (like if the user does a hard-refresh or if they open that URL directly, without navigating to it through a link). Note: I believe this should be the default in any website if you respect the concept of a URL (whether client or server-side rendered).
2) If there's a form input at each step, the server needs to store that info and be aware that the user has an incomplete checkout.
Now the user is at step=2 and presses the back button, or clicks on the step=1 link. In that case, the server should know the information stored in the point no. 2 above, and return an HTML form with the data pre-filled based on the last state. E.g:
I think there are 3 main keys:1. You need different URLs for each step. 2. Each URL should work both with HTMX (maybe using hx-push-url or the HX-Push header) and *without*. That is, any navigation to that page should also render the same HTML. 3. The server needs to be aware of the state. When a user requests page.com/checkout?step=2, the server should know if the HTML form requires pre-filled values.
This increases a bit the complexity on the server, but I believe it reduces the client-side complexity a lot more.
The problem is that when you press back button in the browser, it doesn't make another request to the server. It reloads the page from browser memory. A link back can be made to work, but that's not what I was speaking to.
I tested the most trivial case, when you return a response, and push navigate to next step, then press browser back button, form state is not retained. Both chrome and firefox do not restore the form state on navigation back after a url push navigation.
I don't think that without some client side JS that saves/reloads prior form state this is a solvable problem because of browser behavior. Either that, or perhaps use different divs for each step then have js hide/show them which is what I will try next but involves writing js to do so.
EDIT: tried multiple divs on same page, same behavior so that will not work.
It's pretty clear that htmx hasn't considered back button much at all, it also clobbers the page titles in history as well (https://github.com/bigskysoftware/htmx/issues/746), but that's a fixable problem.
What about using hx-trigger="load" for the form? Maybe that makes the browser reload it even after hitting the back button? (Sorry I can't check this right now, just a random idea).
Edit: I quickly tried it (mixing hx-from="#some-other-element" and hx-trigger="revealed", and it seems to be doing the request, but I haven't looked a lot.
Set htmx to not cache prior pages by setting `htmx.config.historyCacheSize = 0` in window.onload.
Also set the http caching header `cache-control: no-cache`
Assumption or knowledge?
How do you know this?
Hence the famous xckd comic.
I honestly don't see this happening. Beyond the open source arguments, blazor server-side mode is uniquely compelling specifically for organizations like Microsoft where there are thousands (tens of thousands?) of internal business systems that need some way to interact with, but don't necessarily need to serve 4k video traffic to the entire planet.
What makes me most skeptical about Blazor though, is that it's shifting a huge burden to the client just to make developers happy. Even if the runtime is stripped down and compiled to wasm, it seems kinda wild to send a whole runtime just so you can run C# code, especially when there's alternatives like Rust that require no runtime.
What's funnier too, is that it's been possible to write F# on the frontend for a while now, compiling down to javascript (like clojurescript). It makes me wonder why this approach was never done with C# too, even if there are pitfalls in compiling to javascript.
> What's funnier too, is that it's been possible to write F# on the frontend for a while now, compiling down to javascript (like clojurescript). It makes me wonder why this approach was never done with C# too, even if there are pitfalls in compiling to javascript.
There have been several initiatives which allowed you to do that. None of them really successful. I've worked with one specifically in the past (can't remember the project's name though), which even had C# types/bindings for Knockout.js.
FWIW, you seem to be talking about Blazor-WASM, but most real-life Blazor usage right now is server-side Blazor which doesn't do any of that.
I say that as someone who is been in the industry since just before the first .com bust, and have seen a lot of this cycle.
I've been doing web dev for 30 yrs and it's kind of funny to see everyone inventing server side rendering, plain old html and php again. It's a spiral, not a circle and we're a bit wiser and performant this time, but much of it has been done and gone in some way or another.
You're wrong about this.
You and I see things differently.
You see things as never being new and "plain old X and Y again".
I try to see things with fresh eyes, yet still with the benefit of my 25+ years in the industry. I try not to make assumptions that limit my thinking about something. Some might call it a beginner's mindset, and it has served me well.
That would be impressive, since Mosaic is only 29 years old at this point :)
I don't thinking people are reinventing server side rendering. Rediscovering it, perhaps. It has always been here, along with plain old HTML and PHP. The modern toolbox of JS-based toolboxes exists for a reason: all the things that you can't do (or can only do very clunkily) with server-side implementations. That hasn't changed.
What people wanted from a web page in 1994 is so utterly different than what many web pages are expected to do now. If it's a spiral, it's one that is spiralling out, not in, as the scope expands significantly.
My feeling now is that in the greater scheme of things none of the technology choices really matter all that much, the main thing is if the software is written in a clear, documented and maintainable fashion. Unfortunately people will still throw that away and pointlessly rewrite it in a few years, so making the choice to contribute in that fashion is more a matter of professional pride than practical utility. Arguably it's better for your career to let go of that pride and just embrace the constant unnecessary rewrite process.
I do wonder if there are still some corners of software development which aren't like this. Perhaps in public universities or government?
Since it was "optimized for developer happiness" (https://news.learnenough.com/ruby-optimized-for-programmer-h...) it's more likely to be easier to understand, document and maintain.
It's kind of a catch-22, and tons of companies have overcome it, but rails by far has the "least long term maintainable" defaults. Good for quick prototypes/small teams but bad for large and scaling teams
Should check out Java Spring (and for a bonus round, Lombak). So much magic pixie dust spewed around to get around not being able to monkey patch.
I specifically left Rails and Ruby because I failed to see any production Rails code actually meet any of those criteria. All of the metaprogramming, OOP, inheritance, and DSLs just made the code more confusing than it needs to be. Ruby is a cult of "the code documents itself", but code can never document itself, because good documentation includes the how and the why and some examples. Code is a horrible at describing how it exists, and no, unit tests are often not sufficient examples. And then there's the issue of Rails apps taking way too long to boot up despite their only job being to serve webpages. Debugging serious issues is a pain when the Ruby code takes minutes to actually run, and having neither clear nor documented code doesn't help. It's always abstractions upon abstractions upon abstractions.
But some people like Ruby because it's a beautiful language and Rails gives them an opinionated structure, and maybe that matters more to them.
I'll take simple functions and primitive data structures with detailed comments any day over design patterns with a bunch of classes to describe abstract ideas that inherit from one another and fail to self-describe.
Try aerospace, defense, critical infrastructure. They tend to move much slower and methodically about their stacks.
A few decades of programming has taught me that cool technology inevitably turns out to be janky and annoying and half-finished.
We also won't accept other people's test results. Sure, 80 other devs have said this isn't a nail, but are they SURE?
It's not the technology's fault.
There was a time Java used to be cool new technology.
The conclusion I've come to is that we're making expensive sandcastles. I don't know when I start a project how big the sandcastle will need to get, or exactly what it will end up looking like. I also don't know when the tide is coming in. Some of them were pretty good, others were disasters, but they've all washed away now.
I do quite like building sandcastles though, so I don't worry too much about it.
I think the fashion industry is a consequence that a big subset of the industry lives from selling services, books, trainings, conference talks,....
So the need for something new needs to be constantly generated so that the crowds feel the need for new content and buying services.
Then on top of that, most people new to the industry tend not to learn the past, so they keep re-discovering stuff as the "new coolness".
Of course this is the case, so does that mean new things shouldn’t be made because it’s been pre-decided it would be a waste? I can’t say I agree with that, even though I agree with the premise that all PLs suck.
Maybe this stuff is just hard, and also maybe part of that is because as humans we’re pretty limited. So I think we just have to deal with it and try. I don’t love front end stuff, for example, and it kind of annoys me at times that everything gets reinvented over and over, to great fanfare no less. However at the end of the day, I realize it’s because we’re limited and one of those limitations is not being smart enough to do everything right the first time. That makes sense and isn’t like a knock on people, just the truth.
And these new frameworks and paradigms that keep getting made indicate to me that things are reaching some stability, but aren’t there yet. Like, a lot of native stuff has been literally miles ahead for years, which is why you don’t really see a ton of innovation in that spaces, aside from adding new frameworks to support new sensors. But you still see stuff getting made to support more privacy aware stuff, which is a shame because it could have been that way from the beginning.
Anyway, I think it’s fine for both to be true: PLs suck because tech is hard and people are limited, and we keep trying new stuff because it’s just both there yet.
(Note: wrote this on my phone so maybe it rambles and is incoherent or has mistakes)
https://remix.run is a prime example. It's new, and better, and simpler.
It also equalizes the playing field every few years, you become an expert in the latest new thing as there isn't an old guard. Some new web framework comes along, you can invest in that and become leet, where its very difficult to start new in react today and achieve that.
This isn't to say past experience isn't valuable or helps you adopt things more quickly, can make you cynical about the new shiny and sometimes miss out on the actual improvements, even if small. I
If you want to really fall down a rabbit hole, Alan Kay has been espousing similar themes for years. He of course was the driving force behind Smalltalk, which did things in the 70s that still seem hard to do. Look at the examples built by middle schoolers in [1] - super impressive stuff! I personally believe OOP got a really bad rap by the bastardizations of C++ and Java, and a principled reframing of it may be what takes us to the next level of programming.
[0] https://www.edge.org/conversation/jaron_lanier-why-gordian-s...
[1] https://www.dgsiegel.net/files/refs/Kay,%20Goldberg%20-%20Pe...
1. software is a VERY new discipline. its also one of the most malleable. I doubt we'll ever stop seeing churn in this space.
2. we don't reinvent the how we build houses each year. you can safely ignore all this new fangled web things if you want.
3. churn is also domain specific. we've more or less stopped inventing drastically new APIs at the OS/system level.
4. software for UIs have never been great. we are still learning how to build them. most of the major players in UI software still exist, windows, java, macosx (cocoa?), QT, GTK, Enlightment, and HTML/CSS/javascript.
finally software will continue to evolve as base layers add the ability for higher layers to do things differently. for example as CPU get more and more vector operations that can dramatically change how we write code.
this churn is a positive not a negative on the industry.
//
The thing about rendering and processing things server-side and relying on very little, if any, JavaScript is that it makes it possible to send very small amounts of data to the client but still handle demanding tasks.
There's something to be said for making a website usable for even the most anemic of client hardware.
An optimum defined both in terms of what it enables users to do with software but also how easy it is for developers to deliver it. Since simple is better than complex it feels that any architecture that does not require two distinct ecosystems might have an advantage (all else being equal).
This is the irony, Erlang/Elixir, despite being functional language with less and highly restricted access to stateful side effects, is really FANTASTIC at safely holding onto state and persisting it for the user, and making that model digestible for the developer.
https://www.reddit.com/r/lisp/comments/s1itqi/the_common_lis...
https://www.reddit.com/r/lisp/comments/sd9wf1/clog_builder_c...
"I CLOGed my frontend"
"I Reacted my frontend"?
"I AngularJSed my frontend"?
"I VueJSed my frontend"?
I just don't see it.
Its a nice language all around on backend (and i suppose mobile, but i wouldnt know) thats a pleasure to code in
Either way, I'm receptive to the "LiveView" model, but until such a time a server can deliver both HTML and server driven native UI for mobile interchangeably, I prefer the RPC approach.
I don't want to develop:
1. Both an API for mobile and LiveView for web.
OR
2. Create my own server driven UI paradigm for mobile.
I find maintaining one architectural pattern simpler. I do want to support users with the best technology fit, but I don't see why I have to make this tradeoff. The platform holders are (and always have been) jerking us around.
I want to see a LiveView that can deliver both HTML and equivalent native UI markup. This is needed to sell the vision end to end - the world is not just web.
I feel like this would enable a more sensible choice:
Offline (first)? Use RPC with sync.
Online-only? Use the LiveView paradigm and it'll work with native or web.
I really think this is such a key point and is the main blocker to this sort of architecture for cases where you need to support all the platforms.
That said there are a lot of web applications that just need some form of UI and don't need full multi-platform support and LiveView type systems involve many fewer pieces to get going with. I'm thinking more here about company internal tooling for whatever purpose, rather than web services provided to customers which are more likely to need mobile apps.
Also, let's say you've already created your backend in Elixir (e.g. using Phoenix for GraphQL or JSON), and have built your mobile app against it. To implement your web frontend, is it easier and better to roll a whole JS app from scratch or just interface with the APIs that already exist locally to produce a LiveView app? Obviously there are some app characteristics that dictate this, but for a lot of things LiveView is still going to be easier. But then, maybe I'm biased because I dislike frontend programming!
Websockets don't really make sense to use as a broad bidirectional communication tool; they're overly complicated for situations you can just open a plain TCP socket to communicate over, and making them a requirement for clients that have no need of them is a poor ask. So as soon as you're supporting a client other than a browser, while still supporting a browser, you already are going to likely want to support two APIs.
Good design will allow you to share your model for bidirectional communication regardless of the connection type, and you can then bake in any updating JS into the Websocket connection via LiveView or similar, while exposing a more normalized socket endpoint for other servers, mobile clients, etc. Even if you end up having to support multiple connection assumptions at a later point (i.e., a Websocket connection for your web client that contains JS, a Websocket connection for a web client being developed by a different team that should just return data, and a plain socket connection for non-browser based connections), the lift should be pretty small.
You can start this way, but if you have a new requirement, you might reach a technological crossroad and ask yourself "why do I have to add a new paradigm? If the thing I'm already using could just do X, I'd save a shit load of time and/or money."
You can always add, yes. But why do I have to?
The world has treated web and native as separate for far too long. We're really just squabbling over UI toolkits, so why can't we come up with something that just says "Fuck it, we're supporting both native and web as first class in every server framework because that's how it should be. And we're also going to let you use any language in the browser because that's how it should be"
> why do I have to add a new paradigm? The answer to that question also depends on which paradigm you are using currently, not only on which you are choosing for the future.
But in theory I see no reason why you couldn’t deliver LiveView to some mobile runtime that controls its native UI via some abstraction layer. Hell, some of the React Native stuff I’ve seen gets close already.
I'd like to see the technology work with HTML or server driven native UI, and let developers decide which UI toolkit is best for their app market.
Since it would theoretically support both, you could incrementally transition as well.
Now, I haven't dug into Apple iOS dev yet, I know they have some artificial limitations on what an app can receive, but thats an Apple limitation, not a technical one. I'm pretty sure Apple allows an iOS app to receive data over the Internet and render that data within the app? I just need to figure out what format it can be sent it for the app to render it.
(Admittedly, browsers on iOS are gimped, but that's part of the Apple tax).
I have a working solution for something like this that is based on Chrome
https://github.com/mumba-org/mumba
The applications developers publish native, Swift applications, where Swift have the full access to the Webkit/Blink api the same way Javascript does and even more with the patterns from the Chromium renderer (for instance, access to lifetime events, OnDocumentLoaded, OnVisible, OnFirstPaint, etc..).
The offline first comes from the fact that every application runs first as a daemon which provide a gRPC api to the world of the services it offers, where the web-UI application process might also consume this same api from its daemon -process manager or from other applications.
Note that the daemon process who is always running give access to "push messages", so even if no UI app are running things can still work, like syncing into the DB, or even launching a new UI application given some event.. This service process also is pinged back by the web-UI process for every event, so the daemon process can also act when theres a need (when everything is loaded on the UI, do this..)
Also about the article, note that with this solution you will code in pure Swift (not WASM) just like the article is pointing out the web applications that can be built without any javascript.
Other languages like Rust, C++, Python can be added giving the Swift applications are talking to the runtime through a C api. (And i could use some help from other developers who also want this in other languages)
If you want to ship your applications with this, you will get a much better environment than Electron, using much less resources, as things are being shared to every application, and the cool part is the applications can consume one another services (for instance a Mailer application) forming a network, and depending one-another (the magic here is that they are all centrally managed by a core process that is always running)
Is that really that hard a problem?
In the other/current model you're building total 3 components: web frontend, mobile frontend and the API and in the liveview model you're again building total 3 components: LiveView for Web front/backend, and mobile frontend and API for mobile backend.
If done properly, the LiveView backend can share a lot of code with the API backend. Moreover, an added advantage is that the Web codebase and Mobile codebase can be different depending on the requirements of the two platforms, except where, as noted above, it makes sense to abstract it out and share. So, IMvHO better software engineering in general.
Let's say I have absolutely zero business purpose for an API - like zero. Neither general purpose or single purpose. I now have to make one to serve a native/mobile app. I have to pick language, I have to design API surface, pick an RPC framework, REST or GraphQL, I have to adopt a different testing strategy for it, etc.
When all I really wanted to say was: "Hey server... can you serve a slightly different template connected to all the logic I've already written that a mobile app can understand as long as the app contains a component library?"
As for the opposite model where you are API first, at least you have the language, API contract / technology, testing strategy in place. And it will work regardless of what your clients are! The clients then implement their own UI, ideally on top of some shared, headless client (maybe a native module?) and you have maximized code re-use. Only the UI tech is different (and that's a maybe, since you could use flutter or RN), and is tailored to each device nicely.
So I do think the second is VERY desirable because it's single paradigm and you can go pretty far to reduce duplication of effort, almost entirely.
There is no such possibility in the server-driven paradigm, and I'd like to see it because it would give me all the re-usability benefits of the second approach, with a huge advantage of making the clients leaner.
It's a personal thing, but I personally don't want to smash my web-app backend into the same service as a general purpose API. It requires a lot of discipline to keep the concepts separate, and it fails more often than I've seen it work. I do appreciate your comment here of "better engineering" because I so very much wish for that. I wish that the average Django/Rails/Phoenix/whatever framework would not turn into a swampy piece of junk when you keep both responsibilities in the same codebase, but they often do.
The options we have are pretty decent - I just think something like LiveView could be better. Its only promise is a (admittedly slicker) take on SSR for the web. That doesn't move the needle far enough to be revolutionary to me, and doesn't solve a problem that most people have. The problem we have is that the server paradigm is way, way behind where it should be when it comes to serving different types of clients.
Have used it in production and it works great. Author is also very responsive to bugfixes / feature requests.
As a hobbyist Python dev who doesn't want to deal with frontend bs more than absolutely needed, I found my perfect stack - fastapi, svelte and tailwindcss.
Less need for an API-layer and related contracts.
You can still use Tailwind CSS. Works quite nicely.
I had started down the path of fastapi, svelte and tailwindcss, but when I figured out that htmx let me use server-rendered templates, getting rid of the api and the packaging toolchain felt more ergonomic.
And if you're doing server-rendered things instead of APIs, django has a few more batteries included. (But I really like fastapi for APIs.)
- 2x developers
- 2x CI/CD stacks
- 2x build tools
- 2x model classes
- 2x instrumentation code
I could keep going but it's a pretty significant improvement especially for small teams or solo developers.
(Pun semi-intended)
Modern X applications render bitmaps which get shipped over the compositor and the X server to the graphics card driver. That is not a good model for the web, because it would mean the web server has to produce rendered bitmaps, specific for the fonts, window size, and display panel led configuration over the web. The browser cannot even select text or provide a search dialog. That is almost VNC.
But originally, X applications didn't render bitmaps but submitted drawing calls. Sun used to use Postscript for that. So using that approach, it would be possible for the browser to select text, to scroll, to copy text, to search text etc. A clear improvement. But resizing the browser window would still need a complete re-transmission from the server.
But if the web server sends static html, css, and a fixed JS library, which is used to replace parts of the dom, the browser can do a lot more locally. And still the whole application logic resides on the server.
So not much different than "modern" <canvas> based apps.
The benefit here is that we can get to a place that is almost a SPA without needing to do a whole lot of JavaScript for the Frontend. It also helps that Elixir is built on top of Erlang which gives it a boon to be able to handle a lot of users on one server.
Designed to support multiple back-ends and front-ends. The first back-end will be Nim and the first front-end will be Flutter.
I am surprised that there are no browsers that can support other languages. My ideal architecture is to have a browser where you can select your front-end language interpreter, as in a Chromium + V8 + CPython + Whatever front-end processor you might want (Brython[0] achieves this, but transpiling to JavaScript).
What doesn't make sense to me is that JavaScript has genuinely been the only language for the front-end, and it has been a monopoly for many years. Of course, there are other great languages like TypeScript, but these end up anyway transpiled to JavaScript, which to me feels like mounting your skyscraper over dunes. Not to hate on JavaScript, but JavaScript has grown too quirky for my tastes and that's why I've been away a lot from front-end development.
There are efforts to fix it, with the new ECMA standards, but I don't feel it's going anywhere unless breaking changes are introduced to modernize the language. The fact that you have to "patch" your scripts with 'strict mode' on the top of the file speaks a lot of being defensive with programming.
WASM is a solution to this, except you're not supposed to write WASM yourself. I want web development to be more straightforward, like the old days, where you didn't have to "compile" or "package" anything, and you just did your thing, and that worked.
--
[0]: https://brython.info/
In a period where most languages are experiencing a "rebirth" as a well thought out modern language, Dart feels like the "before" waiting for an "after".
I'd be deeply disappointed if we had progressed from Js to Dart, and it's why I'm not a fan of Flutter
(Java => Kotlin, Obj C => Swift, Js => Ts, Erlang => Elixr, etc.)
If you are speaking of Android, yes.
On the JVM is it just one more guest on the building.
https://madnight.github.io/githut/#/pull_requests/2021/4
Groovy was never really in the building and is just awful.
Scala is like a reimagining of the building that happened to find the old foundation useful.
Clojure is like a skybridge from the Lisp skyscraper across the way.
Kotlin is the only JVM language that's gained traction while aiming to be Java but better, the rest just happen to use the JVM, but calling them "evolutions" of Java would be deeply misleading.
It will follow the path of every other JVM guest language.
I will care when the JVM gets a single line of Kotlin commit.
Google should just buy JetBrains and rename ART into KVM.
Kotlin exists because Java moved like molasses for years
If Java had moved like C# it'd be a much nicer language today, and Kotlin wouldn't be needed.
Even comparing Kotlin 1.0 to today's Java nearly 6 years later would favor Kotlin for ergonomics with stdlib, nullability, reified generics, and syntax
Kotlin exists because JetBrains wants your money, that is all.
> The next thing is also fairly straightforward: we expect Kotlin to drive the sales of IntelliJ IDEA. We’re working on a new language, but we do not plan to replace the entire ecosystem of libraries that have been built for the JVM. So you’re likely to keep using Spring and Hibernate, or other similar frameworks, in your projects built with Kotlin. And while the development tools for Kotlin itself are going to be free and open-source, the support for the enterprise development frameworks and tools will remain part of IntelliJ IDEA Ultimate, the commercial version of the IDE. And of course the framework support will be fully integrated with Kotlin.
https://blog.jetbrains.com/kotlin/2011/08/why-jetbrains-need...
Outside Android, I will care about Kotlin when KVM becomes an unavoidable reality, until then, it can party with Beanshell, jTCL, Jython, JRuby, Scala. Closjure, Groovy, Frege, and plenty of other ones,
https://en.m.wikipedia.org/wiki/List_of_JVM_languages
Without the web browser engine, no matter which HTML, CSS and JS you write, the fact is it cannot run without it.
What would be great to have is choosing which programming language runs in your browser. It'd be great for me to move away from JS engines like V8 or SpiderMonkey, and be able to run CPython (directly, not transpiled to JS) as my interpreted language. The stack could be HTML, CSS and Python, for example. WASM came to solve part of this, fortunately.
We are missing an excellent opportunity for more powerful web technologies if we don't embrace WASM.
In other words, it's about creating a SPA-like experience with little or no custom-written JavaScript.
It's amazing, really, how people feel comfortable condescending to others who explain how we did things before the current technologies existed as if we could never grasp how the new technologies improve things. Yes, this is nice, but it's evolutionary, not revolutionary.
https://www.youtube.com/watch?v=XhNv1ikZNLs&list=PLqj39LCvnO...
The programming model (in liveview, don't know about blazor or hotwire or livewire) really lets you get better performance by doing less. A part of me sarcastically thinks wow, damn, deleting data is irreversible data transformation and therefore increases entropy, every stateless http request is inching us closer to the heat death of the universe.
What's this concept called? Is it simply a matter of setting a priority level on a certain task, that way the scheduler can make sure it doesn't block?
Basically: the scheduler can interrupt an erlang thread at any time, instead of a depending on threads to cooperate with the scheduler to see if they should stop. In go, for example, goroutines will only check with the scheduler at function calls, selects, and a few other things like that.
There's a really neat demo of a machine at 100 CPU% but that's still responsive because of Erlang's preemptive scheduling. There's a ton of other goodies in that video if you're interested.
It really shows off the Erlang BEAM VM.