Tony Marston's Blog About software development, PHP and OOP

Re: Objects should be constructed in one go

Posted on 19th July 2018 by Tony Marston

Amended on 23rd July 2018

Introduction
1st response from Paul Court
2nd response from Paul Court
3rd response from Paul Court
References
Amendment History
Comments

Introduction

I recently came across a blog post titled Objects should be constructed in one go in which the author identified a rule then went on to explain how this rule should be implemented. This caught my attention straight away as that rule simply does not exist, which means that the entire article is based on a false premise and is therefore invalid. I posted a comment to his blog, yet almost immediately I received the following message in my mailbox:

Hi Tony, I will be deleting this comment and I am sorry I have to do it. You're not joining civilized conversation in any way. I'll also block you from further interaction on this blog. My advise: please stop bothering people like this.

I replied with this:

By deleting my perfectly valid post you are exposing yourself as a snowflake who cannot tolerate criticism or an opinion which differs from your own.

My statement that the rule on which your article is based does not exist is perfectly valid, which means that your entire article is based on a false premise and therefore can be questioned.

I have seen plenty of articles on the internet which show a constructor creating nothing but an empty object, so you appear to be saying that everyone else is wrong and you are right. How arrogant.

He replied with this:

I've had an awful encounter with you before, and how you start off your latest comment, well, that's not how you have a conversation. I know many people who have tried to point this out to you, and yet, here you are again. Please, go somewhere else. And please keep out of my comment section, and my mailbox too.

This simply means that I have criticised several of his statements in the past and that he didn't like that criticism. He therefore fits the definition of a snowflake.

Here is the post that he deleted:

This entire article is rubbish as it is based on a rule which simply does not exist. The purpose of a constructor is to initialize an object into a sane state, which means that it can accept calls on any of its public methods. It is these methods which are responsible for moving data in and out of the object.

I have been writing database applications for several decades, and in my OO implementation I have a separate class for each database table, and when I instantiate a table object it always starts off by being empty. There are only four basic operations which can be performed on a database table, and these are Create, Read, Update and Delete, or CRUD for short, and I have a separate method for each of these operations.

After I have instantiated an empty object I use one of these methods to populate the object with data. The CREATE method will take data supplied from the presentation layer, validate it, and if valid will write it to the database. The READ method will supply optional arguments for the WHERE string, then pull in data from the database which is then passed to the presentation layer. It is simply not possible to perform these operations in the constructor.

I wish people would stop inventing artificial rules which serve no other purpose than to make the art of programming much more difficult that it need be.

I ask my readers (both of you!) to consider the following questions:

Why did he publish his article and ask for comments if he is unwilling to publish responses which contain different opinions? He certainly cannot claim that what I wrote was off-topic, abusive or contained foul language, so what is his problem? Is he really that delicate that he cannot handle legitimate criticsm? Is he really that much of a snowflake?

1st response from Paul Court

Shortly after I published this article I received the following email from Paul Court. My responses are embedded.

Hello Tony,

Whilst pootling round the web - as one does, I came across your article and Matthias' related article:- Objects should be constructed in one go.

Since you don't have comments enabled on your blog or appear to be in twitter, I assume your preferred method of comms is email. So here I am to reply to some of the questions you raise at the end of your post.

Q: Does the rule which states that a constructor must create an object that is pre-populated with valid data before the first public method called actually exist?

Short answer, Yes. Matthias just made it up.

Longer answer, No.

My interpretation of it was as an opening statement to a blog article and not something that is etched in stone as the 11th commandment! The opening four words are "Consider the following rule". So while you are reading the post, imagine that the rule exists (and we want to obey it).

Me:
Your interpretation of the opening statement "Consider the following rule" as a mere suggestion is not something with which many would agree. If he had said "Suppose the following rule existed" then that would have changed the tone of the article in the direction which you suggest. I interpreted that opening statement as "This rule exists, so how do we implement it?"
The very next line of the article is "It is derived from the more general principle that it should not be possible for an object to exist in an inconsistent state.". This is a very important OO concept. The more robust we can make our models, the better we will make our finished OO programs.

Me:
The statement "it should not be possible for an object to exist in an inconsistent state" is perfectly valid, but it depends on what you mean by "state". In some contexts it could mean the data that an object contains, as in "stateful" or "stateless", but in the context of a constructor it means "condition". The original rule was stated as "a constructor must leave the object in a condition in which it can respond to calls on it public methods". This misinterpretation of a single word is something which happens quite often in the English language where the same word can have more than one meaning, or where different words can have the same meaning. As evidence I suggest you read Making Wrong Code Look Wrong which explains how confusion over the simple word "type" led to that abomination called Hungarian Notation.
Q: If so, then where is this rule documented, and by what authority?

