Ask HN: Data Driven Applications
Hi all,

First write after a lot of reads...

I've been using ORM for years in Java and C# and came to the conclusion that the only reason we use these tools are because most Java and c# developers think that the business logic applies on objects and not data.

So when they/we see a entity-relationship diagram we think that must reify these entities as classes. This results, most of the time, in classes with accessors (and nothing else, so OOP purist are also a little bit skeptical when they see theses classes without any behaviors). And then we need a ORM to map this classes with the tables.

But everyone else on the project (dba, domain experts) think that the business logic we write uses data stored in the db, not objects. And if we start thinking like them, the only thing we need is something to manipulate the data and apply business logic on it.

For example if I need to get a piece of information on a bank account to accept or reject a withdrawal:

C# with Dapper:

var accountInfo = (await dbConnection.QueryAsync<(double balance, int overdraft)>("select balance, overdraft from Account where id=@id", new {id = "..."})).SingleOrDefault();

Java with Spring JdbcClient:

record AccountInfo(double balance, int overdraft){}
Optional<AccountInfo> accountInfo = jdbClient.sql("select balance, overdraft from Account where id=?").params("...").query(AccountInfo.class).optional();

No account entity class. Thanks to tuples and records, data are not excluded citizens in a Java or C# application.

with an orm (Java with JPA):

Account account = entityManager.find(Account.class, "..."); // Account is an entity class

results in select * on the account table, what if account table has 50 columns...I cannot see any use cases that justify fetching all the columns for a given row. On the contrary, every step of every use case involves some data that must be fetched and records or tuples help to get them in a shape that is easy to use.

of course you can do that with JPA:

record AccountInfo(double balance, int overdraft){}
Optional<AccountInfo> accountInfo = entityManager.createQuery("select balance, overdraft from Account where id=:id", Object[].class)
.setParameter("id", "...")
.getResultStream()
.findAny()
.map(a -> new AccountInfo(Double.parseDouble(a[0].toString()), Integer.parseInt(a[1].toString())));

but that only proves that an ORM is an obstruction between the code and the data, not a helper that makes data retrieval easier. And if you do that all the time then you never retrieve your entities.

Same for lazy loading, which selects all the columns of the lazy loaded entity while you often need one or two properties.

Becoming an expert with an ORM consists in knowing how to use its leaky abstraction so the sql query is the one you would have written without orm. Not very fulfilling (there are tons of more useful things to learn for a programmer) nor useful for the project.

More over, the choice of a database is (or could be) guided by business requirements. If a project benefits from a MongoDB database the developer should have access to the mongodb language, if it needs a graph database the developers should have access to the its query language, etc... It also fosters good relations with the DBA (I can ask for help to write a query) while ORM and their sub-optimal queries breaks the confidence between developers and DBA.

Of course the DB may change in the future (but most of the time it is here to stay) and vendor specific syntax will then break, but running tests against the new db will show which queries must be adjusted. Markers could also be written for vendor specific queries: /specific/ at the end of the string so they are easy to find.

An ORM is useful if you reify the domain model in classes with behaviors or if you sell a product that must be database agnostic. But for most project it is not a requirement.

What to you think ? Thanks !