
Modern information technologies amaze with their power, stun with the opening opportunities, discourage their technical perfection, but there is one ridiculous point about which IT breaks its teeth again and again and again. Show user data from the database, get input from him, put it back into the database, show the result. The input fields, buttons, checkboxes, inscriptions - it would seem that they can be so prohibitively complex that it took to build puzzles like frameworks over template engines over frameworks over transpilers? And why, despite all the tremendous efforts, we have that tutorial toy examples, of course, are done easily and pleasantly, but as soon as the toolkit is faced with real-life tasks ... how to say it more softly ... with increasing complexity of the tasks being solved implementation difficulties. Well, if we were talking about something really puzzling at the level of theoretical physics or space technology, so there are no buttons and ticks. Why this nonsense continues to poison the lives of citizens and labor collectives for decades?
The reasons, probably, as always it happens, are many. Probably all of them are somehow worthy of consideration, but here and now we will talk about the object-relational mapping (Object-Relational Mapping, ORM) task, which is always in any form behind all these "buttons and ticks".
What we know about ORM
- Data storage in relational tables is not to say that it is a very simple matter, but in general the idea and the ways of its application are quite understandable and well researched.
- Object programming is not so good (there are several competing approaches), but in general, with the implementation and application of technology, everything is also more or less clear.
- Both that, and another - about the data, their storage and processing. That is, in fact, about the same thing.
- It seems logical to us that there should be a simple, clear, convenient, predictable and universal bridge between these two worlds.
- And every time we easily find this bridge, but bad luck, its simplicity, clarity, convenience, predictability and universality do not work beyond simple examples from tutorials.
- Everybody suffers: both developers, who have to do a lot of extremely boring work, and users, who have to fight with clumsy software, and a business, the realization of whose needs suddenly turn out to be unbearably long and expensive, and the industry as a whole.
- I have seen many different ORMs, but I have not seen any good ones. That is, one that, outside of simple examples, does not turn into a burden and a Procrustean bed.
Why is everything so bizarre
The ideological basis of the theory and practice of relational databases is the predicate calculus, that is, a branch of mathematics. As for the PLO, there is no ideological basis similar in strength. The basic idea of ​​OOP can be tried to formulate something like this: since the world consists of objects, it would be convenient to model it, this world, by creating objects within a software system. In this sense, just two mistakes. First, the world itself is not a member and has never consisted of objects. Secondly, I'm sorry, but why should the program necessarily model the world? That is, we have a conceptually incorrect statement, perfectly complemented by a meaningless statement of the problem.
')
Every ORM is an attempt to clearly stretch a unified correspondence between, in fact, a section of mathematics and a loose set of diverse practices based on considerations of convenience, historically established approaches, and often on legends, opinions of authorities, and simply misconceptions. In vitro, this can be made to work, but in vivo it is doomed to look pathetic and bring more grief than joy.
On the inevitability of object orientation
Nevertheless, the necessity of object orientation of our software is our inevitable reality. This inevitability is based primarily on the fact that the handling of objects is the essence and basis of any of our activities. The world itself does not consist of objects, but in order to understand something and to do something with this world, we declare for ourselves its parts as objects, call them names, try to understand their behavior, apply to them efforts to produce the desired results. This is our way of functioning, and it is impossible to leave him, and it is not necessary. Everything is an object not because it really is, but because we cannot do otherwise. That which in no way can be an object lies entirely beyond our ability to comprehend and cannot be the subject of our efforts.
Even if the program is written without the use of OOP techniques, it inevitably contains objects (in the broad sense of the word), by manipulating which the developer solves his task — variables, data types, operators, algorithms, syntactic constructions, functions, modules. From the user's point of view, the program also has a set of objects with which it interacts - buttons, captions, input fields, pages, websites, and the whole system.
What we store in our databases
As mentioned above, relational databases are based on the predicate calculus. Predicate is a fact that is formulated and, in our case, saved to a carrier. Just in case, I note that the relationality of the database is not only and not so much about the relationship between tables on foreign keys. In the correct terminology, relations (relations) is what we simply call tables. That is, even if there is only one table with two columns in your database (for example, name and phone number), you already have a relational database that establishes a relationship between two sets, in this case sets of names and phone numbers.
The relational database does not store objects, it stores facts. The stored facts, of course, have a subject (“what is this fact about?”), And when we try to teach the system to answer this question, we have entities, that is, objects with which the facts are connected. If we work correctly, the structure of the base comes from a series of answers to the question “what kind of facts do we intend to preserve?”, And only at the next stage do we have something resembling objects that give facts to facts. Of course, you can also design “from objects”, but I would not recommend doing it otherwise than in laboratory work on subjects not directly related to database design. The danger of heavy architectural miscalculations is too great. In addition, it is at least inconvenient.
A small lyrical digression about object databases. A very simple idea: if we are tired of problems with ORM, then maybe we should do something with that part of which is “R”? Let our database be not a rigid and demanding relational monster, but something fashionable youth, specially sharpened for the storage of objects. Any beschemny NoSQL-base, for example. But in the end, suddenly it turns out that NoSQL ORMs are even more crooked and unnatural than the good old SQLs. Anyway, we can have and be happy to exploit a schematic-free DBMS, but there is no beskhemny data in nature. There is nothing more helpless, irresponsible and immoral than ORM for databaseless databases.
Good orm
A good ORM is a missing ORM. Seriously. Look at any of your systems using ORM and honestly try to answer the question: what profits does this monster bring? What is the reason for its use except for unfulfilled promises of happiness and repeatedly discredited prejudices? Certainly, there will be some useful handyies, but what about the background of the introduced architectural deformations and constantly arising performance problems?
As a rule, the “low-level” database API is simple, convenient, complete and consistent. There is usually enough fingers to enumerate all the functions. Learning them is not a godsend what a task.
I will try to sketch a set of architectural principles that allow objects to be zipped to the database without using ORM:
- We keep the facts, we operate with objects. Remember that a database stores facts, and object models involved in data processing are projections of fact sets from different points of view. For example, for the given example with names and phone numbers, we can have the Abonent class, for which several numbers can be saved, as well as the PhoneNumber class, for which several subscribers can be set (don't forget that, besides personal mobile numbers, we have where there are still home and office phones). And the table in the database is only one, which defines the many-to-many relationship between multiple names and phone numbers. Just two different projections. This approach, by the way, normally scales to much more complicated cases, allowing you to have such useful classes in the system, such as, for example, “the average sales volume for a given period by a given combination of criteria”.
- Facts are projected into objects and back through a problem-oriented API. Without applying a solution that claims to universality. If suddenly you are not able to compose convenient API, then learn. And what is also important, teach yourself to document them immediately.
- Order is above all. If you use the classic version of a DBMS with a hard data scheme, then this scheme itself will bring order into the work with the data. The additional structure encoded by the object structure is simply redundant. If you are using a databaseless DBMS, then you will, of course, have to make some efforts to ensure that your database does not become a mountain of garbage due to the fact that different developers have different ideas about where they are stored.
- DBMS independence (if needed). If the most interesting property of ORM for you is DBMS-independence, then use such special tools as ODBC, JDBC, ADO, or if this is impossible, make your own level of abstraction. It is not as difficult as it may seem at first. You do not need the support of absolutely all the capabilities of absolutely all DBMS for your task, right?
- Do not forget about the additional aspects of working with data. Such as, for example, the separation of data access (which can be arbitrarily difficult), monitoring, replication, and more. But here I have good news for you: since in your favorite ORM you need the add. the aspect is still implemented according to the principle “you will not please everyone, eat what they give”, refusal of doubtful service, which you have to fight more than cooperate, will ultimately prove to be a strategically correct decision.
Total
ORM is a very painful topic for our industry. In an era when cloudy artificial intelligence is plowing the expanses of a quantum blockchain, the vast majority of labor resources are busy screwing business logic and user interface to databases. Millions of lines of horrible code, nailing microscopes, pain and despair everywhere accompany this creative process. One of the roots of this sad state of affairs is an extremely persistent misconception that a universal ORM is in principle possible. But it is impossible, and this is a fundamental reason that cannot be eliminated. Awareness of this fact is the first step towards getting out of this nightmare. The way out is possible, there are alternatives, but first of all, to realize, feel and learn to keep the focus of attention.
PS I sincerely apologize to those brothers in the profession who have invested a lot of time and effort in creating many universal best ORM in the world. I am really sorry.