Scala 2 is a dying language, and Scala 3 is an immature one. The ecosystem and community are also very messy, with fragmentation and witch hunts running rampant. OCaml provides same advantages, but without all the drama.
> I wonder if this will wind up being a category of problems and the solution is a separate "system" set of effects (effectively `({user}, {system})`) or if this one-off extension is all that will be needed.
It already is, kinda. In my practice very often you have global singleton values that are either defined as static variables, or passed as arguments to nearly all functions in a module. Since implicit presence of `Debug` effect is already a compilation parameter, it could be generalized to support any sets of implicit effects. Thus you might design a module that has implicit Logger and Database effects in all its functions.
> Thus you might design a module that has implicit Logger and Database effects in all its functions.
Logging does seem like a very similar case to debugging, only that you expect to leave it on in production. On the other hand an implicit Database effect kind of defeat the point of an effect system.
I think the key is that Debug and Logger effects don't really affect the rest of the code - if you remove all debug/log statements, the only thing that changes is the debug/log output (and slightly faster execution probably).
> Logging does seem like a very similar case to debugging, only that you expect to leave it on in production
In a lot of logging systems, debug is one of the common levels of logging. I'm not even convinced that the term "debug" is unambiguous to clearly refer to something that's not a subset logging. Presumably the difference is intended to mean things printed that are unconditionally going to stdout rather than into some system that might change the output location and filter/annotate things, but I have to imagine that it might just make more sense not to have separate models for them at all
I was referring to the specific Debug effect described in the post, which only works in debugging builds. This means that the production build cannot have unexpected output from a function with no declared effect.
I understand. My point was that if you did want to extend further to have an effect for logging, it seems like having fully separate abstractions for them rather than finding a way to express them both as part of the same abstraction would make sense.
> Real life software is much more than just downloading a game and running it.
Real life software outside of Linux is pretty much just downloading and running it. Only in Linux we don't have a single stable OS ABI, forcing us to find the correct package for our specific distro, or to package the software ourselves.
A properly secured Linux machine is a unicorn. The Linux desktop ecosystem is struggling a lot with putting software in namespaces. People still install software with their package managers outside Flatpak, there is no isolation of data, not to say many workflows depend on the whole user directory being available to access.
Are there any approaches which implement server-side rendered SPAs with Rust? In that case Rust would render the HTML for the first load and server JSON APIs for changes in the SPA. Rendering the HTML is performance-intensive in my experience, using Rust could save up quite some computational resources.
Just serving static files from Rust is not that interesting. It definitely does not sound easier to me, since you are coupling deployment of both BE and FE with no resource optimization to get. Also, since built SPAs are essentially static files, their deployment could be just uploading these files to your CDN.
> Are there any approaches which implement server-side rendered SPAs with Rust? In that case Rust would render the HTML for the first load and server JSON APIs for changes in the SPA
Yes, frameworks like Dioxus (https://github.com/dioxuslabs/dioxus) implement next.js-like "fullstack" SPAs in Rust (the client-side code compiles to WASM).
> Rendering the HTML is performance-intensive in my experience, using Rust could save up quite some computational resources.
The server-side performance is indeed much better than JS alternatives (client-side performance is more or less the same).
I think there is Dioxus and Leptos if you want full-Rust solutions for SPAs. You're right that CDN is another thing that I forgot considering, too. Can you elaborate more on "coupling deployment of both BE and FE with no resource optimization"
Usually FE and BE are developed by different people or even teams. It's helpful to decouple release cycles of both components, or else a bug on one component could block deployment of a different component. It's important not to decouple deployments of two components when doing so would save up significant resources, but here decoupling could be achieved by deploying a separate nginx server with static files – this is incredibly cheap, as there is very little static overhead, and performance is comparable.
> Leptos is a library for building fullstack web-apps, similar to SolidJS and SolidStart. The two libraries share similar goals on the web, but have several key differences:
> Reactivity model: Leptos uses signals to drive both reactivity and rendering, while Dioxus uses signals just for reactivity. For managing re-renders, Dioxus uses a highly optimized VirtualDOM to support desktop and mobile architectures. Both Dioxus and Leptos are extremely fast.
> Different scopes: Dioxus provides renderers for web, desktop, mobile, LiveView, and more. We also maintain community libraries and a cross-platform SDK. Leptos has a tighter focus on the fullstack web with features that Dioxus doesn't have like islands, <Form /> components, and other web-specific utilities.
> Different DSLs: Dioxus uses its own custom Rust-like DSL for building UIs while Leptos uses an HTML-like syntax. We chose this to retain compatibility with IDE features like code-folding and syntax highlighting. Generally, Dioxus leans into more "magic" with its DSL including automatic formatting of strings and hot-reloading of simple Rust expressions.
For Go, sadly I don't know any framework in the scope of Rust land's Dioxus/Leptos. You continue to have two choices:
- Either to go down the SSR route (and add HTMX for a more SPA-like experience, and use Templ for HTML templating)
- Or to use Go in the backend and something else for the frontend (NextJS or SvelteKit or React Router, you name it; I went with SvelteKit as it fits my needs well, and seems to be "the most popular niche" frontend framework)
This is beautiful. Deterministic, bootstrapped, and doesn't break the established Linux conventions! Shame it's musl-only, I would love to use something like that to build glibc-based apps for future redistribution as proper Linux binaries.
Musl is -much- easier to bootstrap than glibc with far fewer dependencies, that said, we are adding a x86_64-linux-gnu (glibc) cross compiler right now, among other target combinations.
That will make it possible to make packages for any other linux distro as you like.
Curious, why do you think so? As a Russian I found Dutch to be much easier to learn than Japanese, and English knowledge helps. The largest problem by far is Dutch speakers falling back to English almost always.
Well, as a native speaker I don't really have first-hand experience to how hard it is, but here in Belgium it generally agreed on that it's easier for Flems (Dutch speakers) to learn French than for Walloons (French speakers) to learn Dutch. And past tenses of verbs in Dutch are absolutely borked, so much so that this past weekend my sister and I (and we're both quite well read) had no idea what the past tense was of a word, though which word it was escapes me at the moment.
Kubernetes is absolutely not an accidental complexity. Microservices are not an accidental complexity, and they are not a replacement for a proper repository.
Kubernetes solves administration of a cluster of Linux machines, as opposed to administering a single Linux machine. It abstracts away the concept of a machine, because it automates application scheduling, scaling across different machines, rolling updates of applications, adding/removing machines to the cluster all at the same time. There are no instruments like that for applications, the closest to them are something like Spark and Hadoop for data engineering tasks (not general applications).
Microservices are also used to solve a very specific problem – independent deployments of parts of the system. You can dance with your repository and your code directories as much as you want, if you're not in a very specific runtime (e.g. BEAM VM), you will not achieve independent deployments of parts of your service. The ability to "scale independently" (which tbh is mostly bullshit) is an accidental consequence of using HTTP RPC for microservice communication, which is also not the only way, but it allows reuse of the HTTP ecosystem.
In my previous position, we accomplished this using a "dev docker" (which I covered generally in a previous post: https://blog.fahhem.com/2023/12/dev-onboarding-then-now/) that's based around a specific version of Ubuntu (20.04) so the glibc is tied to that.