We don't have a great big fat rule-book. We have a collection of guidelines and best practices which evolve over time as our collective experience of modeling the insane logic of business grows.

Me:
You fail to realise the problem that this causes. If there are different rules in different places, then what happens when a rule in one place contradicts a rule in another place? What if a rule is accepted by some programmers but rejected by others? What happens if a new rule which has just been invented is based on a misinterpretation of a valid rule? All the while you have different people documenting different rules in different places you will get arguments as to which rules are valid and which are rubbish. Programmers cannot even agree on simple concepts - try asking 10 programmers "what does OO mean" and you will get 10 different answers - so asking for the correct way to use a feature of OO does nothing but open a can of worms.
Regardless of which language you program in, any developer with more than a few years experience in writing business code will more than likely have a handful of books on the theories behind modeling (More than likely from Martin Fowler, Eric Evans or Vaughn Vernon - I have all three).

Me:
The only book on modelling which I bought many years ago was by Gane and Sarson. I also went on a Jackson Structured Programming course. As I only work on database applications for the enterprise these were the only things that I found gave sound advice.
This is us (developers) collectively learning and improving from our peers and predecessors.

There is no "single authority", but when the same principles are proposed and/or recommended by multiple, well regarded people in the industry then they hold significant weight.

Me:
Just because one person is accepted as a guru by one group of programmers does not mean that he is accepted as such by all programmers. There are some people who have made statements with which I agree, but that does not mean that I have to agree with everything they say. I often quote Robert C Martin when discussing Single Responsibility Principle (1) and SRP (2), but I think his article One Thing: Extract till you Drop goes too far in the wrong direction. It is simply not possible to identify a list of people who are well-regarded by the whole of the programming community, or who have produced documents on which everybody can agree, so it is wrong to say "someone I like proposed this rule, therefore I must obey". I will pick and choose whose writings I will follow and which rules I will implement without interference from anybody.
Q: If not, then can my response be regarded as legitimate and fair?

No. Not if you started your response with "This entire article is rubbish".

As Matthias goes through the article, he explains his thinking behind the rule. Gives an example with the geo-location bit and then walks through a real-world scenario. As he does so, there's that "code smell" which all developers love to hate.

Something is not quite right.

As the article progresses, it goes through an exercise of re-assessing the thing we are modeling. The result is that the domain experts description of "a document with lines" doesn't quite paint the full picture and that it's OK at a certain point of it's life-cycle for the purchase order to not have any lines.

Me:
In a database a purchase order is represented by two tables - a PO_HEADER and a number of PO_LINES, but these are separate tables in the database and should therefore be separate objects. It is valid for a PO_HEADER to exist without any PO_LINES, but it is not valid for a PO_LINE to exist without a PO_HEADER.
We didn't break the rule - we gained a better understanding of the thing we were modelling. I would consider this to be a fantastic exercise for a developer of any skill level.

Me:
How can that be? What actions we perform in a class constructor have nothing to do with how we designed the application model, they are mere implementation details.
If we bring this back to your database example, I very much doubt you are modelling a database table. If you were, you would be talking about file handles, buffers, indexes and not CRUD operations. What I suspect you are actually modeling is "database table interactions". Building queries and sending them to the database and handling the response.

Me:
I disagree. I have been writing database applications for several decades using a variety of hierarchical, network and, for the last 20 years, relational databases. I never have to bother with file handles, buffers and indexes as the RDBMS takes care of that for me. Every table in the database is a separate entity with its own set of columns, but every table is subject to the same set of CRUD operations. Every enterprise application I have ever written is nothing more than a piece of software that moves data between the presentation layer and the data access layer, so I have built a framework which lets me build application components which fit that pattern.
Indeed, you would not pass potentially millions of records to the constructor. However, I would be very surprised if you are not passing a connection object or connection parameters as your table model would be useless without them.

Me:
Stand by to be surprised. I never pass a connection object to any of my table classes. It is not until the class itself wants to access the database that a connection object is created. This means that when I create a table object it starts with no data and no connection. You may class this as a "code smell", but has this mechanism has worked for nearly 20 years with nothing but benefits and no downsides I would regard your sense of smell as being off-target.
If indeed you do have an empty constructor and the possibility of having a table model with no database to talk to, you might want to consider if that is a "code smell" which you might want to improve upon.

