Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Another way of looking at the problem is that (in many naively-implemented backend codebases) almost every layer and component of the stack ends up depending on the ORM objects, which has the consequence of allowing any of those layers or components to do arbitrary database operations.

You might have some 'data access layer' class/module but if you're using an ORM, it more than likely accepts as arguments and returns as results some ORM objects. The ORM objects returned from the data access layer invariably have methods like `save()` or `delete()` or `validate()` or some magical property when called ends up issuing another query (think: `customer.orders` or `order.customer`). The objects you're supposed to pass to your data access layer as arguments probably also have constructors that, under the hood, grab static references to singletons (often the connection factory).

In this way, the data access layer is leaking the opportunity to (if not the responsibility of) invoking save/delete/validate functionality to any and every part of the code base, when it should really be contained in one module. Moreover, you cannot reason about whether a particular data object is persisted, could be persisted, or was persisted just from its type.

That is, your Customer object always exposes `save`/`delete`/`validate` even if you got it from a data access layer method called `getCustomersWithRecentOrders`. (Idem for the elements of `getCustomersWithRecentOrder()[0].orders`.) There's nothing stopping you from pulling out `getCustomersWithRecentOrder()[0]`, mutating it, then calling `save()` (or `validate`, or `delete`)—which never-ever makes sense.

Instead, `getCustomersWithRecentOrders` should return behavior-less structs, and your data access layer should provide an `updateCustomer` method. Moreover it should be impossible to construct the type that goes into `updateCustomer` with data that does not validate.

When you implement this kind of data access layer, maybe you use a low level DB driver, maybe you use an ORM for some niceties, but either way, you shouldn't leak types from these dependencies out to the consuming module. However I rarely see this kind of discipline in 'naive' ORM apps (rails/django/laravel/CoreData/Hibernate/etc).



Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: