Object-oriented means a variety of things in different contexts and to different people and organisations. It always seemed to me that the best application of the object-oriented concepts was in writing windowing user interfaces, such as the desktop interfaces for Apple's MacOS, Microsoft's Windows and the Gnome desktop for Linux systems. In these systems, multiple windows are usually open at the same time. They operate independently of one another most of the time, but they can send messages to one another. Each window is an object, and they operate in a consistent way, inheriting their appearance and behaviour from a higher-level generic window type.
But, in the development of almost all business applications, including applications for commercial, public and charitable organisations, I have never found the object-oriented concepts to be useful. One of these concepts - inheritance - is available in my favourite database (PostgreSQL) and my favourite programming language (Java). I do inherit from ("extend") the
There are many database systems that claim to support object-oriented features. I consider this to be a big mistake and I will try, here, to explain why. MongoDB is very popular and is described as an object-oriented database and, alternatively, as a document database, and as a
MongoDB emphasises the storage of objects, which they refer to as
In practice, parts of a MongoDB
When you create a new application, or modify an existing one, with MongoDB, you have to look at many different documents containing overlapping, potentially inconsistent, versions, sub-sets and supersets of the data you want. Even the documents in one collection can be different from one another, so, to produce a robust application, you have to consider all the variations that exist now and may exist during the life of your application. The consistency of relational tables makes building applications far more productive.
MongoDB claims high performance But see the benchmark which compares MongoDB with PostgreSQL. In almost all cases, PostgreSQL is much better than MongoDB. One area showed MongoDB as being more efficient in data storage than PostgreSQL. But this was using the JSON data-type in PostgreSQL. If the data had been structured appropriately for PostgreSQL, being in tables rather than JSON documents, PostgreSQL would have been far more efficient. If you try to play a game to someone else's rules, you are less likely to win.
In a relational database table the metadata is stored once for the table, and all records in that table have the same structure. In MongoDB and other JSON-style databases the metadata is repeated in every record and for every field. Look at the example below, where the metadata takes up about as much space as the data.
As well as wasting space, this approach increases code and execution time since every record (or "document") has to be parsed to see what fields it contains. We use computer systems to process large amounts of repetitive data, millions of records with the same format, because that is what computers are good at. If we allow multiple formats in the same "document" we increase the amount of work that has to be done, significantly. And if we don't know what is in a particular document until we read it, we are less likely to have anticipated all the possibilities, and that will lead our program to fail, on particular data, or to process it wrongly. Infinite flexibility is not our goal; instead we need to provide robust and reliable processing of defined scenarios.
MongoDB claims ease-of-use. Mainly, this is because a document looks like the data used for a particular application process. But most databases serve the needs of several different groups of users, so several different views are required, and this means that parts of the data have to be included in several different documents, or one document has to include everything. In the real data model for a medium-sized UK charity, the individual donor had sixteen related objects, most of which can have multiple occurrences for one donor. The JSON object to describe all this would be a monster. Models for commercial or government organisation are usually more complex.
Here is a diagram of a small part of the database supporting a charity. It is much simplified for the purposes of this example.
And here is some data for this data-model, stored in JSON.
{
"first_name": "William",
"last_name": "Oakeshot",
"date_of_birth": "23-Jun-1952",
"date_of_death": "07-Jun-2018",
"address":
[
{
"street address": "18,Summerfield Drive",
"town": "Tenbury",
"postcode": "HX58 6RL",
"email": "willo@instruimus.com",
"phone_number": "07855 553551"
}
],
"correspondence":
[
{
"sent_date": "15-Mar-2011",
"received_date": "",
"medium": "email",
"direction": "sent",
"subject": "sponsored run"
},
{
"sent_date": "15-Mar-2011",
"received_date": "",
"medium": "email",
"direction": "sent",
"subject": "legacy"
},
{
"sent_date": "",
"received_date": "06-Apr-2012",
"medium": "phone",
"direction": "received",
"subject": "legacy"
}
],
"legacy":
[
{
"will_date": "21-May-2014",
"stage": "signed",
"amount": "£2,000"
}
],
"campaign_action":
[
{
"campaign_title":"Forever European",
"start_date": "13-Jun-2016",
"end_date": "13-Jun-2016"
]
}
This document could serve the needs of those users in the charity who are dealing with legacies, and those who are dealing with routine correspondence, and those who are organising campaigns that require action from their supporters.
Each of these groups will get documents that include data that is of no interest to them, because it is handled by the other groups. Dragging data that is not needed out of the database is inefficient; it includes data transfers that could be avoided.
A more serious point is that legacies involve data that will usually be sensitive. Here we are talking about money that people wish to be given to charities after their death (not "legacy systems" which are just old computer systems). Legacies involve people's saved money, and are usually discussed when people are aware of their closeness to death. So data about legacies should be handled by a small team of users who have been trained to deal with such sensitive issues in a sympathetic manner, and who can be trusted with confidential data.
So we would need separate documents for legacies, and we could do it like this:
Unrestricted document:
{
"first_name": "William",
"last_name": "Oakeshot",
"date_of_birth": "23-Jun-1952",
"date_of_death": "07-Jun-2018",
"address":
[
{
"street address": "18,Summerfield Drive",
"town": "Tenbury",
"postcode": "HX58 6RL",
"email": "Bricen@instruimus.com",
"phone_number": "07855 553551"
}
],
"non_legacy_correspondence":
[
{
"sent_date": "15-Mar-2011",
"received_date": "",
"medium": "email",
"direction": "sent",
"subject": "sponsored run"
}
],
"campaign_action":
[
{
"campaign_title":"Forever European",
"start_date": "13-Jun-2016",
"end_date": "13-Jun-2016"
]
}
Document restricted to legacy department only:
{
"first_name": "William",
"last_name": "Oakeshot",
"date_of_birth": "23-Jun-1952",
"date_of_death": "07-Jun-2018",
"address":
[
{
"street address": 18,Summerfield Drive
"town": 18,Summerfield Drive
"postcode": HX58 6RL
"email"; willo@instruimus.com
"phone_number": 07855 553551
}
],
"legacy_correspondence":
[
{
"sent_date": "15-Mar-2011",
"received_date": "",
"medium": "email",
"direction": "sent",
"subject": "legacy"
},
{
"sent_date": "",
"received_date": "06-Apr-2012",
"medium": "phone",
"direction": "received",
"subject": "legacy"
}
],
"legacy":
[
{
"will_date": "21-May-2014",
"stage": "signed",
"amount": "£2,000"
}
]
}
Most database sytems, relational, object, or others, provide some access control, so the legacy
This could work, but it causes us to have the name and address duplicated. Duplication wastes space, but what is far more important is that duplicated data leads to other problems. If the same infomation exists in two or more places, then when it changes, it is very frequent that not all copies get changed, and then we cannot tell which is the correct one, or we can fail to realise that we are not looking at the latest version, so we send a letter to the wrong address, or we try to contact a dead person, which can be very distressing for their survivors.
I suppose that when you write your very first application which accesses a database, then the data representations using
And formatting is not the main issue. What is far more important is consistency and reliability of data. With relational databases, all records in a
One more thing... "Horizontal scaling" seems to be a big thing for the
A distributed database is one that is spread across multiple machines. Data on disks - including solid-state drives (SSDs) is stored in blocks. Block sizes vary between systems, but typically a block would hold between 10 and 100 records. In a distributed database, the blocks are distributed across multiple disks on multiple servers. Each server with its disks is called a "node". Usually each block is stored on more than one node, so that, if a node fails, the whole file can be recreated from the blocks on other nodes. This makes the file system resilient. It is typical to have three copies of each block on different nodes.
This is a sledge-hammer to crack a nut. Non-distributed relational databases are also highly resilient, and, in practice, seem to need recovering less often than
Distributed databases have become fashionable, but they are needed only in extreme cases which are outside the requirements of very nearly all organisations.
Distributed databases have significant drawbacks.
When all the disk storage is on one machine, it is possbile to apply multiple changes to the data in the database on the disks, and to ensure that all these changes are safely stored on the disks, or none of them are. This is the concept of a
Transactions can be safely recorded like this when one machine is controlling all the disk storage.
But when transactions are applied with parts of the transaction on different nodes, things get a lot more complex. Transactions have to be committed in a two-phase protocol to have some hope that the change has been applied successfully. Two-phase commit is much more complex than the simple commit performed when everything is on one node, and things can go wrong even when this complex protocol is used.
A related issue is the allocation of identifiers (or "keys"). On a single node it is easy to have a central key generator which guarantees that no two records get the same key. This is fast and efficient as well as being reliable and the keys generated are usually 4-byte integers (from 1 to about 2 billion). 8-byte integers can also use the same mechanism and that will give enough distinct keys for any dataset that you will ever have.
A central source for the next identifier is not feasible in a distributed system, so these systems use large random numbers instead. The numbers used are usually UUIDs. (Microsoft, being hostile to standards, calls these "GUID"s.)
A UUID looks like this: 2c885f6c-8e5b-456f-8a9f-44dc52c7fd96.
Microsoft's own documentation says:
"Because GUIDs values are long and obscure, they are not meaningful for users. If randomly generated GUIDs are used for key values and you insert a lot of rows, you get random I/O into your indexes, which can negatively impact performance. GUIDs are also relatively large when compared to other data types. In general
And yet, Microsoft forces its
There really is no good reason to use