Q: If so, then was Matthias Noback justified in removing it?

Yes. His blog, his rules. At least he took the effort to email you why. By your own admission, you called his article rubbish and then branded him a snowflake (and apparently not the first such exchange). I probably wouldn't have bothered with the email and would have just whipped out the ban-hammer.

Me:
if someone posts an opinion and asks for comments it is disingenuous to delete those posts which provide a contrary opinion. If I had posted a comment which was off-topic, contained personal abuse or foul language then he would have been right to delete it. He started his article with the statement "Consider the following rule" and gave examples of how it should be followed. I merely provided a contrary argument which stated that such a rule does not exist and provided examples which showed the impossibility of implementing that rule. If he had allowed my comment to stand then that would have given everyone the chance to view my opinion and either agree or disagree (just as you have done). By deleting my comment simply because he didn't like it he is in effect stifling honest debate. That is why I labelled him a snowflake.
Q: Why did he publish his article and ask for comments if he is unwilling to publish responses which contain different opinions? He certainly cannot claim that what I wrote was off-topic, abusive or contained foul language, so what is his problem? Is he really that delicate that he cannot handle legitimate criticsm? Is he really that much of a snowflake?

I'm not going to dwell on these, but I would imagine polite and constructive criticism is welcome. "this entire article is rubbish" is neither of those.

2nd response from Paul Court

Here is his subsequent email and my responses:

No one mentioned an RDBMS. What if it's being stored in Mongo, flat files or XML?

Me:
I write nothing but database applications for the enterprise, and have done for over 30 years. I have yet to see any modern organisation which uses anything other than a relational database for its enterprise applications. Other storage systems may be used in some specialised circumstances, but the vast majority of data is held in relational databases.
You are not modelling a database table. You are modeling the interactions with a table.

Me:
I disagree. Each of my table classes encapsulates the structure of a single table and the business rules associated with that table. It contains methods to perform the basic CRUD operations, but does not contain any methods which allow it to interact with other tables. Each of these classes then becomes the "model" in the Model-View-Controller design pattern. If it did not contain any business rules and only handled the generation of SQL queries then your point might be valid.
How does it create the connection when it needs to? Where does it get the database credentials?

Me:
If you look at http://www.tonymarston.net/php-mysql/uml-diagrams.html#add1 you will see that each concrete table class is made up of code which is inherited from the abstract table class plus custom methods which exist within itself. When it needs to communicate with the database it does so by instantiating an object from a DML class (with a separate class for MySQL, Postgresql, Oracle and SQL Server) then calls the relevant method on that object. It obtains the DML instance by calling the _getDBMSengine($dbname) method with the name of the database in which the current table resides. This will then use values read in from the config.inc file which identify which DBMS to use as well as the credentials required to connect to that DBMS. By using a singleton I ensure that in any page execution which contains multiple calls to the database that only a single instance is ever used.

My framework is an implementation of the 3-Tier Architecture with its Presentation layer, Business layer and Data Access layers. One of the rules of this architecture is that the Presentation layer can only communicate with the Business layer, and the Business layer can only communicate with the Data Access layer. This is why I do not instantiate the DAO in the Presentation layer and inject it in to the Business layer.

3rd response from Paul Court

Here is his subsequent email and my responses:

I have no doubt about your skill and experience as an RDBMS application developer, however, you seem reluctant to do the same mental wandering. I can assure you there are many enterprise applications which don't rely on an RDBMS.

Me:
Can you point to any websites which claim such a thing? Enterprise applications were originally known as data processing systems, which means that they processed data in some way and stored that data in a database.
The projects I am most involved with on a daily bases are for what I can best describe as "Bridge Applications" or "Cross platform gateways". These are very much key enterprise applications.

Me:
I'm sorry but "bridge applications" or "cross platform gateways" are not enterprise applications in themselves. A true enterprise application has a Presentation, Business and Data Access layer so that it allows data to be put into and read from a database.
They will normally have front-end GUIs, however they hardly ever have their own RDBMS. Instead, they communicate between the other software platforms at an API level to cross reference, analyse and collate data.

Me:
If they don't have their own DBMS then they are not storing enterprise data, so they are not true enterprise applications. A piece of software which is used in an enterprise application is not itself an enterprise application.

References

Amendment History

23 Jul 2018 Added 2nd and 3rd response from Paul Court
21 Jul 2018 Added 1st response from Paul Court

counter