HN user

banashark

349 karma
Posts3
Comments137
View on HN

I'm a big fan of Postgres I've used it for a while and prefer it (partly due to experience) over other options. There is a lot that it _can_ do, especially when you take FDW, extensions, PLs, etc into the equation.

However, it's not an "always better" situation. These other specialized services excel in ways that Postgres cannot at the moment. _If_ you have a small system, _and_ the featureset you need overlaps with postgres' abilities, _and_ you don't expect to outgrow those two properties, then it could definitely make sense to use Postgres.

Let's imagine that adding all the pressure to the same system _didn't_ impact other parts of the same system (you wouldn't want a surge in kafka write traffic causing latency on your basic crud routes, right?).

Redis vs Postgres unlogged tables:

* Redis has a bunch of algorithms which are battle-tested and ease implementation of common patterns. Need a bloom filter, expiration with ttl that you don't need to write extra code for?

Kafka/SQS vs postgres queueing: * There are pros and cons here, but you definitely don't want your other Postgres work being impeded by high spikes in traffic. Distributed logs and dedicated message queues are built to handle elastic scalability in ways that are difficult to achieve with Postgres. What if you have certain, super busy tenants whose queueing traffic comes in giant batches at unexpected times? With SQS and their recent fair queues, you not only don't need to worry about the spikes (as long as your writers can write fast enough), but you also don't need to worry about the distribution of in-flight consumer work being imbalanced due to the spikiness of a single tenant

ElasticSearch: * Postgres FTS can work for a number of simple scenarios, but there's a number of edge-cases where performance deteriorates as well. What happens when large documents are normal? https://old.reddit.com/r/PostgreSQL/comments/1q5ts8u/postgre... shows some metrics on what happens when you get into TOAST territory. FTS also puts a decent load on the db both in indexing as well as searching.

MongoDB: * Mongo, for all of the deficiencies that it's had over the years (which I hear are mostly resolved these days), can scale writes in a _muuuuch_ more simple way than Postgres.

The claim is that "unless you're at unbelievable scale" you won't hit it, however I don't think that's true. I've worked on multiple Postgres databases that tapped out due to the amount of work it would take to scale things up further (full tenant sharding by db, multiple shards for some larger tenants, keeping that all going and working at a larger scale).

Every additional piece of logic you add into Postgres complicates the story of how you fix things once it becomes too much. Once you've got a single write that triggers 10 different table writes, with 80 index updates, and you want to scale those writes up, you might hit scenarios where you need to choose what gets migrated out. Or you get smart with materialized views, but those require full refreshes. So you create your own version of incrementally-maintained-views, which is more writes and work.

That all being said, I do think Postgres can work for more concerns than it currently is used for, even if I think the recent glazing is a bit much.

Postgres is great, and having everything in a single transactional workload is extremely convenient and can remove a lot of race conditions and buggy behavior.

.NET 10 8 months ago

Although you inevitably end up writing some OOP code in F# when interacting with the dotnet ecosystem, F# is a really good OOP language. It's also concise, so I don't spend as much time jumping around files switching my visual context. Feels closer to writing python.

.NET 10 8 months ago

They killed off VB, which if I recall the announcement correctly, noted that it statistically had a larger user base (by Microsoft metrics) than F#. There are a number of companies relying on F# for critical operations and MS has some use of F# internally which I understand has no plans of replacement, which helps balance out the fear.

.NET 10 8 months ago

I think saying that Spring is the representative of Java metrics is somewhat equivalent to saying that full aspnet mvc is the representative of dotnet metrics.

On the dotnet side, both Oxpecker and Giraffe (Giraffe being written by the author of that post) perform very well with simple code and from what I see, no "tricks". It's all standard "how the docs say to write it" code (muuuuch different than those platform benchmarks that were rightfully scrutinized in the referenced blog post).

On the jvm side, I started looking for a reference near the top without any targeted non-default optimizations (which is really what I personally look for in these). The inverno implementation has a few things that I'd call non-standard (any time I see a byte buffer I imagine that's not how most people are utilizing the framework), but otherwise looks normal. I recall an earlier quarkus implementation that I read through a couple years ago (same repo) that wasn't as optimized with small things like that and performed very well, but it seems they've since added some of those types of optimizations as well.

All to say: If you venture outside the standard of either platform (full fatty aspnet/ef or spring/hibernate) you can make the tradeoff of framework convenience for performance. However when it comes to the cost/benefit ratio, you're either going to be joining a company using the former, or writing your own thing using the latter (most likely).

.NET 10 8 months ago

I'm at my current company (actually writing mostly typescript and node services now) because of a YC "who's hiring" post that mentioned F# positions (bait and switch /s, but my experience lined up heavily with the team I ended up joining which didn't use F#).

Nim 2.2.6 9 months ago

The main release note here is more stable async. I’m curious how folks using nim feel about the async situation.

One of the most recent opinions from the discord is:

“ we have async and asyncdispatch but its leaky and bug prone esp when used with threads and causes deep ownership issues, i prefer using taskman when possible but it leaves the IO problem yet unsolved ”

I’ve also been told to just use regular threads whenever possible.

Do others have more info or sentiments to share?

Not only do you need to walk a mere block or two from the tourist line to find charming quiet spots, but there are tons of people that walk directly past beautiful and interesting places to get _to_ the jam-packed spots.

Small private gardens with interesting history and splendid views sitting nearly empty while a train of tens->hundreds of tourists walk directly past it per minute. Or small hiking trails within a stones throw of a packed entrance with a tiny fraction of the foot-traffic. They aren’t obscured either, just not the “main attraction”.

I was genuinely baffled.

How does this work internally?

From the docs, it looks like it's building a graph to retrieve data, though the comparison it gives contrasts it to doing many small individual queries and passing them to other methods to get evaluated.

I find in the apps I'm working on, either services will build complex queries themselves, or they need to make multiple queries due to data needing transformations between queries that aren't simple to facilitate in the database itself (these services also tend to avoid code in the database, which I'm mixed on).

In the "Deep Composition" section it has a comment in the code `// These three tiles run in parallel`. Does that mean that the way of composition is through pulling in multiple different pieces of data then joining at the application layer?

I'm coming from a very much sql mindset and trying to understand the intended mechanism for data retrieval here. It kind of reminds me of how ad-hoc LINQ queries use Expression trees to resolve sql queries, but not exactly the same.

Or is the thought more that this would be used when you have many disparate data stores (micro services, databases, caches, etc) and doesn't make sense for a monolithic single-database application)?

Not every developer needs to know about all of these things. I'd take this more as a "list of interesting details related to common things you might depend on", it's akin to suggesting that doctors of specific specialties (dermatologist) should know about random things that are part of other specialties (proctologist).

I've always hoped for something like https://github.com/fordfrog/apgdiff that was comprehensive and maintained.

I want to manage my database items like I manage my code. I get a hierarchical folder structure of items with support for goToDefinition and findReferences, and when I update my code I can run something that generates the diff migration. That way I can see historical context of what has changed and when, rather than looking through migration files grepping for the fields or function names of interest.

The migration log ends up being your changelog, except that it's not a simple diff (create or replace function with the whole definition of the function rather than the diff).

Well you say that.... https://openresty.org/en/

"Real-world applications of OpenResty® range from dynamic web portals and web gateways, web application firewalls, web service platforms for mobile apps/advertising/distributed storage/data analytics, to full-fledged dynamic web applications and web sites. The hardware used to run OpenResty® also ranges from very big metals to embedded devices with very limited resources. It is not uncommon for our production users to serve billions of requests daily for millions of active users with just a handful of machines."

Interesting read. I’ve often wondered why the projection we see needs to be the same as the stored artifact. Even something like a git diff should be viewable via a projection of the source IR.

With things like treesitter and the like, I sometimes daydream about what an efficient and effective HCI for an AST or IR would look like.

Things like f#s ordered compilation often make code reviews more simple for me, but that’s because a piece of the intermediate form (dependency order) is exposed to me as a first class item. I find it much more simple to reason about compared to small changes in code with more lax ordering requirements, where I often find myself jumping up and down and back and forth in a diff and all the related interfaces and abstract classes and implementations to understand what effect the delta is having on the program as a whole.

Hearing from past coworkers and friends who have been on the job hunt at some point within the last 5 years has been interesting with regards to what is scrutinized in a candidates profile.

During the hiring spree it seemed like other than ensuring that a candidate was able to (or was able to be trained to) operate at the average expectations of a role's level.

With the demand for software engineers dipping below the supply, recent anecdotes have painted a different picture.

Some of the rejection reasons I've heard for candidates that have otherwise passed all rounds:

* They don't have enough experience in our stack (need to be able to hit the ground running)

* Their experience in our stack, while of a suitable duration, was 2 or 3 jobs ago, so it's not "recent enough" to hit the ground running

* They have worked too many jobs within a timeframe

* They've worked too few jobs in their career

While these of course vary company to company, the former 2 are interesting in this context in that I wonder how an automated candidate <-> requisition matcher would go about gathering data to make it's decision. Will the stack you work in now cement you into that stack for a longer period of time? Will lack of blog posts or other publicly scrapable details about your knowledge or abilities with certain technology impact your matching score?

Related to the above, if those get gamified, I wonder how that might affect a surge of slightly altered blog posts to make one look more experienced with a technology. And when will the SaaS startup get created that will auto-post technical blogs copied/altered from other existing tech blogs.

It will be interesting to see how this all progresses.

I've worked with dotnet and node for a while now (15 years of experience, with roughly half in each, and work at a company that is heavily invested in both stacks).

I've had the opportunity to interview engineers switching to my team that have come from both backgrounds (a node engineer switching to my dotnet team, a dotnet engineer switching to my node team).

Dotnet has plenty of advantages over node, which I'm sure you're familiar with based on the perspective of your comment, but there have been some interesting learnings when having folks from dotnet teams come over to node teams that might interest you:

* Agility in the small

Relevant to the featured framework of the OP, if I want to create an executable with node/bun, it's _very_ fast to get started. I can create a native executing "hello world" with 2 commands: `bun init && bun build ./index.ts --compile --outfile mycli`. This results in a 56MB[1] executable.

_The below is incorrect, dotnet can publish single file executables as well without needing to worry about AOT library compatibility_

~~Getting a NAOT executable with C# isn't too much extra work either, _however_ that's where the iteration speed tanks. With node/bun I can add whatever libraries I want and don't really have to think about "is this AOT compatible?" or "are the accompanying libraries that this library goes with AOT compatible, or do I need to select a different library?". I've seen some momentum starting up to make things a bit more NAOT friendly, but it's a far cry from how effortless node/bun seem in comparison.~~

* The default stack is more modular

This is actually in my perspective also a con. Dotnet comes with a ton builtin, which is excellent, however what I've experienced and had corroborated by other dotnet engineers is that what is builtin to the framework often times is _just enough_ _not_ what is needed, that they need to seek out an external library. Although the modular approach has its own downsides, it means that using an integrating separate modules is often more of a trodden path than with dotnet. An example here is dotnet identity, which while an excellent library (I think it's actually underrated in some ways) often isn't enough to cover the need for things like SAML SSO that are fairly common in enterprise environments as table-stakes nowadays. With node, perhaps you just plugin better-auth which has it by default. Or, your authentication library probably has simple documented extension points, and someone has implemented it already.

