79 karma · joined June 16, 2022
It maximizes the user market. https://iosref.com/ios-usage
Losing a potential 10% of your market share because they’re 2 versions away is unquestionable for some companies.
As a design choice of OCaml’s eio - an async runtime, you must pass around a dependency to all your IO functions. With the “net” object passed visible in my function type signature, I can tell some network work may occur. The first benefit is we get synchronous Go-like code.
When reading ocaml on _text_ like from GitHub, I personally accept that I won’t need to know the type and underlying data structures just yet unless I read and have open the .mli file.
I’m excited first and foremost because we can have async code feel synchronous like Go.
How does the code run? IO runtime is defined in userland, like Rust’s Tokio. That’s the “Eio_main.run” part. Underneath, eio spins up and manages processes in a non blocking manner, even scheduling work.
Since effects are essentially resumable exceptions, this particular http request throws an effect to the runtime. The logic and this particular process pauses (okay I may be wrong here). Logic flow now continues somewhere in our runtime level (the effect handler), where all the async IO work happens. The runtime resumes the child process and returns the http result back to the child via a “delimited continuation”.
https://github.com/mirage/ocaml-cohttp/blob/16e991ec1f7e5f0c...
Performing these effects is similar to throwing exceptions up the callstack where whichever ancestor handles the IO work, then resumes the child with IO work done in hand.
Example: https://github.com/dhall-lang/dhall-kubernetes
Haven’t used dhall myself but I’d definitely prefer a DSL on top of yaml.
If I forget some api or technique in some language, I ask it. Depending on its results, I may or may not start browsing for more details or to verify.
I use prisma, and then when it becomes too complex, or is annoying, switch to sql.
Sometimes I don’t want to have to manually deserialize rows into my objects (and yes, orms do this for us, and some non-orms do too).
Even a C# developer building with aspnet has to reach out to many of these tools: grafana, some hosting service, some log/error monitoring tool.
But at the same time, I think a lot of comments here are pointing at the glaring reminder of how obscenely complex development for the web can be in the JS ecosystem (for new or non-js devs). Why point new engs to remix, prisma, mailgun, insert 3rd party tool when it’s so much better to give them the Ruby on Rails approach? Aspnet, Ruby on Rails, and similar frameworks in all languages including JS frameworks incorporate nearly all the tools mentioned but without requiring someone to wire it up themselves (or to understand the wiring).
https://www.wsj.com/articles/amazon-scooped-up-data-from-its...
The gist is that yes it’s true. They’d come out with their own Amazon Basics branded stuff and push it to the top.
The second is no IO.
Had to look up to see where Java is at for sum types. First link I found. https://sfietkonstantin.github.io/2021/09/03/Java-sum-type.h...
Sometimes I go back to F# and sigh because I can just print any complex data structure. Sure, there’re limits, but it’s just one less pain.
Regardless, really enjoy everything else. I cloned and built the Dune repo to try to help fix something. Compiled very quickly for its size.
Render.com, Fly.io, northflank. And I actually like AWS lambdas, so great option for me is SST.dev, which wraps AWS CDK, and provides an actual live development workflow with actual AWS resources.
I haven’t used it much, but the tool is able to generate all the code for services that want to speak to one another. This to me is enough service discovery.
If you pick Supabase, it's Postgres with a web api and sdk on top. Then, sure you can serialize all the game state as a jsonb record. You don't even need to deal with authentication if you don't care about isolating games.
Free tier until you make money somehow and then pay the 25/mo.
I think Gleam is pretty good enough to get that typed feel on the BEAM.
A helpful consequence of immutability is that it makes concurrent and parallel programming easier. Take Erlang/Elixir. The main reason it’s able to share state between processes so easily is because it completely copies values from one process into another’s mailbox. Compiler guarantees you don’t pass a reference. If it were the same memory, two processes could mutate and unwittingly break one another.
Another helpful aspect are the patterns of code you end up writing. It’s common in Node and C#, even Go, to pass a mutable context or stateful object with a bunch of hands reaching in to read and write. Because you can naturally do this, you naturally also tend to program like this. Cue data access issues again.
But if you guarantee immutability at the runtime level, it changes how you write code. You tend to write functions in a “transformer” / pipeline style. there’re great examples of open source codebases to read from that exhibit this. See a typical F#, Haskell, and presumably Scala web api codebase, and see how they handle state.
In Haskell or other typed fp languages, you have all these well-recognized and well-used typeclasses and their attached methods, conceptually equivalent to generic interfaces in c#/java. It's easier to adapt new data structures into these interfaces and have all your existing functions immediately work with them.
The "mathematics" part here is that these typeclasses are backed by category theory that prescribes their behaviors.
There are plenty of random readings you can find, so I won't recommend them. Someone's bound to argue with me on what's a better entrypoint.
I do want to note that you don't need to use haskell or an fp language to use these concepts. Example: a complete set of fp data structures in typescript https://gcanti.github.io/fp-ts/modules/. It's just that fp languages make using them much easier because of their type system.
What I also recommend to others now is to skip the complexity of the front end ecosystem, and learn how the web operates from a server side point of view.
If you truly want to stick with react, I’d suggest using https://remix.run. They offer a react experience but forces you into a typical server-first mental model.
Or just learn Node and how to do things the node only way. Basic html forms. Cookies. Security involving forms. Database access. Rendering html with templates. These are basics that get so abstracted over by the modern web dev frameworks that it’s not surprised you’re distracted by something like react hooks.
Maintaining a Postgres server or cluster is hard. But it offers way more functionality.
I agree that the term heavyweight can mean many things to people. I’ve take it as a generic mix of maintenance, complexity of project, ease of use for your purposes.
Seriously, having an http mocking tool is so helpful. I use msw, a node equivalent of wiremock. To help with a situation like yours, it’s easy to say “before this executes, I want the mock tool to return this response”. The abstractions are good enough that I don’t have to deal with recreating my dep-injected service objects, and really reduces the tests’ lines of code. It also seems like the most complex bit here is handling your permutations of code paths, as well as their error paths. I salute. I can’t think of a way to simplify it all except to be glad I work on smaller products now that don’t require so many microservices or 3rd party apis.
The unfortunate bit is ensuring your mock stays up to date with their api. But if we have most or all of the variations, then it’s their fault for breaking their APIs on us, no?