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

Having a separate class for each database table *IS* good OO

Posted on 1st December 2017 by Tony Marston

Amended on 8th February 2021

Introduction
My training in OO programming
My approach
One class per table
Datasets instead of columns
Forms families
Reusable XSL stylesheets
Transaction Patterns
Criticisms of my approach
Real OO programmers don't do it that way
You are not following the rules of Object Oriented Design (OOD).
This results in a lot of duplicated code
You should use object composition instead of inheritance
You just don't understand what OO means
You wouldn't model people by creating a Person class and subclass it for each new person would you?
Having a separate class *instance* is good OO, having a separate *class* is bad OO
This leads to a problematic dependency between the DB and the class
You should not have to create a new class for each database table
You have to recode both the table and the class every time you change the table
You are not using the right design patterns
Your implementation is not OO, it is procedural
You have created a God Object.
You have an anemic domain model.
Your implementation is too simple.
This approach is only useful for simple CRUD applications
I tried this approach once, but I couldn't get it to work
Arguments against having a single class for multiple tables
Arguments against having a multiple classes for a single table
Advantages of my approach
I don't need to waste any time with OOD or DDD
I don't need to waste time in designing class hierarchies
I don't need to waste any time choosing which design patterns to use
I don't need to waste time in building each table class from scratch
I don't need to waste time in designing methods and properties for each table class
I don't need to waste time with writing code to validate user input
I don't need to waste time in writing code to perform standard SQL queries
I don't need to waste time with designing Controllers for each of my Model classes
I don't need to waste time with writing a separate Data Access Object (DAO) for each table
I don't need to waste time designing and building HTML documents for each web page
I don't need to waste time writing code for each of the components on a web page
Additional Advantages of my approach
Conclusion
References
Amendment History
Comments

Introduction

This article expands on what I wrote several years ago in Each database table requires its own class.

I have been told many times by numerous people that having a separate class for each database table is not proper OO, that real OO programmers don't do it that way, but none of these people have ever provided a satisfactory answer to these simple questions: "Why not? What are the alternatives? Why is my chosen method worse than the alternatives?"

As far as I can tell there are only three possibilities when it comes to the relationship between tables and classes:

  1. Have a class which is responsible for the data and business rules for more than one database table.
  2. Have a class which is responsible for the data and business rules for a single database table.
  3. Have the data and/or business rules for a single database table split across several classes, such as by implementing the Command Query Responsibility Segregation (CQRS) pattern which advocates using separate models (classes) for update and display.

In my humble opinion option #1 violates the Single Responsibility Principle as a software object ends up by being responsible for more than one business object. See Arguments against having a single class for multiple tables for details.

Option #3 violates the principle of encapsulation which states that a class should contain ALL the data and ALL the operations concerning the entity which it represents. See Arguments against having a multiple classes for a single table for details.

Option #2, my chosen approach, not only does NOT violate any principles, it has actually enabled me to build software which provides a huge amount of reusability simply by utilising inheritance and polymorphism in a more practical way.

So far the only reason provided by the critics of my approach goes along the lines of:

You are supposed to model the real world, and tables in a database are not real objects, they are just representations of real objects.

I find this statement to be seriously flawed. Just because you can model the real world does not mean that you should. You should only model those parts of the outside world with which your software will communicate directly. When you are developing software which communicates with "something" outside of itself then you have to write code which communicates directly with that "something". The fact that the "something" is a collection of database tables each of which represents "something else" does not mean that you have to create models for that "something else". There is no communication between objects in a database and the corresponding objects in the real world which they represent, so why waste time on modelling the objects with which there is no communication?

When you come to terms with the fact that if your application is dealing with database tables called Customer and Product then you are not dealing with entities called Customer and Product in the real world but different tables in a database. The software communicates with entities in a database and not entities in the real world. There is no communication between these database entities and real-world entities, so why on earth would a sensible programmer create models for entities with which there is no communication, either direct or indirect? You should only use a model of a real-world entity if you are communicating directly with that entity.

While the differences between a Customer and a Product in the real world may be great, you should be able to recognise that the differences between the two tables are far less. In fact there are more similarities than differences simply because every table in a database, regardless of its contents, is subject to the same rules, and a competent programmer should be able to apply the concepts of Encapsulation Inheritance and Polymorphism to abstract out the similarities and create code which has more reusability and therefore requires less maintenance. This is supposed to be the aim of OOP, so why are so many programmers following a path which does not achieve this aim?

I have written an ERP application which currently consists of 20 different domains using a total of over 400 database tables, and while each of those tables is totally different they also have a number of similarities:

If creating a separate class for each database table is so wrong, then can you explain why Martin Fowler, the author of Patterns of Enterprise Application Architecture defined patterns called Table Module, Class Table Inheritance and Concrete Table Inheritance which specify "one class per table"? Can you explain why Craig Larman, the author of Applying UML and Patterns, mentions the Representing Objects as Tables pattern? If these people say it's OK, then who are you to argue? If it's so wrong then why does the author of Decoupling models from the database: Data Access Object pattern in PHP state the following in his opening paragraph:

Nowadays it's a quite common approach to have models that essentially just represent database tables, and may support saving the model instance right to the database. While the ActiveRecord pattern and things like Doctrine are useful, you may sometimes want to decouple the actual storage mechanism from the rest of the code.

If it is a "common approach" then why is it wrong to follow it?

In this document I shall explain why that not only are there absolutely no pitfalls to my approach but in fact there are nothing but advantages.


My training in OO programming

I started experimenting with PHP version 4, my first language with OO capabilities, way back in 2002. This was after programming for several decades with other languages, primarily COBOL and then UNIFACE, so I was already used to a range of good practices such as KISS, DRY, structured programming, coupling and cohesion. My research told me that OOP was built on these same foundations, but was supposed to be better because it included new and revolutionary concepts called Encapsulation Inheritance and Polymorphism. I read the PHP manual which described the mechanics of these concepts and how to implement them in my code, then I began to build a new version of my existing development framework in this new language which took advantage of these new concepts. If OOP was supposed to be better, then my aim was to produce a framework which enabled me to build applications in a more cost-effective manner than what I had achieved with similar frameworks which I had written in my previous languages. As I write nothing but database applications, what are now known as enterprise applications, I am used to building a standard family of forms to maintain the contents of a database table, so I used as a benchmark the amount of time it would take to build a set of these forms for a new database table. These are the levels of productivity which I achieved:

Those levels of productivity are a combination of the capabilities of the language and the features provided by my development framework. Each language provided new features which made development easier and quicker, and my framework made use of these features to provide a common set of utilities for each of the applications that were developed. The fact that my PHP framework was far more productive than either of my previous versions led me to believe that the benefits of OO were "as advertised" and not just a bunch of hype and that my implementation of OO was on the right track. I began to publish articles on my personal website explaining my approach so that others could benefit from my experience, so imagine my surprise when people started telling me that I was doing it wrong and that real OO programmers don't do it that way. Most of the arguments were along the lines of Your way is different from mine, and as my way is the right way your way must be wrong. Instead of concentrating on writing cost-effective software these people appeared to be concentrating on following an arbitrary set of rules which I did not know existed. To them it appeared to be more important to follow a set of rules in a dogmatic fashion and produce software which is 100% "pure" (whatever that is) whereas my approach is totally pragmatic as I put results ahead of any arbitrary rules.