I think the distinction here is that in dotnet I tend to do more implementation vs in node I tend to do more api gluing together. There are tradeoffs in either direction.

* It's more simple to debug libraries

One of the benefits of node is that if a library appears to have a bug, I can just go tweak the file in my `node_modules` and reload and see if it's fixed. Stack traces also tend to be much more manageable compared to aspnetcore framework stack traces (it's not spring, but it's not small either), so the time-to-finding-out-the-path-to-a-library-function-getting-hit (and being able to reason about it) is often more quick and requires less context within my head to be maintained.

* A thriving community of open source projects and blog posters

Quantity is not quality, but often times when I hit a path in dotnet that doesn't seem written about much (other than perhaps a outdated project on GitHub), I'll see "I wonder how folks are doing this in java or node" where I'll find much more modern and lively discussion on topics.

Microsoft itself does an excellent job of communicating about the projects they're focused on (example: aspire), but they haven't built the same type of community that can support other amazing, but under recognized libraries that they don't have the time to shine the spotlight on (TPL dataflow, etc).

----

All this being said, I think that dotnet really has a more solid foundation. Avalonia exists and is probably the best that the node ecosystem has had yet in an all-in-one server-side framework, but there is a ton of scope that isn't well covered by it or other libraries (first thing that comes to mind is data redaction, but there are other things) and EF Core, while missing lots of features still (glad that left joins are actually coming as first-class lol) is still miles ahead of ORMs in just about any ecosystem (coming from someone who often prefers raw sql).

This is just info to help provide another perspective.

[1] While I agree that 56MB is insane for a hello world in theory, in practice the size of executables has never proven an issue. Devs have tons of disk space and so these things don't even make a dent.

Interesting. So it was 11k for the dropdown component, but if you eschew the std lib inclusion (which sounds fairly impractical), it goes down to 3k.

