> I for one don't like it when people online, with every statement, signal their personal ethics. It gets to be very tiresome and degrades my HN experience.
Ironically, buying a Tesla is nowadays a very visible political statement.
If cars were not statements of the owner's ego or personality or brand, everyone would be driving either an unwashed Toyota Corolla or (if 3+ kids) a minivan.
I've made an opposite progression from the op. I was a strong believer of upfront design, but now value iterative approach as you do.
For the first try, hack together something working, you'll learn things along the way, validate/disprove your assumptions. Iterating on this will often bring you to a good solution. Sometimes you find out that your current approach is untenable, go back to the whiteboard and figure out something different.
Starting with raw SQL is fun. But at some point you find out you need some caching here, then there, then you have a bunch of custom disconnected caches having bugs with invalidation. Then you need lazy loading and fetch graphs. Step by step you'll build your own (shitty) ORM.
Same thing for people claiming they don't need any frameworks.
caching is orthogonal to using or not using ORM. You might opt to have caching with or without ORM in a consistent manner. You can also opt to add read replicas fronted by say pgcat in Postgres case without having separate caching layer.
I guess this is a point where terminology matters. If you work with SQL database in an OOP language, you pretty much always do some object-relational mapping, no matter if you have a big framework or just raw SQL connection.
But this is not what people usually call as ORMs. All the "bad kind of ORM" (JPA impls, Entity Framework, SQLAlchemy, Doctrine, Active Record...) have some concept of an entity session which is tracking the entities being processed. To me, this is a central feature of an ORM, one of its major benefits. It is, incidentally, also serving as a transaction-scoped cache.
I won't of course dispute that you can have caching on other levels as well (which may perform differently, for different use cases).
As SRE who dealt with more caching errors then I care to. Alot of caching comes down to YAGNI.
To his point: It's very hard to beat decades of RDBMS research and improvements
Your RDBMS internal caching will likely get you extremely far and speed difference of Redis vs RDBMS call is very unlikely to matter in your standard CRUD App.
There are plenty of libraries/packages for SQL that do all of that for you, too. The choice isn't between a sophisticated ORM and just throwing SQL text at a socket. The fundamental assumption of ORMs is broken, but much of the tooling works well and exists in non-ORM places.
JPA implementations have "managed entities", sometimes called session or 1st level cache which is making sure that every entity is loaded at max. one time within a transaction. Like e.g. checking user/user permissions is something which typically has to be done in several places in course of a single request - you don't want to keep loading them for every check, you don't want to keep passing them across 20 layers, so some form of caching is needed. JPA implementations do it for you automatically (assuming you're fine with transaction-scoped cache) since this is such a core concept to how JPA works (the fact it's also a cache is kind of secondary consequence). JPA implementations typically provide more advanced caching capabilities, caching query results, distributed cache (with proper invalidation) etc.
Why is caching not a feature in DB connection pools? I mean, most databases have it on their side, why not have it as an option for the same query sets prior to hitting the db, with configurable invalidations? Or is it, and I've just never thought to look for it.
Integrating cache into connection pools brings little added value since connection pools don't have enough context/information to manage the cache intelligently. You'd have to do all the hard work (like invalidation) yourself anyway.
Example: if you execute "UPDATE orders SET x = 5 WHERE id = 10", the connection pool has no idea what entries to invalidate. ORM knows that since it tracks all managed entities, understands their structure, identity.
I guess I was thinking more of frequently run queries against infrequently modified data or where stale data doesn't matter so much. The sort of things that are ideal cache targets. You'd think you could tag queries like that. Sort of the things that a CDN caches but more granular. Sure if it's stuff that's frequently changed, an ORM could reason about it just like, well, the database does, but then you're back into all the bad things about running your shadow database with a badly fitting model, and you'd be better off just ensuring all or part of the database ran closer to your app with replication, say, in memory on same server.
That would be a result set layer, not a connection pool. Could make sense if you worked with rows, but if you use ORM, why mapping cached row again and again? ORMs cache hydrated objects, which seems to be more efficient.
> They just needed some syntactic sugar to help redirect certain developers into less self-destructive ways of procrastinating on proper error handling.
Syntactic sugar it needs is an easy way (like ! prefix) to turn it to a runtime exception.
Procrastinating on exceptions is usually the correct thing to do in your typical business application - crash the current business transaction, log the error, return error response. Not much else to do.
Instead the applications are now littered with layers of try-catch-rethrow (optionally with redundant logging and wrapping into other useless exceptions) which add no benefit.
The try/catch/rethrow model can easily be substituted by just adding a `throws` to the method. If you truly don't care, just make your method `throws Exception` or even `throws Throwable` and let the automatic bubbling take care of making you handle exceptions at top level.
I disagree. The real value of exceptions is you can skip 6 levels of functions that have lines like
status = DoThing();
if(status != allIsWell) {return status;}
C++ embedded for a long time has said don't use exceptions they are slow. However recent thinking has changed - turns out in trivial code exceptions are slow but in more real world code exceptions are faster than all those layers if checks - and better yet you won't give up on writing all the if checks. Thus embedded projects are starting turn
exceptions on (often optimized exceptions with static pre allocated buffers)
The final "print something when wrong" is of little value, but the unwinding is very valuable.
Khalil Estell has some great work on that. https://www.youtube.com/watch?v=bY2FlayomlE is one link - very low level technical of what is really happening. He has other talks and papers if you search his name.
Well, usually you want to handle it at some level - e.g. a common REST exception handler returning a standard 500 response with some details about what went wrong. Or retry the process (sometimes the errors may be intermittent)
Yes, this is a joke - implying that his stance on DEI is self-serving and simply changes with the political climate. The physical appearance change is more superficial, but could also be seen as a change in PR strategy.
The joke above was that in a phrase like "Meta's Mark Zuckerberg ...", the first word is unnecessary because he's one of the most famous people in Tech, if not the country in general.
I guess my problem is that I had no idea that he changed his visual appearance so these references just confused me. I'm not really following his personal life.
Ironically, buying a Tesla is nowadays a very visible political statement.