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

How to decouple business logic from UI logic

Posted on 1st September 2021 by Tony Marston
Introduction
My programming background
My Object Oriented implementation
Moving common code to an abstract class
Data Dictionary
Business Logic and Data Validation
Reusable Views
Reusable Controllers
Transaction Patterns
Final Framework Structure
Rules that I break
References
Comments

Introduction

The question "How is it possible to decouple business logic from UI logic?" is one which I have seen asked many times by novice programmers, and I have seen many answers containing statements which I either consider as too vague or with which I do not agree. I do not claim that my answer to this question is perfect, just different, but I hope that it will provide a different viewpoint which may stimulate your thought processes.

The first step is to decompose that question into its component parts, then answer each of those part individually:

The answer to the main question can therefore be described as follows:

Presentation logic is that program code which receives the HTTP GET and POST requests, calls the Business layer to do the necessary processing, then takes the output of that processing and transforms it into the format required by the user. This is usually HTML, but could be CSV or PDF. The rules for creating each of these types of output are exactly the same regardless of what application data is being included, so it should be possible to create reusable components which implement these rules. The only additional data which is required is that which identifies which piece of application data goes where in the output.

Data Access logic is that program code which constructs and executes an SQL query using the api which is relevant for that DBMS. Note that in all cases the SQL query is a string which is constructed using standard rules, so it should be possible to create a reusable component which implements these rules. I have seen some developers advocate the use of a separate Data Access Object (DAO) for each table in the database, but in my opinion this is overkill. I personally have a separate DAO for each DBMS that I support - currently MySQL, PostgreSQL, Oracle and SQL Server - and these can handle any and all tables. This gives me the ability to switch my entire application from one DBMS to another simply by changing a single line in my config file. Some people say that this is wasted effort as organisations rarely change the DBMS which is used by their applications, but they are missing an important point - while it is rare to change the DBMS after an application has been installed, when using third-party software it is extremely useful if that software offers a choice of DBMS so the organisation can select the DBMS before it is installed.

My programming background

In my days as a COBOL programmer I wrote nothing but 1-tier applications simply because that was the only method that was being taught. After going on a Jackson Structured Programming course I saw the benefits of making the software structure follow the data structure. As a junior programmer whenever I saw myself writing code which was I had already written in another program I had no option but to duplicate that code in every other program simply because the project did not have any reusable libraries. When I eventually became project leader in another company I started to create a central library of this common code so that functions could be called instead of having to be duplicated. In 1985 I started working on a new project which required a sophisticated Role Based Access Control (RBAC) system, and while implementing my design I managed to upgrade my collection of reusable components from a library into a framework.

I was originally taught to write programs where the different user actions (list/browse, create, enquire, update and delete) were built into a single program, which then required methods to switch from one mode (user action) to another. This resulted in a small number of large and complex components. After discovering problems when trying to deal with multiple modes of operation in a single program I decided to extract the code for each mode and have it in its own separate program, thus resulting in a large number of small and simple components. This idea was so successful I later wrote about it in Component Design - Large and Complex vs. Small and Simple. This also meant that I could move all access control out of individual programs and into the framework, so if a particular user was not allowed to update or delete records from certain tables in the database it was much easier to deny access to the update and delete tasks for that table than to deny access to the update and delete modes within the single task which could everything for that table.

When my employer moved to UNIFACE in the early 1990s I became aware of the 2-tier structure. The UNIFACE language was built upon the Three Schema Architecture which was comprised of the External Schema (ES) which is what the end users saw, the Conceptual Schema (CS) which described the tables, columns and relationships in the application database, and the Physical Schema (PS) which dealt with the physical storage structure of a particular DBMS. It was first necessary to build the Conceptual Schema in the Application Model which was built into the UNIFACE Integrated Development Environment (IDE) where each database table was a separate entity within this model. I started using Uniface version 5 where end-user forms, which were compiled and could only run on the desktop, were built using the Graphical Form Painter (GFP) where each screen was built by specifying which entity (table) needed to be displayed, and within that entity frame which columns from that table table needed to be displayed. Using the GFP it was then possible to drill down into the various entity and column triggers to insert program code. This type of component therefore combined both presentation and business logic.

This changed in version 7.2 which introduced the 3-tier structure and also allowed the creation of web pages. This allowed all business logic to be defined in a new type of component called an entity service, and the new type of form component communicated with each entity service by using XML streams. Thus a single entity service could be shared by several form components. As well as being my first introduction to XML, I also discovered that UNIFACE included the ability to perform XSL transformations, but unfortunately this was limited to transforming an XML document into another XML document. I played around with XML and XSL and discovered that it was also possible to transform XML into HTML using XSL templates. Unfortunately UNIFACE used a different and, in my humble opinion, a more clunky and inferior method of producing web pages, and this encouraged me to write Using XSL and XML to generate dynamic web pages from UNIFACE.

I was involved in only one UNIFACE project which required web pages, but it was an unmitigated disaster. I recognised that web applications were the way of the future but that UNIFACE was nowhere near the best language for the job, so I decided to switch to a better language. As I had already been using a home computer for several years I decided to teach myself a new language and become proficient in it before seeking employment using that language. I had a brief look at Java but I did not like what I saw. When I came across PHP I was struck by the fact that it had relatively simple syntax, yet was powerful and flexible. Having a good online manual and access to a multitude of books and online tutorials meant that I could learn in my own time and at my own pace very easily. It was also an advantage that all the software components which I needed - PHP (version 4 at the time), the Apache web server and the MySQL database - could all be downloaded for free.