The PHP 4 manual simply described the mechanics of how to introduce Encapsulation Inheritance and Polymorphism into my code with a few simple rules. These were genuine rules which had to be followed otherwise the code wouldn't work. Imagine my surprise when several years later I was told that these were not the only rules that had to be followed, that I should also be following the ideas described in such documents as Object Oriented Design (OOD), Domain Driven Design (DDD), the SOLID principles and Design Patterns. I read those documents and I laughed. It was clear to me that they were written by a bunch of comedians who did not have my experience in developing database applications, and it was clear to me that if I followed their "advice" I would be swapping my very productive development environment for one which had more complications, less reusable code, and which would be a maintenance nightmare. I regard the aforementioned documents as "advice" and not "rules" for the simple reason that if I broke a real rule then my code would not work. As my code obviously works, and has done for over a decade, and has been easily migrated through PHP versions 5 and 7, there is absolutely no basis for calling it "wrong". If something works it cannot be "wrong" just as something which does not work cannot be called "right". If I ignore a piece of advice and do not suffer any measurable consequences, then what value can be placed on that advice? If I disobey a rule and nothing breaks, then how can that rule be justified? If the only problem which arises when I ignore one of these artificial rules is that I upset the delicate sensibilities of its followers then all I can say is Aw Diddums!

When someone tells me "you should be doing it this way" my immediate response is to ask "Why?" They need to prove that their way is better than mine by identifying all those areas where my approach produces problems and theirs does not. No such proof has ever been provided. All they can do is claim that their method is better, but that is always subjective, it is nothing but an opinion. They cannot offer any objective proof, something which can be measured scientifically. When they say "your method is wrong" I counter with "how can it be wrong if it works?" When they say "your code is difficult to read and maintain" I counter with "how can it be if I have successfully been maintaining and enhancing it for over a decade?"


My approach

One class per table

A classic example of where my critics say that I am breaking a golden rule is in my approach of having a separate class for each database table. I have never seen a rule written anywhere which says I cannot do this, and I have certainly never seen a list of problems which arise from disobeying this so-called rule. Not only have I never encountered any problems with my approach, I have actually avoided the problems which are inherent in their approach and have even provided facilities and cost savings which their approach cannot.

As far as I am concerned my practice of having a separate class for each table is in line with the following definition:

A class is a blueprint, or prototype, that defines the variables and the methods common to all objects (entities) of a certain kind.

If you look at the CREATE TABLE script for a table is this not a blueprint? Is not each row within the table a working instance of that blueprint? Is it not unreasonable therefore to put the table's blueprint into a class so that you can create instances of that class to manipulate the instances (rows) within that table?

It is important to take into consideration one very important fact when you are developing a piece of software which communicates with objects outside of itself - you need to model those objects and not some mythical objects which exist in a different plane. For example, an enterprise application may deal with objects such as "customer" and "product" which exist in the real world, but the application will NEVER communicate with real customers or real products, instead it will only communicate with information about those objects which exists in a database. A customer, who is a person, may have operations such as "stand", "sit", "walk", "run", "eat", "sleep" and "defecate", but these are irrelevant in a database application. Different products may have different sets of operations, but again these are irrelevant in a database application. Every piece of information on any object you can think of is held in a database object known as a "table" with each piece of data held in its own "column", and regardless of what real-world object a table represents, and regardless of the amount and type of data which is held for that object, every table in a database is subject to the same set of operations, and these operations are Create, Read, Update and Delete (CRUD).

In OOD you are supposed to use the idea of is-a to identify groups of entities which share a common set of characteristics, which includes properties as well as operations. This group identifies a "type" and each member of that group is a different implementation of that "type". You should then be able to create an abstract class to cover what is sharable in the group and then a separate subclass for each entity in that group to specify what is unique and therefore not sharable about that specific entity. For example, if you have objects A, B, C, D and E which are all of type "foo" then you can create an abstract class called "foo" which can be extended into separate subclasses for each of those objects. The abstract class called "foo" contains what is sharable while each subclass, using the power of inheritance, combines what is defined in the superclass with what is defined within that subclass. If I write software which is communicating with objects in a database, and every one of those objects is a table which shares common characteristics with all database tables, then surely it is obvious that I should create an abstract table class which contains the properties and methods which can be applied to any database table and then inherit this class into every concrete table class that may exist? In this way everything which can be applied to any unspecified database table can be defined once in the abstract class, and each concrete class need only define those things which are specific to the table which it represents. This use of an abstract class then opens the door to implementing the Template Method Pattern which is described as being a fundamental technique for code reuse.

Too many programmers apply this idea of is-a at entirely the wrong level. They encounter a table called "customer" and think to themselves "each customer is a person, so I must create a Person class and then extend it to create a Customer subclass". I'm afraid that this viewpoint is far too narrow for the following reasons:

If I have hundreds of tables in my database then the idea of creating a separate abstract class for each table which can then be inherited by only a small number of subclasses produces a minimal amount of reusable code. Instead I have just one abstract class to cover the concept of a non-specific table and a separate subclass for each physical table then I have. Which means that if I have hundreds of database tables then I have hundreds of subclasses which means I can share the contents of that single abstract class hundreds of times. The result is therefore a significant amount of reusable code instead of a minimal amount.

Enterprise applications are comprised of a number of user transactions (also known as units of work, use cases or tasks) where each transaction has a User Interface (UI) at the front end, one or more tables in a relational database at the back end, and some software in the middle which transports data between the two ends while applying any business rules. In a large application there can be thousands of transactions and hundreds of tables. With my previous languages I gradually progressed from using the 1-Tier Architecture through 2-Tier and eventually 3-Tier with its separate Presentation, Business and Data Access layers. With the UNIFACE language it was standard practice to create a separate component in the business layer for each database table, so I saw no reason why I should not continue with this practice and create a separate class for each database table so that each could then become an object in the business layer.

I have been told on more than one occasion that the "correct" and "approved" way of applying the principles of OOP is to start with Object Oriented Design (OOD) with its is-a and has-a relationships, compositions, aggregations and associations, then design all objects using these principles. The database is left till last and accessed through an Object-Relational Mapper (ORM) which is required in order to deal with the differences between the object structure and the database structure. As I did not know that these rules existed, let alone were obligatory, I did what had proved successful in the past and started with my database which I designed using the rules of Data Normalisation, then structured by software around the database as was taught in Jackson Structured Programming. This approach produced very good results in my PHP code, so I could see nothing wrong with it.

Other programmers may attempt to justify their criticisms of my approach by saying that I was self-taught, and therefore taught badly, instead of being properly trained in the mystic arts of OOP by someone who knew the "proper" way, the "correct" way, the "pure" way. Instead, after having read up on the mechanics of encapsulation, inheritance and polymorphism in the PHP manual, I used nothing but a mixture of my experience and plain common sense to add those concepts into my software in order to produce as much reusable code as I could. It should be noted that my use of an abstract class and the Template Method Pattern are both recommended in the following books:

Anybody who thinks that my usage of these two ideas is wrong ought to take it up with those authors.

My logic for creating an abstract table class which could be inherited by every concrete table class went as follows:

An abstract class cannot be instantiated into an object as it is devoid of essential details - it knows what properties/characteristics a database table may have, but it has no values for these properties/characteristics. In order to instantiate a table's object it is first necessary to inherit the abstract superclass into a concrete subclass, and it is the constructor of this subclass which provides all the missing details when it loads in the contents of the <table>.dict.inc file. The abstract table class deals with an unknown database table while each subclass deals with a specific database table with a specific set of characteristics.

When I first developed my code I did not start with an abstract class, instead I created a complete concrete class, without any inheritance, for a single database table, along with the six Controllers shown in Figure 1. I then copied this code into a second class file for a second database table. As you can imagine this produced a lot of duplicated code, so when I identified a block of duplicated code I looked for a way to define this code in a single place so that I could call this code in that single place instead of having to duplicate it. This is precisely why inheritance was invented, so I created a superclass to contain this code and added an extends statement to each table class. After moving all the duplicated code out of each subclass and into the superclass I found that the subclass contained nothing but the constructor. When I found the need to augment this inherited code with some specific code for a particular class I added some hook methods to the abstract class which could then be overridden in each subclass.

The first set of table classes I created by hand, but as I found myself simply transposing information from the database schema to a PHP script in order to define the properties of each table I decided to automate this process. I designed and built a separate piece of software called a Data Dictionary which allowed me to import details from the database schema into an application database, then export that information to produce two PHP scripts - a table class file and a table structure file. The logic behind having two separate files is that the import/export process can be rerun whenever the structure of a table changes, but only the table structure file will be overwritten. The table class file is never overwritten as it may have been updated by a developer to include some of the variant/customisable methods which are part of the Template Method Pattern.

I performed a similar refactoring process on my Controller scripts. I noticed that the only difference between the script for table #1 was exactly the same as the script for table #2 except for the identity of the table, so I changed the script to remove the hard-coded table identity and to accept it from a variable instead.

OO programmers often say that OO Design is incompatible with Database Design, which is precisely why I don't waste my time with it. Once I have designed a properly normalised database I don't have to design any classes to communicate with that database as I can automatically generate a class file for each table. Some people are mystified when they see one of these newly generated class files as there is nothing there but the constructor. "Where is the code?" they ask in a bewildered voice. When they see the word extends in the class definition the truth begins to dawn on them. By default there are no methods other than the constructor in a class as all the standard boilerplate code is inherited from methods which are defined in the abstract class. Each method call made by a Controller on a Model refers to a method which has been pre-defined in the abstract table class, and each method is an instance of the Template Method Pattern.

Because I don't use OOD I never end up with that problem called Object-relational Impedance Mismatch which then requires that abomination of a solution called an Object-Relational Mapper (ORM).

Datasets instead of columns

Another point to notice is that I never knew of the rule which said that each column in a database table should have its own separate property in the class, along with a pair of getter/setter methods to read and write its value. My experience of writing database applications for the previous 20 years told me that databases deal in datasets where each set can contain any number of columns and any number of rows, so I did the obvious thing and built into the abstract table class a single property called $fieldarray which could hold whatever dataset the object needed to handle at that time. This would allow different subsets or supersets of data to be used on insert and update queries, and would allow select queries to contain additional columns from other tables using JOINs.

Part of the data which is loaded in by the constructor is the $fieldspec array which contains the specifications for every column within that table. This then makes it possible to write a standard routine which uses those two arrays, one of field values and another of field specifications, to validate that the data which is supplied for a field actually matches its specification before it is allowed to pass through on its way to the database. Because this validation is performed automatically by the framework it is another section of boilerplate code which I do not have to add to each table class.

Forms families

When I started programming we used the name transaction to identify a unit of work which performed a task which was useful to the user, something which allowed him/her to carry out their business duties. When databases later introduced the concept of a database transaction this was renamed to business transaction or sometimes user transaction. Some design methodologies use the name use case or event, but in the RADICORE framework I use the short name task. There is a table called TASK, with a primary key of task_id, which has a separate entry for each task which is available in the application. There is another table called MENU which is used to split this huge list of tasks into options on menu buttons and a similar table called NAV_BUTTON which shows which options are available on navigation buttons when that task is active.

After having created a database table it is usual to create one or more tasks to maintain the contents of that table. The most common series of tasks, what I refer to as a family of forms, is shown in figure 1:

Figure 1 - A typical Family of Forms

infrastructure-07 (1K)

In my early COBOL days this family would be merged into a single large component (also known as a user transaction). There are still some programmers today who regard all six of the above transactions to be a single use case, so they build a single controller for that use case. The problem with this outdated approach is that each of those six parts has a different screen and different behaviour. Each part is called a "mode", so each time it is called you have to identify which mode - either LIST, SEARCH, INSERT, UPDATE, DELETE or ENQUIRE - is actually required so that the controller exhibits the correct behaviour. This has several problems:

In order to avoid these problems I decided to break down the single large multi-mode component into a series of single-mode components, as discussed in Component Design - Large and Complex vs. Small and Simple. I therefore have a separate user transaction for each mode - LIST, SEARCH, INSERT, UPDATE, DELETE and ENQUIRE. Each of these reference the same table class in the business layer. This arrangement has the following advantages:

Reusable XSL stylesheets

When I originally took the decision to rebuild my previous COBOL and UNIFACE frameworks using PHP I chose to create all my HTML pages by extracting the necessary application data into an XML file which could then be transformed into HTML using XSL stylesheets. I had first become exposed to XML and XSL while working on my last UNIFACE project, but while it made the construction of XML documents very easy its only use of XSL was to transform one XML document into another XML document with a different structure. UNIFACE was originally designed as a language for creating desktop applications, and the ability to generate HTML pages was added on years later as an afterthought. However, I thought that the mechanism it chose to generate web pages was far too clunky, and after having studied what could be done with XML and XSL I concluded that it would have been much better if they had gone down that route. I decided to put that theory into practice by going down that route in my new framework. It was a decision that I never regretted as, with lots of refactoring over several years, it has enabled me to build large numbers of different web pages using just a small number of reusable XSL styleheets. For example, in my ERP application I have over 3,500 web pages which are produced from just 12 XSL stylesheets. This is in contrast with those people who manually create a separate XSL stylesheet for each web page in order to identify which piece of data goes where and with what control.

I found this method of building web pages far better than that which I had seen in all those code samples I had found on the internet which involved outputting fragments of HTML code during the execution of the script. This meant that if you suddenly decided to jump to another page instead of completing the current one you would invariably encounter the "headers already sent" error. Using the XML/XSL method you can wait until all the processing is complete, and then you can pass the Models to a standard process which extracts the data from those models, inserts it into an XML document, then performs the transformation using the specified XSL stylesheet. It does not matter which order the data appears in the XML document, just that it is there.

Some people may be wondering how I can possible create 3,500 different web pages from over 400 different database tables using just 12 XSL stylesheets. If you look at the screen layouts in my library of Transaction Patterns you should see that each page can be broken down into a series of areas or zones each of which is populated with data from different sources. The menu bar uses data from the MNU_MENU table, the title bar uses data from the MNU_TASK table and the MNU_TASK_QUICKSEARCH table, and the navigation bar uses data from the navigation_button table. While the pagination, scrolling and action bar areas are generated by the framework at runtime, the data area(s) is/are provided by whatever Model classes are used in that particular task. In order to tell the XSL stylesheet which element of application goes where on the web page I use a small screen structure file whose information is copied into the XML document. The identity of that file is specified in the component script which is the starting point for each task in the application.

Transaction Patterns

When you have written as many user transactions as I have where each transaction performs one or more operations on one or more database tables and displays the results in an electronic form on a monitor, either as a compiled form or an HTML page, you should be able to see some patterns emerge. For example, once you have a built a family of forms for one table, how much effort would be required to build the same family of forms for another table? The idea was to identify what was similar and what was different between the two families so that I could encapsulate the similarities in some sort of reusable module. As documented in What are Transaction Patterns I managed to split each form into the following categories:

The next step was to find a way to create reusable code for each of these categories. This I achieved as follows:

In the six forms shown in the forms family it should be noted that while each of them has a separate Controller the LIST1 form uses its own XSL stylesheet which displays application data using the List View while the other 5 share the same XSL stylesheet which displays data using the Detail View. All six of these tasks also use the same Model component.

I originally created the scripts for each application task by hand, but after a while I constructed a new piece of software which could do this automatically. I created a library of Transaction Patterns, which encapsulate a particular combination of structure and behaviour, then created a mechanism whereby I could link a Pattern with a database table to identify the missing element, the content, and at the press of a button this would generate the necessary scripts. I also made this software add the task to the MENU database so that it could be run immediately.

Every task in a database application, no matter how simple or how complex, has exactly the same characteristics:

  1. It performs one or more of the CRUD operations on one or more tables. This requires code to transport data from the User Interface (UI) to the database, or to retrieve data from the database and transport it to the UI. Each of these CRUD operations has its own method defined in the abstract class:
  2. It may also deal with business logic or task-specific behavior.

An experienced database programmer should be able to see that the code for item #1 in the above list is virtually the same regardless of the contents of the database table. This is often referred to as boilerplate code. On the other hand the code for item #2 is unique for each table or each task. Instead of having to duplicate the boilerplate code in each class it would be very useful to find a mechanism which allowed you to define such code in a single reusable module, and then refer to that module as and when required. It would also be useful if such a mechanism allowed the insertion of any additional unique or custom code. This is where the Template Method Pattern comes into play. Each of the four methods in item #1 above has been implemented as a Template Method in the abstract table class which means that each will execute its own set of sub-methods, some of which will be invariant with fixed implementations while others will be variant/customisable methods which can be defined in each subclass as and when required.

Although I started with just the six Controllers shown in Figure 1, this has been expanded to 50 to cater for the more complex situations which I encountered while developing a large enterprise application. Each of the concrete table (Model) classes shares the same set of public methods which are inherited from the abstract table class, so this automatically provides for a huge amount of polymorphism. When you consider that polymorphism is required before you can make use of Dependency Injection, which is another way of increasing the amount of reusable code, this should be considered as being a good idea. Each of my 50 Controllers uses these methods to communicate with a Model which means that ANY Controller can be used with ANY Model. So if I have 50 Controllers (one for each Transaction Pattern) and 400 Model classes this produces a grand total of 50 x 400 = 20,000 (yes, TWENTY THOUSAND) opportunities for polymorphism.

I do not use a Front Controller in my framework, so the URL for each task points directly to a separate component script in the file system. This is a very simple script which does nothing but identify the different components that are required to implement that task, such as in the following:

<?php
$table_id = "person";                      // identify the Model
$screen   = 'person.detail.screen.inc';    // identify the View
require 'std.enquire1.inc';                // activate the Controller
?>

Each Controller script is then able to instantiate the relevant table class into an object so that it can make the method calls which are relevant to that Controller using code similar to the following:

require "classes/$table_id.class.inc";
$dbobject = new $table_id;

$fieldarray = $dbobject->getData($where);

$fieldarray = $dbobject->insertRecord($_POST);

$fieldarray = $dbobject->updateRecord($_POST);

$fieldarray = $dbobject->deleteRecord($_POST);

As you can see this uses my own version of Dependency Injection.

My methodology may not be the same as that used by most developers, but surely it is the results which are more important? There was a study in 1996 in which the productivity of two teams was compared to find out why one team was twice as productive as the other. The study broke down the code which was written into various categories - business logic, glue code, user interface code, database code, etc. If one considers all these categories, only the business logic code had any real value to the organisation. It turned out that Team A was spending more time writing the code that added value, while team B was spending more time gluing things together. With my approach I can create a table in the database, import it into my Data Dictionary, then generate both the class files and user transactions for the family of forms shown in figure 1 at the press of a button and be able to run those transactions within 5 minutes, all without having to write a single line of code - no PHP, no HTML, no SQL. This means that the developers have to spend far less time in writing boilerplate code, which leaves them with far more time to spend on the code which has actual value to the organisation - the business logic.


Criticisms of my approach

  1. Real OO programmers don't do it that way.

    That is because they were deliberately taught NOT to do it that way by someone who did not understand how databases work and how to write code which interacts with a database. If these teachers consider that doing it "that way" causes problems, then where is this list of so-called problems published? If doing it "that way" does not cause any actual problems then how exactly can it be wrong?

  2. You are not following the rules of Object Oriented Design (OOD).

    This is because they are not genuine rules, just personal preferences. If I break a genuine rule then my code will not work. If I break these artificial rules then not only does my code NOT break, it actually works better. OOD was not formulated with database applications in mind, therefore it does not provide an optimal solution. Using two different design methodologies - one for the software and another for the database - would be a recipe for disaster. I always design the database first using the rules of normalisation, then I skip OOD completely and force my software structure to follow my database structure. In that way I avoid the problem of Object-relational Impedance Mismatch which then requires that abomination of a solution called an Object-Relational Mapper (ORM).

    Writing database applications requires a knowledge of how databases work, yet few OO developers understand this. They start with OO theory and then try to apply that theory in different scenarios, then complain when difficulties arise. I have seen such excuses as:

    The advantage I have is that I worked with a variety of database systems - hierarchical, network and relational - for several decades using non-OO languages, so I knew how to design databases and write database applications. When I switched to an OO-capable language all I had to do was learn how to leverage the new concepts - encapsulation, inheritance and polymorphism - in order to write programs with more reusability.

    Closely related to OOD is Domain Driven Design (DDD) with even more artificial rules which I choose to ignore. When writing a large enterprise application which consists of a number of distinct subsystems/domains I do not need to embark on a separate design process for each of those subsystems/domains for one simple reason - while each of those domains is different they all share one common attribute in that they are ALL database applications, and I have learned to build database applications from a common set of patterns. This is explained more in Why I don't do Domain Driven Design and The Template Method Pattern as a Framework.

  3. This results in a lot of duplicated code - you write the same code for each table (select, insert, update, delete) again and again.

    Then you don't understand how to use inheritance and the Template Method Pattern. All code which is common to all database tables is defined once in the abstract table class and then inherited by every concrete table class. Every piece of code which can be shared is defined once within the abstract class. Every piece of code which is specific to a particular table is defined within that table's subclass. If code is defined once and shared multiple times then where exactly is the duplication?

  4. You should use object composition instead of inheritance.

    This idea is propagated by those who don't understand how to use inheritance properly. Inheritance only causes problems when it is overused, such as to create deep inheritance hierarchies, or to inherit from one concrete class to create a different concrete class where some methods in the superclass are not appropriate in the subclass. This leads to such complaints as Inheritance breaks Encapsulation. Problems such as these can be avoided by only inheriting from an abstract class, which is precisely what I am doing.

    This is discussed further in What is/is not considered to be good OO programming.

  5. You just don't understand what OO means.

    This complaint was explained in the following ways:

    Abstract concepts are classes, their instances are objects. IMO The table 'cars' is not an abstract concept but an object in the world.
    Classes are supposed to represent abstract concepts. The concept of a table is abstract. A given SQL table is not, it's an object in the world.

    This complaint is completely bogus for the simple reason that what I have implemented actually follows what has been written:

    While the structure of each database table is different the way that each table is handled is exactly the same. When a concrete table class is instantiated into an object there is code in the constructor which loads in metadata from the corresponding dictionary file into the instance. This metadata is used by the framework at runtime to guide the processing of that table. For example, the $fieldspec array is used by the standard validation class to check that each piece of data can be inserted into the database without causing an error. The parent relations array can be used when constructing SELECT queries while the child relations array can be used for referential integrity checks when deleting a record.

    As far as I am concerned Object Oriented Programming (OOP) requires nothing more that writing programs around objects, thus taking advantage of encapsulation, inheritance and polymorphism to increase code reuse and decrease code maintenance. The efficacy of your OOP implementation can be measured in the levels of reusability that you achieve.

    This is discussed further in What OOP is NOT and What OOP is.

  6. You wouldn't model people by creating a Person class and subclass it for each new person would you? The concept of a Person is abstract, a given person is not.

    Nobody in their right minds would create a separate subclass for each row in a table. Each class provides a blueprint for each instance of that class just as each table definition provides a blueprint for each row in that table. In a database it is only the concept of an unspecified table which is abstract while a particular table with a particular name and particular structure and particular business rules is a concrete instance of that abstraction. Just as a Person table can hold many rows, one for each person, my Person object is capable of having many instances, one for each person. I do the same for every table in my databases - one table, one class, where each instance of that class can hold as many rows as is necessary. This follows the Table module pattern which Martin Fowler wrote about in his book Patterns of Enterprise Application Architecture. He also has Class Table Inheritance and Concrete Table Inheritance, but as these talk about hierarchies of tables, which I do not have, I do not use them. I do not have table hierarchies in my software as there are no such table hierarchies in the database. The use of relationships may indicate that one table is related to another, but this in no way forces me to go through one table in a relationship in order to get to the other. Each table can be treated as an independent object - in fact it has to be for insert, update and delete operations - but for read operations it is possible to combine data from several tables by using JOIN clauses in the SELECT query.

  7. Having a separate class *instance* is good OO, having a separate *class* is bad OO, since you lose all the potential benefits of low maintenance.

    How can I create an instance of a class without having a class to start with? I cannot create an instance of an abstract class and then supply it with the information it needs as the rules of OO explicitly prohibit instantiating an abstract class into an object. And you have the nerve to tell me that I don't understand OO!

    As for losing the potential benefits of low maintenance, you are talking out of the wrong end of your alimentary canal. All the common code is contained within a single abstract table class, thus following the DRY principle, and each of my 400 concrete table classes contains only that code which is specific to that table while sharing all that code which it inherits from the abstract class.

  8. This leads to a problematic dependency between the DB and the class.

    How so? While it is true that there is a dependency between the Business layer and the Data Access layer what exactly is the problem? Every database application ever written has this same dependency, so what exactly is the problem?

  9. You should not have to create a new class for each database table.

    Why not? Each table is a separate entity in the database, with its own structure and its own business rules, so why shouldn't I create a separate class to encapsulate this information? It has to go somewhere, so where would you put it? Besides, creating a new table class is very easy with my framework:

    Once I have created the class for that table I can then use the generate PHP script facility in my Data Dictionary to create as many user transactions as is necessary to deal with that table. Each transaction can be run immediately from the framework. These will perform the basic operations after which the developer can add in as many customisations as is necessary.

  10. You have to recode both the table and the class every time you change the table.

    No I don't. If I need to change a table's structure I deal with it in three simple steps:

    I do NOT have to do any of the following:

    You may have difficulties with your implementation, but remember that my implementation is totally different, which it had to be in order to eliminate those difficulties.

  11. You are not using the right design patterns.

    Every newbie programmer is taught that "design patterns are good", so they do the stupid thing and try to implement as many design patterns as possible. They have their favourite patterns and cannot understand why everyone else does not use the same ones. There are even arguments as to how each pattern should be used. Take a look at the criticisms against my implementation of the MVC pattern as an example.

    There is no such thing as a set of "right" design patterns which everyone should use. The correct approach is not to pick a collection of patterns and then try to force them into your code, it is to write code that works, then refactor it into those patterns which are appropriate for your particular circumstances.

    I do not pick patterns in advance and then attempt to write code which implements them. Instead I write code that works, and after I have got it working I refactor it as necessary to ensure that the structure and logic are as sound as possible. If the code then appears to match a particular pattern then that is pure coincidence - it is more by accident than design (pun intended!) This follows the advice of Erich Gamma, one of the authors of the Gang of Four book who, in this interview, said the following:

    Do not start immediately throwing patterns into a design, but use them as you go and understand more of the problem. Because of this I really like to use patterns after the fact, refactoring to patterns.

    In case you think that I don't use design patterns at all you would be mistaken. If you bothered to look closely at my framework you would see the following:

    This topic is discussed further in You are using the wrong design patterns and You don't understand Design Patterns.

  12. Your implementation is not OO, it is procedural.

    Too many people seem to think that code which does not follow their definition of OOP is not "proper" OOP at all, therefore it must be procedural. In this context the term "procedural" is used as an insult. Some of these criticism are explained in In the world of OOP am I Hero or Heretic?. A more detailed response is contained in What is the difference between Procedural and OO programming?

  13. You have created a God Object.

    Some people seem to think that just because my abstract table class is bigger than what they are used to that it is automatically bad. They seem to think that there is a rule which says that a class cannot have more than N methods, and each method should not have more than N lines of code (where N is a different number depending on to whom you talk). As far as I am concerned this rule was only invented to cater for those people who are so intellectually challenged they cannot count to more than 10 without taking their shoes and socks off. I am obeying the rule of encapsulation which states quite clearly that when you have identified an entity you create a class for that entity which contains ALL the properties and ALL the methods that the entity requires. Note that as I use the 3-Tier Architecture each table class contains only business logic - all data access logic and presentation logic are in separate components. I am following the Single Responsibility Principle (SRP), so how can I be wrong?

    Besides, this class cannot be used to create a God Object as it is an abstract class and cannot be instantiated into an object. This class is inherited by each concrete table class, of which I now have over 400, so each table class has its own object. There is no such thing as a single object which handles all database tables.

    The definition of a God Object also states that it contains a majority of the program's overall functionality, and in my book "majority" means "greater than 50%", and after counting all the lines of code in my framework I can report that it only contains 17%. That is measurable proof, so your opinion is not worth the toilet paper on which it is written. This also invalidates the claim that I have multiple God classes.

    This topic is discussed in more detail in You have created a monster "god" class and A class with multiple methods has multiple responsibilities.

  14. You have an anemic domain model.

    People look at an example of one of my concrete tables classes which starts off by containing nothing more than a constructor and because it is so small they surmise that it must be anemic. Perhaps they don't notice the use of the word "extends" which allows it to incorporate code from a huge abstract class. An anemic domain model is supposed to be one which contains data but no methods to process any business rules, but if you opened your eyes and looked close enough you would see that all the necessary methods, which includes data validation, are defined in and inherited from the abstract table class.

    This topic is discussed in more detail in You have created an anemic domain model.

    Can anyone explain to me how some people looking at my table classes consider that my abstract table class is a God Object which does too much while my concrete table classes are all anemic as they do too little? Surely these two accusations are mutually exclusive?

  15. Your implementation is too simple.

    The full complaint, as explained in OOP for Heretics, was as follows:

    If you have one class per database table you are relegating each class to being no more than a simple transport mechanism for moving data between the database and the user interface. It is supposed to be more complicated than that.

    Who says? Surely if I make something more complicated than it need be I would be violating the KISS principle? You must be a member of the Lets's-make-it-more-complicated-than-it-really-is-just-to-prove-how-clever-we-are brigade. The alternative idea, that of having a class which is responsible for a group of tables, is something I could never dream up in a million years. I have worked with databases for several decades, and just as the DBMS itself treats each table as a separate entity with its own name, structure and set of business rules, then I follow the principles of OOP and encapsulate that structure and all those rules in a separate class. This simple approach has enabled me to identify and take advantage of a wide range of benefits which are explained below.

    While it is true that each table class, when it it first created, can only handle the basic transportation of data between the UI and the database (which includes all primary validation) my implementation of the Template Method Pattern allows for any additional complexity to be covered by inserting code into the relevant hook methods within each subclass.

  16. This approach is only useful for simple CRUD applications.

    Incorrect. This approach is useful for any CRUD application whether simple or complex. Every program in a database application will perform one or more CRUD operations on one or more tables and execute any number of business rules, so the only difference between a "simple" and a "complex" program is the number of tables it accesses and the amount of extra code required to deal with each of those business rules.

    If my framework could not offer anything other than the six patterns which are part of this family of forms then you might have a point. However, my long experience with developing enterprise applications which cover a variety of different domains and which contain user transactions of varying complexity has enabled me to create a library of 50 Transaction Patterns which contain steps comprised of a mixture of invariant and variant methods. It is very easy to create a starting transaction from any of these patterns simply by pressing buttons and without having to write a single line of HTML, SQL or PHP code. This will enable you to run the transaction with basic behaviour which you can then customise to your heart's content. Additional business rules can be processed simply by inserting the relevant code into any of the available "hook" methods.

    It is a feature of my framework that every method called from a Controller on a Model is an instance of the Template Method Pattern. This is because every concrete table class inherits from the same abstract table class which consists of nothing but a huge collection of template methods. While the abstract class contains the implementation for each of the invariant methods, each variable/customisable method can have a totally separate implementation in each subclass.

  17. I tried this approach once, but I couldn't get it to work.

    Then your implementation was obviously faulty. Mine was not. Perhaps you need to rethink your ideas on how OOP should be implemented and concentrate, as I do, on producing results instead of following arbitrary rules.


Arguments against having a single class for multiple tables

There are far too many programmers who have been taught to create a separate class for each real-world entity, but those who are experienced in the development of database applications understand that, following the rules of Data Normalisation, a complex entity may need to be split across several tables in order to provide a data structure that can be accessed efficiently. For example, take the structure of a Sales Order which has its data split across the group of tables shown in Figure 2:

Figure 2 - a compound "order" object

order-object (2K)

As well as creating a single Model class to deal with all 11 tables the inexperienced programmer is also taught to create a single Controller to handle all the operations which can be performed on this group. I disagree with both of these ideas for the simple reason that they greatly reduce the amount of reusable code that can be produced, and as the purpose of OOP is supposed to be the production of more reusable code, as the more reusable code you have then the less code you have to write, then using a design that produces less reusable code just indicates that the programmer has not grasped how OOP can be utilised to provide maximum benefits and is therefore wasting a golden opportunity. When such a programmer then has the gall to tell ME that my methods are wrong I just laugh at their ignorance. Sometimes I laugh so hard that I can feel the tears running down my trouser leg.

In my world I would never create a class to deal with that many tables. Having designed and developed database applications for over 20 years I know for a fact that each of those tables is a separate entity in the database which is accessed using the same set of CRUD operations. The concept of having to go through a "group" table in order to access any table in that group simply does not exist, so if this concept does not exist in the database then why should it be a good idea to support that non-existing concept in your software?

A huge disadvantage in having a single class which is responsible for multiple tables is that you have to have separate methods for each table, or combination of tables, so that you can identity which operation you can perform on which table. This means that you have to create a unique set of method names for each table, and when you create unique method names instead of sharing common method names you can kiss goodbye to the benefits which can be obtained through polymorphism.

Being both a realist and a practical person my method involves treating each table as a stand-alone entity which has its own class, and because each of my concrete tables classes inherits from the same abstract table class they share those methods which support the standard CRUD operations. I would also create a separate set of tasks for each table so that the user can select the right task for each business process he/she wishes to perform. For the 11 tables in Figure 1 above I would generate 66 tasks as follows:

The observant among you should notice that I am using just 8 patterns to provide the functionality for 66 tasks. Each of those patterns uses the same Controller script which calls a standard set of methods on its target Model(s). Each of the 66 tasks has its own component script which identifies which Controller to use with which Model(s).

In case you don't understand the difference between the LIST1 and LIST2 patterns let me explain:

The benefits of my approach should be obvious. I do NOT have to manually create a massive controller to handle the operations which can be performed on that group of 11 tables as I can make use of the reusable controllers that come supplied with the framework. I do NOT have to create a complex class which is responsible for the business rules and CRUD operations for 11 different tables as my separate-class-per-table approach means that each class is responsible for just one table. I do NOT have to create separate methods to access each table as I can use the standard methods which are inherited from the abstract table class.

If you read the book Design Patterns: Elements of Reusable Object-Oriented Software you will see that my approach is actually recommended:

There are some people who think that my method of creating an ORDER_HEADER record and its associated ORDER_ITEM records in separate tasks is wrong because an order without any items is surely invalid. I agree, but in this context what exactly does "invalid" mean? The bottom line is that an order without any items cannot be progressed to the next stage in the order processing workflow, so what is the best way to deal with that? Ever since the 1980s whenever I have a document which consists of a "header" record and one or more "item" records I have a column on the "header" record called document_status which always starts with the value "Pending". A document with that status can have its details modified by the user, but it cannot be advanced to the next stage. It is only when the user has finished assembling that document that the user then changes the status to "Complete", but this status change will not be allowed unless certain conditions are met, the minimum of which is that there is at least one item. Once the document status has been changed to "Complete" the following rules come into force:

  1. The document details cannot be amended.
  2. The document may be advanced to the next stage. This usually involves a change in status, and may involve other processing.

For example, a large sales order may have to be authorised by a supervisor before it can be processed further, and that further processing may involve the order items being added to a picklist or perhaps being sent to a supplier.


Arguments against having a multiple classes for a single table

The Command Query Responsibility Segregation (CQRS) pattern deals with the notion that you can use a different model to update information than the model you use to read information. For some situations, this separation can be valuable, but beware that for most systems CQRS adds risky complexity. The above article contains the following statements:

The mainstream approach people use for interacting with an information system is to treat it as a CRUD datastore. By this I mean that we have mental model of some record structure where we can Create new records, Read records, Update existing records, and Delete records when we're done with them. In the simplest case, our interactions are all about storing and retrieving these records.

As our needs become more sophisticated we steadily move away from that model. We may want to look at the information in a different way to the record store, perhaps collapsing multiple records into one, or forming virtual records by combining information for different places. On the update side we may find validation rules that only allow certain combinations of data to be stored, or may even infer data to be stored that's different from that we provide.

As this occurs we begin to see multiple representations of information. When users interact with the information they use various presentations of this information, each of which is a different representation.

Note that this definition of CQRS is an extension of the Command-Query Separation (CQS) pattern which was devised by Bertrand Meyer as part of his pioneering work on the Eiffel language which states that:

Every method should either be a command that performs an action, or a query that returns data to the caller, but not both. In other words, asking a question should not change the answer. More formally, methods should return a value only if they are referentially transparent and hence possess no side effects.

It should be obvious from my design that because I use methods which mirror the CRUD operations which can be performed on any database table on a one-for-one basis that a call to the getData() method does nothing but issue an sql SELECT query which does not alter the database. THis therefore automatically satisfies the above principle.

There are some people, however, who seem to take great delight in expanding or stretching the words in a principle and end up changing its meaning entirely. The CQS principle talks about having different methods for commands and queries, which to me implies different methods in the same object, yet some people like to go one step further and put those methods into different objects. This to me is a step too far.

The idea that you need different Models to provide different representations of the data tells me that he doesn't understand how the Model-View-Controller design pattern is supposed to work. In this pattern the Model does nothing but output raw data while it is the View which formats that data into the representation required by the user. The same Model can be used with any number of different views to provide an equal number of different representations. There are many ways in which a Model's data can be incorporated into a web page, but how that data is presented is of no concern to anything but the View. If I wish to create a task which outputs data to a CSV file then I construct it from either the OUTPUT1 or OUTPUT4 patterns. If I wish to create a task which outputs data to a PDF document then I create it from either the OUTPUT2 or OUTPUT3 patterns. This is without the need to create a new Model. I even have specialist pattern to create address labels.

The idea that you would need separate classes to deal with separate operations is a non-starter for me as it violates the principle of encapsulation which states that a class should contain ALL the data for an entity and ALL the operations which can be performed on that data. The only time I create a subclass for one of my concrete table classes is when I want to have totally different code in one or more "hook" methods in order to provide different behaviour in a different task. This is why I have a dict_table class to perform the standard processing, a dict_table_s01 class to import data from the application database into my Data Dictionary, and dict_table_s02 class to export that data from my Data Dictionary and write it to a <table>.dict.inc file.


Advantages of my approach

Many people seem to be annoyed at my heretical approach to OOP, but I don't care. It has enabled me to avoid a lot of the unnecessary coding that other approaches seem to require, and to provide a framework that takes care of a lot of the standard functionality that is needed in a database application. Thus I can achieve more with less, and isn't that supposed to be the benefit of using OOP in the first place? Below is a list of the areas in which I can save time:

  1. I don't need to waste any time with OOD or DDD

    I do not use two incompatible design methodologies in my applications, so my software structure is always in sync with my database structure, which I design using the rules of data normalisation. This avoids the problem known as Object-relational Impedance Mismatch which then means that I do not have to work around that problem by using that abomination of a solution called an Object-Relational Mapper (ORM). Prevention is always better than cure.

  2. I don't need to waste time in designing class hierarchies

    The only objects that my business layer has to deal with are objects in the database, which are tables. These do not have hierarchies in the database so why should I have hierarchies in my software? The only inheritance I need is to inherit all the standard code from a single abstract table class.

  3. I don't need to waste any time choosing which design patterns to use

    As far as I am concerned all the necessary design patterns have been built into my framework. I started off by using the 3-Tier Architecture, but because I ended up by splitting the presentation layer into two separate components a colleague pointed out that this was also an implementation of the MVC design pattern. This resulted in a four-part structure which is shown in Aren't the MVC and 3-Tier architectures the same thing? The four components are as follows:

    Because of my approach of having a separate class for each database table I was able to create an abstract table class to contain the characteristics which are common to every database table while each concrete table class contains the actual details for a specific database table. Because I recognised that each task starts off by performing one or more CRUD operations on one or more database tables and then includes additional code to deal with the specific requirements of each table I was able to implement each of these operations as a Template Method in the abstract class which then allows additional code to be inserted into any subclass by using one of the pre-defined hook methods. The use of this pattern then provides access to a large amount of boilerplate code which has been defined in the abstract class and which can be made available to each subclass through inheritance instead of duplication.

  4. I don't need to waste time in building each table class from scratch

    Every concrete table class inherits vast amounts of standard code from my abstract table class, so each table class need only contain the specifics for that particular table. Each class file can be generated by the framework in two simples steps:

    If a table's structure ever changes all that needs to be done is to repeat the import and export process which will cause the structure file to be recreated. The class file will not be overwritten as it may have been modified to include code in customisable methods.

  5. I don't need to waste time in designing methods and properties for each table class

    Every method required by a Controller to communicate with the Model is defined within my abstract table class which is inherited by every concrete table class. Because it is inherited it does not have to be written.

    Because all the data, both incoming and outgoing, is held in an array of variables called $fieldarray, which is defined in the abstract table class, I don't have to spend time in defining a separate variable for each column.

    I do not need to define a separate method for each user transaction (also known as "use case" or "unit of work") as each transaction has its own entry on the MNU_TASK table. At run-time the user selects which task he wants to run from a menu of options, and that selection activates the relevant Controller which calls methods on the relevant Model. While the code with a Controller is standard the code within a Model's customisable methods can be set to whatever the developer requires.

  6. I don't need to waste time with writing code to validate user input

    The validation requirements for each column in a table are defined in the $fieldspec array which is made available in the <table>.dict.inc file which is exported from the Data Dictionary. All user input comes in as an associative array, such as $_POST, where the column values are keyed by the column name. The abstract table class then uses standard code to verify that each of the values in the data array matches that column's specifications in the specifications array.

    This topic is discussed further in How NOT to validate data.

  7. I don't need to waste time in writing code to perform standard SQL queries

    Anyone who has written SQL queries for any length of time will tell you that they all follow a standard pattern with the only differences being the table and column names. Anything which is standard and common to all database tables is therefore defined with the abstract table class, and this is merged with the specifics of a particular concrete table class at run-time in order to provide the information required to build a particular query. This information is then sent to the Data Access Object (DAO) for processing.

  8. I don't need to waste time with designing Controllers for each of my Model classes

    Having written thousands of user transactions over several decades I have noticed that these transactions can be broken down into patterns consisting of structure, behaviour and content. The structures can be provided by a collection of reusable XSL stylesheets, the behaviour can be provided by a collection of reusable Controllers, and the content can be provided by any one of the table classes. I have used this knowledge to create a library of Transaction Patterns which combine structure and behaviour for each user transaction, and I can use the Generate PHP Script feature of my Data Dictionary to create a working user transaction at the touch of a button by joining a particular Transaction Pattern with a particular table. This arrangement provides me with the following levels of reusability:

    The only "difficulty" with this approach is deciding which Transaction Pattern to use in the first place, but as the framework download contains lots of samples this should become easier with experience.

  9. I don't need to waste time with writing a separate Data Access Object (DAO) for each table

    I have seen such a thing proposed more than once, such as in Decoupling models from the database: Data Access Object pattern in PHP, and I am always surprised, even shocked, that so-called "professional" programmers can come up with such convoluted and complicated solutions. In my mind that is the total opposite of what should actually happen. In my methodology I *DO NOT* have a separate DAO for each table, I only have a separate DAO for each DBMS (MySQL, Postgresql, Oracle and SQL Server) where each can handle any table that exists. If you understand SQL you should realise that there are only four operations that can be performed on a database table - create, read, update and delete - so why would I duplicate those operations for each table when I can have a single object to handle any table?

  10. I don't need to waste time designing and building HTML documents for each web page

    For each user transaction the associated web page will follow the screen structure used by that particular Transaction Pattern, and all that is required is a small screen structure script to identify which column from each table goes where on that screen. This script is initially generated from the Data Dictionary, but can be amended afterwards. This file is fed into a View Object at run-time which writes it out to an XML document, along with all the data from the table class(es), which is then transformed into HTML using the designated XSL stylesheet.

  11. I don't need to waste time writing code for each of the components on a web page

    All the following areas in a web page are automatically supplied by and handled by the framework:

    If you have to write such code yourself then you know what a burden it can be. Now imagine not having to write such code to achieve all this functionality.

Because I can save time by NOT doing a lot of useless things I can then spend that time in doing useful things which add value to the application.

Additional Advantages of my approach

My critics love to tell me that because my approach to building software is different from theirs, that it doesn't follow the same rules as they have been taught, then it is not "right" so must be "wrong". If it is wrong then it must exhibit the attributes of wrong software such as being difficult to maintain or extend. The truth is completely the opposite. The fact that I have a separate concrete class for each database table which inherits a huge amount of sharable code from an abstract class has opened up a whole world of opportunities which would not have been available otherwise. All database operations are routed through the same code in the abstract table class and thereby through the relevant Data Access Object (DAO) for the current DBMS. This has enabled me to extend my framework as follows:


Conclusion

There are rules, there are guidelines, and there are personal preferences. Some of these personal preferences are the result of experience while others are the result of ignorance - they simply don't know any better. The "rule" that it is wrong to create a separate class for each database table was obviously devised by a person who learned OO theory before he learned how databases work, and has yet to come to grips with the fact that you have to tailor your solution to fit the problem domain. This is what Domain Driven Design is supposed to be about. I worked with databases for over 20 years before I learned OO, and I used that experience to help me write software that takes advantage of what encapsulation, inheritance and polymorphism have to offer. I never saw any descriptions of encapsulation which said that I could not create a separate class for each database table, so that's precisely what I did. This has never caused me any problems EXCEPT to attract the ire of certain individuals who claim that I am wrong yet fail to offer any substantial proof. As far as I am concerned my method works, so it cannot be wrong.

If a piece of software is communicating with tables in a database it makes perfect sense to me to have a separate software model for each of those tables which will aid in the communication, both to and from, with those tables. Each table has its own name, its own structure, its own relationships and business rules, so a separate class for each table would be the perfect way to encapsulate all of that information in a single place.

Producing Model objects which are all of the same "type" (i.e. database tables) means that I can put all the code which is common to all database tables in a single abstract table class which can then be inherited by every concrete table class. This is a lot of code which is inherited by every one of the 400+ tables in my application, so that is a lot of reusability. The use of an abstract table class then enables me to implement the Template Method Pattern which has long been regarded as a fundamental technique for code reuse.

No matter how large or small an enterprise application may be, each user transaction within it ends up by performing one or more operations on one or more database tables, and those operations are limited to Create, Read, Update and Delete. These operations are common to every database table therefore can be defined within the abstract table class. Because these methods are called by Controllers, and because they exist within every concrete table class, I have create a library of Controllers (called Transaction Patterns) which can operate on any table class within the application through that OO mechanism called polymorphism. If I have 50 Controllers and 400 Models this means that I have 50 x 400 = 20,000 (yes, TWENTY THOUSAND) opportunities for polymorphism.

When my critics tell me that I am breaking one of their precious rules they don't understand that breaking that rule has no adverse effect on my code. They cannot say "because you are doing that you cannot do this", so following that rule would not solve any problem for me. All it would do is force me to write additional code to achieve the same result, only differently, and if that effort is not rewarded with measurable benefits then in my universe that effort would be a total waste of time. I run a business where producing cost-effective software is the name of the game, so I prefer to spend my time in writing software that pleases my paying customers. I do not waste time in trying to write code that pleases the paradigm police with its purity as their definition of purity does not result in cost-effective software.

Not only does my approach NOT cause any problems, it actually opens up a lot of advantages which are completely closed to other methods.

My approach may ignore certain design patterns favoured by my critics, or their preferred implementations of those patterns, but there is no such thing as a definitive list of patterns, or fixed implementations of those patterns, which everyone must follow. Each programmer should be free to choose whatever patterns seem to be appropriate for their circumstances, and be free to implement them in whatever way they see fit. It is the end result that counts, not the effort that you expend to get those results. Being able to achieve better results than your rivals, and in shorter timescales, is what separates the competent from the cowboys.

Not only is it NOT wrong to have one class per database table, I firmly believe that it is the alternative approches which are wrong as they create more problems than they solve.


References


Amendment History

08 Feb 2021 Put Reusable XSL stylesheets into a section on its own.
Added Arguments against having a single class for multiple tables
Added Arguments against having a multiple classes for a single table
02 Apr 2020 Modified several sections to include references to the Template Method Pattern.
01 Sep 2018 Added Additional Advantages of my approach.

counter