When you have a page with many alpine/nim components like this, how does the size increase relative to the # of components added (roughly of course)?

Regarding the js backend: how is the size of the produced artifacts?

I recall seeing a comparison of “transpile to js” languages and noted Kotlin and nim as the two that were outputting MBs of js compared to the tens or low hundreds of kbs that other languages were outputting.

Yeah typically if you're exposing F# code out to C# as a library, you'd want to keep the external API utilizing features that have better interoperability (classes), whereas code that's written in F# and only expected to be called by F# can use things like currying and such.

In practice, this ends up being mostly simple to deal with.

In the other direction, consuming C# libraries historically hasn't had too much trouble other than they don't really design them with any functional-leaning in mind. The real problem that's growing recently is the dotnet teams move towards C#-centric features. Things like source-generators, roslyn, etc that are "C# features" and not "dotnet features". These types of things could create a big enough rift to break practical usage of F# as a dotnet interoping language if it goes unchecked.

Well there are the 3 you mentioned (records, classes, and tuples) which should be easy enough to differentiate from each other. The struct versions aren't necessary to use in most cases, and are an optimization.

The thoughtful, but not breakneck speed of changes within the language is one thing I appreciate a lot. Things do get added (there are proposals and discussions that are fairly regular in the GitHub repo for language design matters). A recent example is adding a spread operator.

I understand where you're coming from, but I'd challenge your dismissal of that note by noting how seemingly powerful a large ecosystem of available packages is when onboarding people to an ecosystem.

I don't think Scala, Kotlin, or Clojure would have had as much adoption if they hadn't had access to the JVM ecosystem of libraries available.

While it's not the only benefit, I think one could just point at the usage of OCaml as the alternative to F#. While both are in the lower percentages of language popularity/usage, I've worked with at least 50 (dozens lol) people who were paid to write production F#.

Comparisons to typescript/node (which I have more ai hours in, but equal experience)

Pros:

* type system is less flexible which simplifies things for the ai

* mostly functional code

* the language hasn’t evolved as much as others because it’s had a strong foundation of features for a while, leading to the corpus containing fairly common themes

Cons:

* smaller corpus

* no reliable hot reloading, which causes annoying iterations of starting a server in the background to test, then forgetting to stop it and hitting errors from starting it again. It does this even when attempting to prompt against it

* Struggles with some breaking changes and interfaces for dotnet things (using old apis, installing old versions of packages)

* file ordering dependency messes with its flow. Usually has to stop to reorder things every once in a while. Can create a mess in the fsproj

Overall my “tier-list” so far has f# below typescript, but above a number of other environments (Kotlin/jvm, Ruby, c#).

Last week I wrote out a 2 page prd for a small service and it got about 95% of the way there (not including tests). If you’re promoting doesn’t have to do with web framework stuff, or you have a repository with existing patterns, it does pretty well.

I gave it a task of “write an inertiajs 2.0 server compatibility library for the oxpecker framework” with a few extra things to create an example test and verify with the playwright mcp. It struggled pretty hard and didn’t end up anywhere close to what I had in my head.

So I’d definitely say that directing it more than vibing would yield a higher chance at success.

Ah rereading your original comment that makes sense.

I found the announcement page here: https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-...

And here are the docs for “dotnet run” https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-r...

You’re right that it’s missing this new functionality. The blog post has some details to get started, but I’m guessing that a docs link or section is missing for that.

Dotnet covers quite a bit so the docs are accordingly larger than other projects that have a smaller scope. I will say though that while hit or miss, on average I’ve enjoyed their docs more than the average project.

Well if you're familiar with the node ecosystem it's a corollary for npx/bunx/etc.

It is so that folks can build and run "tools" that are executed, utilizing the nuget ecosystem.

Relevant links in the dotnet docs (was just a quick google away):

* https://learn.microsoft.com/en-us/dotnet/core/tools/global-t...

* https://learn.microsoft.com/en-us/dotnet/core/tools/global-t...

It's actually a top-level doc section in the primary dotnet docs (https://learn.microsoft.com/en-us/dotnet/).

To boil it down: you create a console app, add a couple of attributes to the solution file (https://learn.microsoft.com/en-us/dotnet/core/tools/global-t...). Packaging and publishing to nuget (if you want to share with others) is via `dotnet pack` and `dotnet nuget push` with some flags.

I do have to say it's actually very well documented.