My Object Oriented implementation

PHP was the first language I ever used which enabled this new programming style called Object Oriented Programming (OOP). Although I had read a few articles which attempted to describe what it was and how to implement it, I found that these were too full of academic theory and lacking in real substance to be of any practical use, so I ignored them. I was also completely unaware that there were huge collections of rules, principles, practices and patterns which every OO programmer was supposed to follow, so I simply relied on my 2 decades of experience in designing and building enterprise applications, plus what I could learn from the PHP manual, the few books which I had purchased, and some online tutorials. After learning the basics I decided my first step was to build a new version of the framework which I had previously built in both COBOL and UNIFACE with the following attributes:

The first thing I noticed when using classes and objects was that OOP programming is inherently 2-tier. How so? When you write a class which represents the model of an entity which is of interest to the application you MUST have a separate piece of code which instantiates that class into an object, then calls methods on that object. The model of an application entity therefore exists in the Business layer of the 3-Tier Architecture while the code which called its methods exists in the Presentation layer.

In UNIFACE each component in the Business layer was built around an entity in its Application Model, and each entity represented a single table in the database. The idea of having a single entity responsible for more than one database table was just not possible, which is why I stuck with the philosophy of having a separate class for each database table even though my critics insisted that this was NOT how it was done. Having built hundreds of user transactions in the previous decades I also knew that every transaction, no matter how it is described to the user, does nothing more than execute one or more of the CRUD operations on one or more database tables.

I had written a development framework in each of my prior languages where the framework provided standard functionality which left the developer to concentrate on the application components, so I rewrote this framework in PHP (refer to RADICORE) and improved it by incorporating whatever new capabilities I could squeeze out of the new language. I started by creating a table class which contained methods which could handle each of the CRUD operations which I called insertRecord(), getData(), updateRecord() and deleteRecord() respectively. Each of these public methods sets in motion a chain of internal methods as shown in the following table:

public methodinternal methods
deleteRecord ($rowdata)
  1. _cm_pre_deleteRecord ($rowdata)
  2. isPkeyComplete($rowdata, $this->PkeyNames)
  3. _dml_ReadBeforeUpdate ($where, $reuse_previous_select)
  4. validateDelete ($rowdata)
  5. deleteRelations ($rowdata)
  6. _dml_deleteRecord ($rowdata)
  7. _cm_post_deleteRecord ($rowdata)
getData ($where)
  1. $where = _cm_pre_getData ($where, $where_array, $parent_data)
  2. isPkeyComplete ($where_array, $this->PkeyNames)
  3. $where_str = _sqlAssembleWhere ($where, $where_array)
  4. $data_raw = _dml_getData ($where)
  5. $data_raw = _processInstruction ($data_raw)
  6. $data_raw = _cm_post_getData ($data_raw, $where)
  7. For each row in $data_raw call getForeignData($rowdata, $rownum)
insertRecord ($rowdata)
  1. _cm_getInitialData ($rowdata)
  2. _cm_pre_insertRecord ($rowdata)
  3. $insertarray = _validateInsertPrimary ($rowdata)
  4. _cm_commonValidation ($insertarray, $rowdata)
  5. _cm_validateInsert ($insertarray)
  6. _dml_insertRecord ($insertarray)
  7. _cm_post_insertRecord ($insertarray) (if $this->errors is empty)
  8. _cm_post_insertRecord_with_errors ($insertarray) (if $this->errors is not empty)
updateRecord ($rowdata)
  1. _cm_pre_updateRecord ($rowdata)
  2. $updatearray = _validateUpdatePrimary ($rowdata)
  3. $originaldata = _dml_ReadBeforeUpdate ($where, $reuse_previous_select)
  4. _cm_commonValidation ($updatearray, $originaldata)
  5. _cm_validateUpdate ($updatearray, $originaldata, $method)
  6. _dml_updateRecord ($updatearray, $originaldata)
  7. _cm_post_updateRecord ($fieldarray, $originaldata) (if $this->errors is empty)
  8. _cm_post_updateRecord_with_errors ($insertarray, $originaldata) (if $this->errors is not empty)

Note that this is different from the method employed by other programmers who have separate public methods called load(), validate() and store(). This is not a good idea as it allows for more data to be inserted after the validate() has been performed, which could lead to errors during the store(). In my framework I do not treat these as separate operations as they must always be executed together and in a particular sequence. In other words they form a group operation in which they are separate steps within that operation. If you look at either insertRecord() or updateRecord() the load() is performed by passing all the data in as an input argument while the validate() and store() are performed internally. Note that the store() method is only called if the validate() method does not detect any errors. For fans of design patterns this is an example of the Template Method Pattern where the abstract class contains all the invariant methods and allows variable/customisable methods to be defined within individual subclasses.

Some of these internal methods contain framework code while others are available for the addition of application-specific code. This I later discovered was an implementation of the Template Method Pattern. I also decided that the way that PHP handled arrays was far superior and more flexible than in my previous languages, so I decided that when my Controller received the HTTP GET or POST request, which was an array, that I would pass that array into the Model as a single argument on the method call, such as insertRecord($_POST). That meant that I would not have to define the columns which belonged to a table as individual properties with their individual getters and setters, which meant that I could pass the entire array from one object or method to another in a single $fieldarray. This is particularly useful when dealing with methods in the Template Method Pattern as none of them have to have any hard-coded references to table or column names, which means that they can work with ANY table with ANY collection of columns.

Instead of having a single component (which I shall now call a Controller) in the Presentation layer to call all the methods of the entity (which I shall now call a Model) in the Business layer I decided to follow what I first practiced in the 1980s and have a separate Controller for each of the user transactions which I would need for that table. This method enabled me to remove all access control code from each application component and have it handled automatically by the framework. Each user transaction has its own entry in the MENU database from which I can display pages of menu options so that the user can choose which one to activate, and my Role-Based Access Control (RBAC) system makes it easy to identify which transactions can be accessed by which users so that each user cannot see, and therefore cannot activate, any transaction for which permission has not been granted. This means that each Model class has a separate Controller for each user transaction (task), the most common group being the family of forms shown in Figure 1:

Figure 1 - A typical Family of Forms

LIST1 ADD1 DELETE1 ENQUIRE1 SEARCH1 UPDATE1 dialog-types-01 (1K)

Note: each of the boxes in the above diagram is a clickable link.

Each of the Controllers for these user transactions (tasks) had its own script in the file system in the format <table>(<mode>).php so that it could be specified in the URL. None of this front controller nonsense for me! I later changed the (<mode>) part to (<pattern>) when I began to create my library of Transaction Patterns.

In this arrangement the parent form is available as a button on the menu bar while all the child forms appear as buttons on the navigation bar which is defined separately for each parent form. This means that a user cannot activate a particular child task without first going through its parent. All menus, sub menus and navigation buttons are maintained using tasks (user transactions) which are built into the framework. Role-Based Access Control, which only allows user to see and activate those tasks for which the system administrator has granted permission, is also maintained using tasks (user transactions) which are built into the framework. Any task or menu which the user does not have permission to access will automatically be filtered out of the display, so if he/she cannot see the button for that menu or task then he/she cannot activate it.

Moving common code to an abstract class

When I informed the outside world that I used a separate class for each database table one of my growing army of critics immediately stepped in and told me that it was wrong for the following reason:

This means you write the same code for each table - select, insert, update, delete again and again. But basically its always the same.

My answer was simple - I do not duplicate that code, I share it by inheriting it from an abstract class. Surely every competent OO programmer would know how to use inheritance?

The route that I took to create this abstract class came about by simple refactoring. After I had built all the code to deal with a first database table (let's call it table1) I had to do something similar for a second database table (let's call it table2). My first step was to copy the file table1.class.inc into table2.class.inc, then go through table2.class.inc and change all the hard-coded references to table and column names so that they would work for table2 instead of table1. I also copied the controller scripts (table1(<mode>).php) so that they mentioned table2 instead of table1. Immediately I could see a huge amount of duplicated code which violated the DRY principle, so I asked myself a simple question - which feature of OO programming could I use to define this code once and share it instead of duplicating it? The answer was just as simple - inheritance.

I started by creating an empty abstract class, even though PHP4 did not support the term "abstract", and modified table1.class.inc and table2.class.inc to inherit from this class. Then I went through each of the class files in turn and moved the common code into methods within the abstract class, which then enabled me to delete that code from each concrete class. Where there was a mixture of sharable and non-sharable code I left the non-sharable code in the concrete subclass, and in order to make it easy to identify it I put it in methods with a "_cm_" prefix to identify them as customisable methods. I defined empty versions of each of these methods in the abstract class and included calls to them in the relevant places. This meant that the method was always called, but unless the concrete subclass contained an implementation then nothing happened.

The end result was that each table class was initially devoid of any methods except for the constructor which contained the code to load the relevant values into $this->dbname, $this->tablename and $this->fieldspec.

Data Dictionary

In my first implementation I thought I could hand the whole of the $_POST array to the DAO so that it could construct and execute the INSERT query, but this failed because the array also included the SUBMIT button which did not exist in any database table. To get around this I added an array called $fieldlist to the class in which I hard-coded a list of all the column/field names which belonged in that table, then I changed the code in my DAO to ignore any column in $fieldarray which did not exist in the $fieldlist array. Later on I upgraded the $fieldlist array into the $fieldspec array which still contained a list of all the fields within that table, but also included a list of specifications (type, size, et cetera) for each field. This list of column specifications then made it easier to write a standard routine which could verify that each piece of column data provided by the user matched that column's specifications.

This meant that each time I created a class for a new table I had to hand-code a new class file and hand-code the contents of the $fieldspec array. After doing this for dozens of tables, and realising that I was following the same procedure each time, I decided to automate it. I decided to build my own version of the UNIFACE Application Model which I called my Data Dictionary, but with two big differences:

Business Logic and Data Validation

There are some programmers out there who believe that business logic and data validation are different things. They believe that it is wrong to insert unvalidated data into an object. This to me is poppycock. The only golden rule in a database application is that all user data must be validated BEFORE it gets sent to the database in order to verify that the data for each column matches that column's specifications otherwise the operation will fail. This means that it is perfectly fine to load unvalidated into an object provided that it is validated before it gets sent to the database. If you look at the processing flow for my insertRecord() and updateRecord() methods you will see several methods which perform data validation before the Data Access Object (DAO) is called to modify the database. These validation methods either perform primary or secondary validation. Primary validation will verify that each field's value matches its specifications in the $fieldspec array. If it does not an error message will be generated and the current operation will be aborted. This processing is automatic and requires no action from the developer except for ensuring that the contents of the <tablename>.dict.inc file are up-to-date. Secondary validation is any other validation which is unique to that table and which has to be defined manually in the relevant customisable method.

There are some programmers out there who believe that objects in the Business/Domain layer should not have any knowledge of the table's structure as this should only be visible in the Data Access layer. This to me is poppycock. Each database table is constructed in order to satisfy a business requirement, so surely validating that any data which will make its way into the database is valid for that structure is a business rule. How can you possibly ensure that the data is valid without knowing the validation rules for each item of data?

Reusable Views

The decision to use XSL stylesheets to produce all HTML output turned out to be a good decision on my part as it eventually enabled me to create a single reusable object which could generate the HTML output for any screen in the application. When you consider that my current ERP application contains over 3,500 different screens that is far better than having to code each of those screens manually. The way it works is quite simple. The Controller calls one or more methods on one or more Models, and when all that processing is complete it calls the standard View object which performs the following:

When I first started creating XSL stylesheets to produce the HTML output for each user transaction (task) I produced each one manually, as described in Generating dynamic web pages using XSL and XML, as that was the only way that I could specify the position on the screen for each column's data. I also had to specify which HTML control (textbox, checkbox, radio group, dropdown list, etc) was to be used. This seemed a bit tedious to me, so I bought more books on XSL, obtained an XSL debugger, and played around to see what could be done. I first discovered that it was possible to define reusable code in a template which could be called much like a subroutine, so I created a separate template for each HTML control. This cut down dramatically the amount of code I had to define within each screen's template, so it was a step in the right direction. I looked at the code that was left, and it was nothing more than a simple list of column names and template names, so I wondered if it was possible to define this list in the XML document and then have some instructions in the XSL stylesheet which could process this list.

After a bit of trial and error I discovered that it was possible. All I need was a way to define this list and load it into the XML document. My solution was to create a separate screen structure file for each screen which could then be copied into the XML file as the <structure> element. Note that the identity of the HTML control which is to be used for each column is specified as an attribute for that column in that table's data. This is described in Reusable XSL Stylesheets and Templates.

Because I no longer had to manually create a different XSL stylesheet for each screen in order to specify where the application data went I could then drastically reduce the number of XSL stylesheets to a small set which provided standard layouts which could be modified at runtime using the contents of the screen structure file. The framework now comes supplied with a library of 12 stylesheets which, in my ERP application, have been used to create over 3,500 different screens. How's that for reusability?

Reusable Controllers

In my first set of Controllers I had hard-coded the name of each table which had to be instantiated into an object before a method could be called on that object. This resulted in code similar to the following:

<?php

require 'include.general.inc';

$mode = 'add';  // identify mode for xsl file

initSession();

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

$dbobject->startTransaction();
$fieldarray = $dbobject->insertRecord($_POST);
if ($dbobject->errors) {
    $errors = $dbobject->getErrors();
    $dbobject->rollback();
} else {
    $dbobject->commit();
} // if

$xml_objects[]['root'] = &$dbobject;

if (!headers_sent()) {
    // build XML document and perform XSL transformation
    $view = new radicore_view($screen_structure);
    $html = $view->buildXML($xml_objects, $errors, $messages);
    echo $html;
} // if
exit;

?>

How could I get rid of that hard-code table name? After a quick test I discovered that I could replace the lines

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

with the following:

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

This meant that instead of a single large script called <table>(add).php I could move the bulk of the code into a separate script called std.add.inc and reduce the contents of <table>(add).php to the following few lines:

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

You should be able to see that I could create any number of these scripts and simply by changing the name of the table I could get the contents of the std.add.inc script to perform exactly the same actions on a different table.

The file <table>(add).php is what I call a component script, and one of these must be created for each user transaction (task) in the application.

The file std.add.inc is now a standard controller script which is provided by the framework.

Transaction Patterns

After all this refactoring I ended up with a variety of reusable software components which could be glued together in order to create usable user transactions (tasks).

All the possible combinations of Controller and View which can be used to create a user transaction (task) are described in Transaction Patterns. I was once told by one of my critics that transaction patterns do not exist as nobody famous has ever written about them, and they do not even have a page in wikipedia. How is it possible for a heretic such as myself to obtain so much benefit from something which supposedly does not exist?

In an early implementation of my framework it was necessary to create each component script and screen structure script by hand, and then to update the MENU database by hand, but this got a little tedious, so I decided to automate the procedure. I added new functions into my Data Dictionary which, simply by selecting a database table and a Transaction Pattern and pressing a button, will automatically create the necessary scripts and update the MENU database. You can then go to the menu which contains the new task and run it.

Final Framework Structure

Although I started off with an implementation of the 3-Tier Architecture it was pointed out to me several years later that because I had a separate object which created the HTML output using an XSL transformation, which effectively split the Presentation layer into two separate components, I had also implemented a version of the Model-View-Controller (MVC) design pattern. This combination of the two is shown in Figure 2:

Figure 2 - MVC plus 3 Tier Architecture

model-view-controller-03a (5K)

A more detailed version is shown in Figure 3:

Figure 3 - Components of the RADICORE framework

Component Script Controller Script Database Table Class Abstract Table Class Validation Class DML Class Screen Structure Script XML document XSL Stylesheet XSL Transformation Process HTML Output CSS File Audit Class Workflow Engine View Object Presentation layer Business layer Data Access layer infrastructure-05 (13K)

Note: each of the boxes in the above diagram is a clickable link.

Using this structure I have found a method of separating out all business logic from the Presentation/UI layer. Even better than that the framework will not allow the developer to put any business logic in the Presentation layer. I have also gone a step farther by removing the need, which still exists in those other frameworks which are favoured by my critics, to manually create any Controllers and Views. I have even gone so far as providing a mechanism which helps the developer create the Model components. Any application which is built using this framework now consists of the following types of object:

  1. Entities - an object whose job is to hold state and associated behavior. Examples of this might be Account, Product or User.
  2. Services - an object which performs an operation. It encapsulates an activity but has no encapsulated state (that is, it is stateless). Examples of Services could include a parser, an authenticator, a validator or a transformer (such as transforming raw data into XML or HTML).

My framework contains the following objects:

  1. Model - this is an entity. One of these is created for each entity in the application and holds all the business rules for that entity.
  2. View - this is a service, a reusable component which is provided by the framework.
  3. Controller - this is a service, a reusable component which is provided by the framework.
  4. Data Access Object - this is a service, a reusable component which is provided by the framework.

You should be able to see from this that because my framework provides so much in the way of pre-written and reusable code, and even functions which create the scripts for individual components in any user application, it saves the developer from all that effort in designing, writing and testing that code and leaves them with nothing but the essentials, the business rules.

You should also be able to see that because it is only the Model components which can be touched by the developer, and that the View and Controller components are provided by the framework, that it is now impossible to put business logic in the UI/Presentation layer.

Rules that I break

As far as I am concerned the only absolute "rules" which exist in programming are the syntax rules within the particular language which you are using. How you join the various pieces of syntax together to produce cost-effective software is a matter of personal preference and skill. The PHP manual defines all the functions which are available, and includes sections which state "this is how you create a class with methods and properties" followed by "this is how you instantiate a class into an object so that you can reference the methods and properties with that object". This covers Encapsulation. The manual also describes how to use Inheritance. It does not describe what Polymorphism is and how to use it, so I had to work that out for myself.

In spite of the fact that I had designed and built a framework which helped me write cost-effective software, as soon as I started to publish what I had done an army of critics crawled out of the woodwork to tell me that everything in my methodology was wrong, that I was breaking all the rules and not following best practices. It turned out that these "rules" and "best practices" were nothing more than personal preferences which were then being taught to other programmers as if they had been cast in stone and brought down from the mountain top. I quickly noticed that by refactoring my code to follow these rules that I would destroy its effectiveness, so I decided to ignore them.

  1. You must use Object Oriented Design (OOD) before you attempt OOP

    I do not agree that OOD is in any way "necessary". Having worked for decades in software houses where we designed and built one bespoke application after another, the method we used to gather requirements, produce a logical design from which we could produce cost estimates and timescales never varied, even when we changed languages. If we won the contract and had to build the application then that was nothing more than an implementation detail. Considering the fact that I only ever worked on enterprise applications which all followed the same pattern - electronic forms at the front end, a database at the back end, and software in the middle to deal with the business rules - I began to design frameworks which could help implement this pattern with less effort by building more and more standard and reusable components. I built my current PHP framework in PHP before being aware that OOD existed, and when I read about its rules I said "Thanks, but no thanks" for the simple reason that my framework already worked very well without following those rules, and changing it to be OOD compliant would have done more harm than good. Among the rules which I refuse to obey are the following:

    Too many people seem to think that Object Oriented and Procedural programming are so different that they require totally different thought processes. I do not. There are more similarities than differences as they are both concerned with the writing of imperative statements which are executed in a linear fashion. The only difference is that one supports encapsulation, inheritance and polymorphism while the other does not.

  2. You must follow the rules of Domain Driven Design (DDD)

    A domain is defined as A sphere of knowledge and activity around which the application logic revolves. Using my framework I have built a large ERP application which consists of what I call subsystems, each of which deals with a different business area, has its own database and its own set of components in both the Business layer and the Presentation layer. As such each of these subsystems can be regarded as a separate domain, in which case, according to the rules of DDD, I should use a separate design process for each of them.

    No thanks. While there are many differences between each subsystem there are just as many similarities in their implementations:

    The are some people who seem to think that every use case in a domain should have its own method in the Business/Domain layer. I do not, for the simple reason that it would immediately cancel out the benefits of using object oriented programming, such as the following:

    Instead of starting with the unique aspects of each domain and dealing with the common aspects later I do the exact opposite - I build working user transactions which automatically contain all the common processing, and afterwards I add in the domain-specific logic by inserting code into the relevant "hook" methods of the relevant domain objects. I use the framework to build and then run these user transactions simply by pressing buttons and without the need to write any code at all - no PHP code, no HTML code, no SQL code. I add in any custom code later.

  3. Having a separate class for each database table is not good OO

    Where was this "principle" published? Who is its author? What are the reasons for the existence of this rule?

    If it is so bad then why has 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"?

    Amongst the pathetic reasons which support this ridiculous claim was the following:

    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.

    It is quite clear to me that this numpty simply does not understand the words that he wrote:

    Each table in a database is a different entity and not just a different instance of the same entity. There is a standard concept called "table" but each physical table has a different implementation - its name and its structure. That is why each concrete class simply identifies its name and its structure while all the standard code is inherited from the abstract class.

    Consider the following definition of a "class":

    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 therefore not unreasonable 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?

    Another numpty wrote the following:

    This means you write the same code for each table - select, insert, update, delete again and again. But basically its always the same.

    Wrong! Any code which can be applied to any table is defined in non-abstract methods within the abstract table class and therefore automatically shared by every concrete table class via that standard OO mechanism called inheritance. I suggest you read up on it and try it out for yourself.

    This topic is discussed in more detail in Having a separate class for each database table *IS* good OO.

  4. Your classes are too big

    This idea is based on nothing more than the large number of methods I have in some of my classes, and the large number of lines of code (LOC). This tells me that my critic has the ability to count, but not to think. The principle of Encapsulation states that ALL the properties and ALL the methods for an entity should be contained with the SAME class which represents that entity. The principle of Cohesion can be stated as follows:

    We would say that something is highly cohesive if it has a clear boundary and all of it is contained in one place.

    When looking at software, we consider a class or module to be highly cohesive if it has a clear responsibility and all of the implementation of that responsibility is close together or in one place.

    This is the basis of the Single Responsibility Principle (SRP) which I have implemented using the 3-Tier Architecture. This is why I separate components for following:

  5. Your class methods are too visible

    The idea that I should be using the qualifiers public, protected and private on all my methods does not strike me as a worthwhile exercise for the simple reason that I developed my framework using PHP4 which did not support them, and this code worked very well. I carried on supporting PHP4 in my framework until October 2016, and I refused to update my code for one simple reason - it would have required a huge amount of effort for zero benefit, so would have been a complete waste of time. It would not solve any problems, it would not result in less code, and it would not result in faster code.

  6. You have the wrong levels of coupling/cohesion/dependency

    If you bothered to study my code you would see that it clearly demonstrates loose coupling and high cohesion which are the correct levels, where the opposites are tight coupling and low cohesion. If you cannot see that then I would say that you need glasses.

  7. Your design is dependent on SQL

    It is dependent on SQL for the simple reason that I develop applications that use a relational database at the back-end, and I communicate with these databases in the standard fashion which means using SQL. This is NOT a problem. It would be just as pointless to say that my design is dependent on HTML. Of course it is, you dork, for the simple reason that I design web applications, and every web application on the planet uses HTML.

    The fact that you see pieces of data which look like SQL in places other than the Data Access layer is irrelevant. They are pieces of data, and not the logic which assembles those pieces into a single query and then sends them to the database using the relevant api. That is the sole responsibility of my Data Access Object.

  8. You must not have the same data names in every layer

    The idea that I should have different data names in each layer is complete and utter bollocks rubbish. Not only have I never worked on a team which practiced this notion, I have used several languages which were based on the assumption that each data element had the same name in every component. To do otherwise would have created masses of effort, so not only did I never see anyone attempt to do this, I never even heard of anyone discussing the possibility.

    Such a ridiculous idea would require extra components to perform data mapping between each layer, so could only come from someone who has been brainwashed into using an Object-Relational Mapper. Such people should be ignored, not emulated.

  9. Your database schema is known to your domain layer

    The idea that the components in the business layer should not be aware that they are communicating with a database is complete and utter bollocks rubbish. It would be like writing a missile control program which is not aware that it is controlling missiles, or an elevator control program which is not aware that it is controlling elevators.

    This idea could only come from someone who does not understand the rules of the 3-Tier Architecture where it is only the component in the Data Access layer which communicates with the database. This means that only the Data Access Object (DAO) can construct and execute SQL queries. This allows the DAO to be constructed from a different class at runtime, thus enabling the DBMS to be switched between MySQL, PostgreSQL, Oracle and SQL Server by changing a single line in a configuration file and without changing a single line of code in any of the other components.

    Data validation is part of the business rules so belongs in the Business layer. Data which is going to be added to the database can only be validated in a Business layer component if that component knows the structure of that table. It must know which columns the table contains and it must know the specifications (type and size, etc) of those columns. If the validation succeeds it does not build and execute an SQL query itself, instead it sends a message to the DAO saying "Add this data to this database table". This means that the Business layer is working with a conceptual model of the database and not a physical model. The Business layer knows that it is working with a database, but it does not know which one, and it certainly does not communicate with the database.

    "Knowing the structure of the database" is not the same as "building and executing SQL queries". One of these is forbidden in the 3-Tier Architecture, the other is not.

  10. You must use an Object-Relational Mapper

    This idea is only promoted by those dimwits who don't understand how relational databases work. They deliberately design their software without any regard to the needs of the database which they regard as nothing more than an "implementation detail". They get somebody with brain cells to design their database but guess what? There is now a mismatch between the software design and the database design. How do these dimwits solve that problem? By generating an additional piece of software to perform the mapping between to the two designs. How does an intelligent person solve the problem? Following the old maxim Prevention is better than Cure it is better to eliminate the problem than to cover up its effects. That is why I always start with the database design, then build my business/domain layer objects around this design with one class for each database table. Result - no mismatch, so no need for additional software to deal with a mismatch. I have automated the method by which changes in the database structure can be conveyed to the software, so it is easy to keep the two structures in sync.

  11. Your design is centered around data instead of functions

    I only write enterprise applications, and these are characterised by the fact that they have a User Interface (Presentation layer) at the front, a relational database (Data Access layer) and a Business/Domain layer in the middle to transfer the data between those two and to process all business rules. OOP involves the creation of objects from classes, and a class involves the bundling of data and the methods that operate on that data within a single unit or "capsule", hence the term encapsulation. Each object in the business/domain layer of the application represents an object for which the application is required to maintain data. In a database application each of these objects is a database table, and as everyone experienced in SQL will tell you, each database table, regardless of its contents, is subject to the same set of operations - Create, Read, Update and Delete (CRUD).

    I have never seen anybody suggest that the correct way to deal with these factors - data and operations - would be to create a separate class for each of the CRUD operations and then tie them to a particular database table with its own set of business rules at runtime, so I do what is intuitive and logical and create a separate class for each table which has the operations to maintain the contents of that table. Note that these operations are not duplicated within each table class as that would violate the DRY principle. Instead they are defined within a single abstract table class which is then inherited by every concrete table class.

    When designing a database application for a new business domain here are two basic parts - the database and a list of use cases which manipulate the data in that database. Each use case is responsible for performing one or more of the CRUD operations on one or more tables. The list of operations is therefore fixed whereas the design of the database is totally flexible. This means that the design of the database is far more important and comes before the design of the software which can be considered as being nothing more than "an implementation detail". This can be summed in in the following quote:

    Smart data structures and dumb code works a lot better than the other way around.

    Eric S. Raymond, "The Cathedral and the Bazaar"

    Get the database wrong and no amount of code will get you out of the mess that you have made yourself. Get the database right and the coding part will be much easier.

  12. You must have a separate class property for each table column

    Where is this documented? Just because it is used in some examples does not mean that it is a golden rule. When the SUBMIT button is pressed in an HTML form the data is sent to the server in a single $_POST array, not as separate columns. When data is read from a database the SELECT query returns a result consisting of zero or more rows where each row is an array containing one or more columns. I found it far easier to keep this data in a single variable called $fieldarray than to introduce additional code to split the array into its component parts and then deal with each component separately. This means that I can make changes to the contents of that array, such as adding or removing columns, without having to change any method signatures, which is a good example of loose coupling.

  13. You must access each class property using getters and setters

    This is only relevant if you have a separate class property for each table column (see previous point). As I use a single property for a complete dataset I can put the data into an object as a single input argument on a method call (as in $dbobject->insertRecord($_POST)) and get it out again as a single result set.

  14. An object can only deal with a single database row

    Not according to Martin Fowler and his Table Module pattern. My single $fieldarray property allows me to deal with any number of columns from any number of rows in a single object, so why on earth should I change this to use a method which is less efficient and more cumbersome?

  15. You must validate all data before it is put into the Model

    Where is that documented? Each domain object (model) is responsible for all its business rules, and as data validation is part of those business rules it means that the validation should be performed inside the model, not outside. If you take the processing of business rules out of the domain object you will end up with nothing but an anemic domain model which is considered to be a bad thing.

    The only genuine rule regarding data validation is that it must be performed BEFORE the insert/update query is executed as invalid data will cause the query to fail and the program to abort. All data should be validated in the code and returned to the user with a suitable error message should any problem be found.

  16. You must validate a value within its setter

    I don't use setters, so I can't. All data validation is performed by a standard validation object as part of the insertRecord() or updateRecord() operation. If the validation fails then the insert/update is abandoned and the method call returns an error message instead.

  17. You must use the constructor to populate an object with valid data

    Where is this documented? This obviously is a mis-interpretation of the statement: A properly written constructor leaves the resulting object in a valid state. In this context the term "valid state" does not mean the same thing as "data within the object must be valid". It actually means the following: A valid object is one that can accept calls on any of its public methods.

    This rule also implies that the data must be validated outside of the object before it can be inserted, but I am afraid that this would violate the principle of information hiding which encapsulation is supposed to enforce. All business rules concerning an object, and this includes data validation rules, are supposed to be buried within the object and hidden from the outside world.

    This topic is discussed in more detail in Re: Objects should be constructed in one go.

  18. In MVC a Controller can only speak to one Model

    Where is this documented? Just because it is used in some examples does not mean that it is a golden rule. While most of my reusable page controllers do indeed work with no more than one model, I have some which work with 2, 3 or even 4. If this were truly "wrong" then it would cause problems, but it doesn't, so it isn't. The advantage of allowing multiple Models within each Controller is that each Model can have its own set of scrolling or pagination controls.

  19. In MVC a Model can only have one Controller

    Where is this documented? Just because it is used in some examples does not mean that it is a golden rule. Each of my model classes inherits its public methods from my abstract table class, and as each controller speaks to its model(s) using these methods it means that any model can be accessed by any controller, and any controller can be used to access any model.

  20. You must define a collection of Finder methods to access your data

    This is only relevant if you use an Object-Relational Mapper. Those of us who understand how databases work know that an SQL query does not use a variety of finder methods, it uses a single WHERE string on a SELECT statement which can handle a multitude of possibilities. I don't need to write special methods to manipulate this string as the PHP language already contains a huge selection of functions to manipulate strings. Once constructed I can use this string in a standard $result = $dbobject->getData($where) command. I can even pass this string from one component to another with great ease.

  21. You must create a separate method for each use case

    Do you realise how much work this would create? In my ERP application I have 4,000+ tasks (use cases) and 400+ model classes. If I had a separate method in a Model for each of these tasks it would mean the following:

    As the primary objective of using OOP in the first place is supposed to be to increase the amount of reusable code, the lack of reusability that following this principle would produce is a step in the wrong direction.

    In my methodology I create an entry on the TASK table of my MENU database for each use case. This entry points to a component script on the file system which in turn points to a Controller and one or more Models where all communication between them is governed by the methods that were defined in the abstract table class. This means that the use case name is defined in the MENU database and not as a method name within a class. The user selects which task he wants to run by its name in the MENU database, and the Controller which is activated for that task uses generic methods to perform whatever action is required.

    I do not have to create any special methods in a Model as all the public methods I need are inherited from a single abstract class. I do not have to put any special method calls into any Controller as they only use the same public methods which are defined in the abstract class. Each of my Controllers has been designed to be reusable with ANY Model, so is available as a pre-written component in my framework. So if I have 45 Controllers and 400 Models this equates to 45 x 400 = 18,000 (yes, EIGHTEEN THOUSAND!) opportunities for polymorphism. If I followed your rule I would not have this level of reusability, so I don't follow your rule.

  22. You should use a Front Controller

    A colleague once told me that all the big boys use a front controller, and if I wanted to be in their club then I should use one as well. He is now an ex-colleague. In my methodology each URL in the application points directly to a component script in the file system, and this script identifies IMMEDIATELY what parts of the application are being used to do what. This makes debugging far easier as you don't have trawl through multiple lines of code in various front controller and router objects to obtain what can be expressed in three lines.

  23. You are using the wrong design patterns

    There is no such thing as the "right" design patterns. Each programmer is allowed to use whatever design patterns he sees fit in whatever way he sees fit. To me design patterns are just like training wheels on a bicycle - they're OK when you are a novice, but after that they become more of a hindrance than a help. An experienced and competent programmer does not write software by first making a list of design patterns which it should use, he simply writes code and design patterns appear naturally of their own accord. This is what Erich Gamma said at an interview in May 2005:

    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.

    If you bothered to examine my framework in detail you should notice where I make use of the following patterns:

    I don't use other patterns simply because I have found no use for them.

    Another reason why I do not use design patterns with the same religious fervour as others is that they are not proper patterns at all. They do not provide pre-written code that can be used over and over again, they merely provide an outline of a design which you then have to implement yourself by writing your own code over and over again. I much prefer to use Transaction Patterns as they provide pre-written and reusable code which can be linked with any Model to produce a working transaction without the need to write any code whatsoever. That is why each use case has its own component script which does nothing but identify which Controller should be linked with which Model and which View.

  24. Encapsulating an entity does not result in a single class

    Some people tell me that my abstract table class has so many methods that it surely must be breaking SRP and that it surely must be a God Object. They do not understand that the content of a class is not governed by the ability to count but by the ability to think. The description of encapsulation makes it quite clear that ALL the properties and ALL the methods for an entity should be put into the SAME class, and not spread across multiple classes. I am already obeying Robert C. Martin's definition of SRP by putting presentation logic, business logic and database logic into different objects, and I am also doing the right thing by following what he says in his article about Anemic Domain Models:

    It's also worth emphasizing that putting behavior into the domain objects should not contradict the solid approach of using layering to separate domain logic from such things as persistence and presentation responsibilities. The logic that should be in a domain object is domain logic - validations, calculations, business rules - whatever you like to call it

    He does not say that each of those areas of logic - validations, calculations, business rules, etc - should go into a separate object, he specifically says that ALL the business logic for a single entity should go into a SINGLE object while presentation logic and database logic should be handled separately. It is quite clear to me - there should be one object in the business/domain layer for each entity, and in a database application each of those objects is a table.

  25. Your code uses global variables

    There is nothing wrong with using global variables in moderation. Problems only arise when they are used in inappropriate circumstances.

  26. Your code uses singletons
  27. There is more than one way in which this design pattern can be implemented, each with its own set of pros and cons. If you choose the implementation which has all the cons and none of the pros then it is your implementation which is at fault, not the pattern itself. For a description of several different implementations please take a look at Singletons are NOT evil.

  28. You don't understand what '3 tier' means

    Really? What definition of the 3-Tier Architecture are you using? If it does not contain descriptions of the Presentation, Business and Data Access layers then I'm afraid that you have been reading the wrong definition.

  29. Your approach is too simple

    That is because I prefer to follow the KISS principle whereas you seem to favour the KICK principle. I have been designing and writing database applications for several decades, and after having personally written thousands of user transactions I noticed that every one followed the same pattern - there was a mixture of common and repeatable code as well as unique and non-sharable code. In my framework all this common code is supplied in sharable modules such as Controllers, Views and Data Access Objects. Each Model component inherits from an abstract table class which provides common functionality, but my use of the Template Method Pattern allows the developer to insert any custom logic into "hook" methods.

    This topic is discussed in more detail in A minimalist approach to Object Oriented Programming with PHP.

  30. You must favour Composition over Inheritance

    Why? There is nothing wrong with inheritance if it is used correctly. In the article Object Composition vs. Inheritance it clearly states that it is only the over use of inheritance which creates problems, and one solution to this problem would be only to inherit from abstract classes. This thought is echoed in the Gang of Four (Gof) book Design Patterns: Elements of Reusable Object-Oriented Software.

    So if I am following expert advice and NOT over using inheritance and ONLY inheriting from an abstract class then your criticism is baseless.

  31. You must follow the SOLID principles

    As soon as I became aware that these principles existed I read about them, but their descriptions did not inspire me with confidence, so I ignored them.

References

The following articles describe different aspects of my methodology:

These are my personal opinions on OO programming:

These are reasons why I consider some ideas on how to do OOP "properly" to be complete rubbish:


counter