According to Designing Reusable Classes which was published by Ralph E. Johnson & Brian Foote in 1988 a major motivation for object-oriented programming is software reuse, so any practice which has a detrimental effect on the creation of reusable code should be avoided. In this article I will show how static typing, which a large number of programmers regard as a prerequisite of good programming, actually has the opposite effect. It results in tight coupling which reduces polymorphism which in turn reduces the production of modules whose dependencies can be injected. When you consider that Dependency Injection (DI) can be the biggest contributor to the production of reusable code, any practice which reduces polymorphism and DI should not be regarded as "best". This includes using getters and setters for column data in database applications.
Before I switched to using PHP as my main development language at the start of this century I had spent the previous 20 years developing enterprise applications using COBOL and UNIFACE. While both of these languages were compiled and statically typed COBOL was procedural while UNIFACE was component-based. PHP is different from both in that it is interpreted, not compiled, dynamically typed, not statically typed, and supports both the procedural and Object Oriented (OO) paradigms. The biggest difference between the two type systems is as follows:
This has the greatest impact when data from outside sources, such as the user interface and the database, arrives in groups rather than individual pieces.
Some inexperienced programmers seem to think that static typing totally eliminates the possibility of type errors, but my experience has shown otherwise. It is possible for a dynamic language to be Type Safe provided that any mismatches can be handled in a predictable manner without causing unwanted results. With a static structure the definition says that a certain number of bytes in a certain part of the byte stream should represent data of a particular type, but if the definition used in the receiving program is not identical it could mean that the data it reads is not of the expected type, in which case the results will be unpredictable and possibly catastrophic.
With static structures each individual data element has the correct type to begin with, but with dynamic structures, such as PHP arrays, all the values are presented as strings. This is not a limitation of PHP, it is a function of the external protocols:
Another difference between the two types systems is how mismatches between the given type and the expected type can be handled:
When I began experimenting with the OO capabilities of PHP I applied its principles in the following ways:
I noticed during my experiments that the amount of polymorphism which was available was affected by the level of coupling with tight coupling being bad and loose coupling being good. A major reason why I became more productive with PHP was because dynamic structures contribute directly to loose coupling while static structures have the opposite effect. My reasoning is as follows:
Despite the fact that I have embraced the dynamic nature of PHP and reaped the rewards, I have noticed that since starting with version 4 all the subsequent versions have starting to drift away from dynamic typing and more and more to strict typing. It started with type hinting in version 7, but I suspected that this would be the first step to type enforcement. My suspicions were correct. It would appear that large numbers of my intellectually-challenged brethren have not yet received the memo that dynamic typing is a more efficient and pragmatic approach, and so they are still living in the past just like neanderthals. They still cling to the idea that dynamically typed languages are not Type Safe. This outdated attitude is one of the reasons I came up with the following phrase:
Some people know only what they have been taught while others know what they have learned.
I will not change my code to include strict typing as it would take a great deal of effort for absolutely no gain, and that would surely violate the YAGNI principle. I don't see why I should waste my time to insert extra code to do manually what the language can do automatically. I have already found ways to eliminate type errors (except when caused by BC breaks which have been introduced by those idiot core developers), which means that I regard strict typing as less of a safety net and more of a straight jacket.
When I say that since moving to PHP with its dynamic typing and object oriented capabilities I have seen my levels of productivity increase dramatically I am not just blowing smoke. As proof let me share with you a common collection of forms which I have developed many times over in all three languages. This collection is shown in Figure 1 below, and my development times have decreased as follows:
Figure 1 - A typical Family of Forms
Each of the boxes in the above diagram is a clickable link which will take you to an entry in my catalog of Transaction Patterns. When I was a junior programmer I was taught that this group constituted a single use case, but when it started to cause problems while trying to implement a permissions system I learned to split it into its constituent parts.
The behaviour of this family of tasks follows a standard pattern - the user selects a parent LIST task from a menu, and each parent has its own set of navigation buttons to activate its child tasks. Each child task may be the parent in its own forms family, so may also have its own set on navigation buttons. Each task performs these basic operations:
Note that while the LIST screen shows multiple rows across the page with column labels at the top, all the child screens show a single row vertically down the page with the labels on the left and values on the right. While the LIST screen has a pagination area which allows the user to browse through different pages of data one page at a time using a variable page size, the child screens will have a scrolling area, but only if multiple rows where selected in the parent screen. This will allow the user to scroll through the selected records one at a time.
Soon after creating the LIST1 pattern and its family of forms, which deal with a single table, I encountered the need to deal with related tables. Every relationship is between two tables in a one-to-many or parent-child hierarchy where the child has a foreign key which points to a primary key on the parent table. In each relationship a parent can have many children, but the child can only have a single parent. Each parent can be related to more than one child table, and each child can be related to more than one parent table. To deal with this situation I followed the convention which was followed in UNIFACE by building screens which had separate zones (areas) for the parent and child tables (which were labelled OUTER and INNER). This has the parent/outer table at the top with the child/inner table underneath. The outer table is read first, then its primary key is converted into a foreign key before the inner table is read. See the LIST2 pattern for details. Note than when a parent table becomes the inner entity I do not paint two entities on the screen, I modify the SELECT query for the child table to include a JOIN to the parent, thus avoiding the N+1 problem.
This is just one example where I used my powers of observation to identify patterns in my code of either structure or behaviour, and using the practice known as programming-by-difference I abstracted out the similarities into reusable modules and the differences into unique modules. Despite not having any formal training in the mystical arts of OO, meaning that I had no knowledge of design patterns or the SOLID and GRASP principles, I managed to create a framework with huge amounts of pre-written and reusable code. Code within an application can basically be categorised in two ways - business logic and non-business logic. Another term for non-business logic is boilerplate code or glue code. The RADICORE framework has the distinction of being the only framework which provides one hundred percent of this boilerplate code in pre-written modules, which equates to a huge amount of code that the developer does not have to write. This means that the developer can spend much more time on the important code which is the business logic.
After using statically typed languages for so long you may have thought that I would find the move to a dynamically typed language to be problematic, but you would be so wrong. I took to dynamic typing like a duck takes to water. I did not encounter a mental stumbling block like so many others. I do not have to pre-define static structures at compile time as dynamic structures are created at run time, and I don't get any type errors as I have learned to take advantage of PHP's Type Juggling capabilities. The only checking that I HAVE to do is to verify that all the string values submitted on an HTML document can be coerced into the type required by the database, but I wrote a standard routine for that which is built into the framework.
My career in Data Processing (DP) before it was renamed to Information Technology (IT) actually began in computer operations where I worked with a UNIVAC 1100 mainframe on a 3-shift system giving 24/7 cover. I taught myself COBOL so that I could amend a small program that produced a list of tape numbers that were to be used in the overnight batch runs, and this impressed my manager so much he arranged for me to transfer to the middleware department so that I could do programming full time. In those days all input was via punched cards, all output was on paper listings, and everything was run in batch. In 1980 I moved to my first software house which ran mini-computers, first a Data General Eclipse and then a Hewlett Packard 3000, which had monitors and keyboards, yet we still stored program listings on paper. In 1982 I moved to another software house where I spent the next 17 years. I continued using COBOL on the HP3000 until the mid 90s when the company switch to UNIFACE running on Windows micro-computers (PCs).
When I started working for software houses building bespoke database applications none of the project teams I worked with maintained a library of reusable code. The more code I wrote the more I realised that there was a lot of duplication which was not an efficient way to write code. That is when I started to construct my own personal library of example programs which I could use as templates. One of the most common complaints against COBOL was that its syntax was too verbose, but wise programmers quickly worked out that it was only necessary to write your first program from scratch. After that you could copy that code and only change those parts that were different.
Static typing was enforced by virtue of the fact that every data item had to be defined in the DATA DIVISION before it could be referenced by code in the PROCEDURE DIVISION. These definitions include the PICTURE clause to identify each item's type and size. When groups of data are passed in or out when communicating with either the user interface or the database they are defined as RECORDS or DATA BUFFERS. It was vitally important that the record definition used by the program which sent that data was exactly the same as the definition used by the program which received that data otherwise a type mismatch would occur and the results could be unexpected and sometimes catastrophic.
Most of my time was spent working with HP 3000 hardware which provided one set of intrinsics (functions) to access VPLUS forms files, which were built using a separate FORMSPEC program. A single program could access any number of forms. It was necessary to load and initialise each form before data could be loaded into it using VPUTBUFFER or read from it using VGETBUFFER where the data buffers were unique to each form and had to be defined separately within the program. Note that these forms operated in block mode, which meant that the data was sent to the terminal in a block, and returned to the server in a block when the ENTER key was pressed.
Another set set of intrinsics was required to access the TurboiMAGE database. Each table had to be accessed using its own procedure call where the database name, table (dataset) name and data buffer had to be hard-coded. Note that each table had to be accessed separately as JOINS to other tables were not possible.
When my team members started to experience bugs due to changes in record definitions which were not propagated down to all the right places I solved the problem by using features which I encountered by reading the manuals. I discovered the VGETFORMINFO and DBINFO functions which could read the record definitions used by that software with enough detail to make it possible to generate the necessary record definition which was required by a COBOL program. I used the functions to create my COPYGEN program so that when record definitions were created or changed the COBOL definitions could be generated and stored within a copy library. Thus instead of coding each record definition by hand it could be pulled in from the copy library when the program was next compiled.
When referencing a data item within a statement that operation had to be compatible with the item's data type. With numbers, for example, it was not possible to display a number if its USAGE was COMPUTATIONAL, and not possible to perform an arithmetic operation on it if its USAGE was DISPLAY. For this reason a data item was defined in the database definition with USAGE COMPUTATIONAL and in the form definition with USAGE DISPLAY. While an item's type could not be changed in situ it could be changed my moving it from one record definition to another. This is why each program had one set of code to move data from the database buffer to the form buffer, and another set to move data from the form buffer to the database buffer.
While it was possible to build a program from a single source file which could access more than one form and update more than one table this could easily hit the memory limit for both the PROCEDURE and DATA divisions. A way around this was to break the application down into multiple source files each of which could be compiled into a subprogram. All the compiled subprograms, plus a single control program, could then be linked together to form a single executable program. The linker could be configured to create a number of segments which could be swapped in and out of memory at run time to avoid hitting the memory limit. The difference between a program and a subprogram is that a program can only be run from the command line, while a subprogram can only be called from within another piece of code within the same executable. Subprograms in the same executable can also share memory.
After building large numbers of programs which performed similar operations on different database tables I noticed that while the program structures were similar it was impossible to produce reusable patterns or templates as each program used a different VPLUS form and different database table, each of which required a different named data structure plus different code to move data between the two structures. The most I could manage was to keep copies of typical programs so that when I needed another version for a different table I could copy the original and only have to change the data names.
One area I could cover to reduce code duplication was to produce a Library of Standard Utilities to contain common functions. I also noticed that where a number of system functions (known as "intrinsics") was always called in a specific sequence I could wrap that group in a separate function in order to replace several function calls with just one. I call this a "wrapper" but you may know it as the Facade pattern. Examples of several wrapper functions can be found in my VPLUS routines.
UNIFACE was completely different. It had its own Integrated Development Environment (IDE) which was tied to a database known as a Repository. This included an Application Model in which was defined a separate entity for each database table, along with its columns. Entities were first defined in the Application Model, and an export function generated CREATE TABLE scripts which were used to build the physical database. When application Components were constructed the source code was maintained in the Repository, but when they were compiled the output was stored in the file system. These files were accessed when the application was run.
Building application components was done using the inbuilt Graphical Form Painter (GFP) which required picking one or more entities from the Application Model and painting them as entity frames on the blank screen, then filling each entity frame with fields from that entity. Business logic was added to the form component by inserting proc code into any of the entity or field triggers, which were fired at run time depending on how the mouse was moved on the screen. When the user instigated a READ or WRITE operation, either by typing in a special key sequence or pressing the relevant button on the screen, UNIFACE would direct that action though its inbuilt database driver which would generate and execute the SQL query for that operation on that table. The advantage of UNIFACE was that the developer did not have to write any SQL queries, but the disadvantage was that the developer could not write any queries, so if the component contained multiple entities each of these had to be accessed separately. This produced a classic example of the N+1 problem as JOINS were not an option. The only way to get around this was to create a database view and define it as a read-only entity in the Application Model.
Unlike a COBOL program which could access any number of forms, a UNIFACE component could only access a single form as each one was built around the layout of a single screen.
The first version of UNIFACE which we used implemented the 2-Tier architecture as the form components were a combination of both the presentation and business layers, with the data access layer being provided by the inbuilt database driver. A later version upgraded this to the 3-Tier architecture by allowing all business logic to be moved out of each form component into a separate service component in the middle tier. This allowed several form components to share the same business logic when they referenced the same service component.
While UNIFACE did not have visible data structures like the RECORDS used in COBOL, static typing was enforced by the fact that all the form and service components were bound to entities (tables) that had been defined in the Application Model where the type and size of each table column were defined. The movement of data between the UI and database was handled by the UNIFACE runtime which used the column specifications in the Application Model to prevent any type mismatches. Because the type of every data element was known, it was impossible to write proc code to overwrite any element with a value of the wrong type.
While every component had to be built by hand UNIFACE came up with a novel way of dealing with components which had a similar structure involving the use of Component Templates. This allowed the developer to build a new form component from a template, then replace the dummy names in the template with actual names from the Application Model.
UNIFACE was originally designed to generate desktop applications, but later it was amended to give it the ability to create internet applications. Because of my experience with UNIFACE on the desktop I was recruited to join a team who were attempting to build a web application, but this was a disaster. It was then that I decided to find a more suitable language in which to develop web applications.
PHP was totally different from both of my previous languages in so many ways:
PHP was also designed specifically for the creation of dynamic web pages using content from a relational database. These applications use HTML at the front end which can be viewed in any web browser, and an SQL database at the back end. It should be noted that neither of these protocols use static and pre-typed data structures as all input/output operations are completed using strings of plain text. This means that instead of static structures where the name, type and size of each element has to be pre-defined PHP makes use of dynamic structures known as arrays where the contents are not known until run time, do not have to be specified before they are received, are infinitely variable, and where all the values are strings. This means that a single piece of code which either sends or receives data in an array can be run multiple times where the contents of the array is different each time. It is this property of arrays that I exploited in my framework, alongside inheritance, to greatly increase the number of reusable components.
PHP scripts are stateless, which means that when a script starts it has no memory of what happened previously, and when the script ends all current memory is lost. It is possible to maintain some state between scripts being run from the same browser using PHP's Session Handling functions.
A PHP script need not reference any particular HTML document, and it is possible for a script to have no user interaction at. If a script receives an HTTP request it does so vial the $_GET, $_POST or $_REQUEST variables. If a script creates HTML output it has to construct the entire document from scratch each time. It is not possible to send updates to an existing document. Different parts of an HTML document can be output during the execution of the script, or the whole thing can be constructed in one burst at the very end of the script.
While it is possible for a single script to be accessed several times, and for each iteration to output a different HTML document, it is also for one script to produce an HTML document and for the user input to be posted to a different script. It is also possible for a document to contain hyperlinks which activate other scripts. A script can transfer control to another script by using the header( 'location: xxx' ) function.
As this was my first attempt at Object Oriented Programming (OOP) I had to find out why it was different and how I could use it to best effect. After a lot of searches of the internet I came across numerous explanations which I found to be unsatisfactory, as documented in What OOP is NOT. The only satisfactory description I found was the following:
Object Oriented Programming is programming which is oriented around objects, thus taking advantage of Encapsulation, Inheritance and Polymorphism to increase code reuse and decrease code maintenance.
The PHP manual described encapsulation and inheritance in simple language, but said nothing about polymorphism, so I had to work that out for myself.
I never had any formal training in the mystical arts of OO, meaning that I had no knowledge of design patterns or the SOLID and GRASP principles. All I had was a working PHP+MySQL+Apache environment on my home PC, the PHP Manual, some books, access to some online resources, and 20 years of programming experience. My aim was to rebuild my COBOL framework in PHP so that I could continue to develop enterprise applications, but this time for the internet.
I did not follow the rules of Object Oriented Analysis and Design (OOAD) because I did not know they existed. I did not start with a Big Design Up Front (BDUF), instead I started with simple code which did basic things, like build a screen to access the database, and added to it in small increments so that it grew organically. After building several components I used my powers of observation to spot patterns of similarity in either structure or behaviour, then used my programming ability to separate the similar from the different so that move the similar into a reusable module so that I could stop writing duplicate copies. This is called programming-by-difference.
Having written code that lived in 1, then 2 and finally 3 tiers, it was obvious to me that the 3 Tier Architecture was the most robust, so that was the first target I decided to hit. This architecture deals with the request-response cycle as shown in Figure 2 below:
Figure 2 - Requests and Responses in the 3 Tier Architecture
While procedural PHP does not force any particular architecture I discovered that using objects created a 2-tier structure by default. After creating a class for an entity that is of interest to your application, something that has properties and methods, you must have a separate piece of code which instantiates that class into an object and then call one or more of its methods. The entity class becomes the Model while the code which instantiates it and controls which methods are called becomes the Controller. The Model exists in the Business layer while the Controller exists in the Presentation layer. In my first iteration I did not have a separate Data Access layer, but I did create methods in the Model to build the SQL queries which could easily be moved later into a separate class.
I decided during my earlier experimentation that using a templating engine to produce HTML would be the best way to go, and as I had already encountered XML and XSL in my UNIFACE days, and had played with it on my home PC, I just needed to verify that I could use these technologies in PHP. This turned to be very easy, as I documented in the following articles:
This meant that, instead of outputting fragments of HTML from within either the Controller or Model, I could leave the construction of the response until the very last step taken by the Controller This could be achieved within a totally separate object. An old colleague later pointed out to me that that this made it an implementation of the Model-View-Controller design pattern which resulted in the structure shown in Figure 3 below:
Figure 3 - MVC and 3 Tier Architecture combined
Note that each of the boxes in the above diagram is a hyperlink which will take you to a detailed description of that component.
Unlike in my previous languages where the code was always coupled to a particular screen structure, this PHP implementation is completely decoupled for the following reasons:
Having proved how easy it was to read data from the database and transform it into HTML I set about creating a small sample application to read data from several tables and build some working HTML documents. I created a small database with enough tables to deal with single-table transactions, a one-to-many relationship, a many-to-many relationship, and a hierarchical relationship which could be displayed using a tree structure. Having built the database I then began writing the code to maintain its contents. Note that this prototype only included the code to create HTML pages and to move data into and out of a database. All the menu buttons and navigation buttons were hard coded as there was no MENU database, no login screen, and no Role Based Access Control. Those did not appear until I built my framework.
I used this prototype to help build some working scripts that moved data from the screen to the database and back again using a variety of relationships which required different Controllers with different logic. I started with simple code and only added complexity when it became necessary. I tried several ideas until I hit upon the ones that used the simplest code to produce the best results.
As the aim of OOP, as stated above, was to increase reusability, I attempted to use the features of OOP to produce as much reusable code as possible. I often found myself ditching the approaches I saw in other people's sample code in favour of something which I considered to be better for the simple reason that it created more components which were reusable, which could then be translated into less code I would have to duplicate in the long run. I decided to use the three pillars of OOP in the following ways:
allows a value or variable to have more than one type and allows a given operation to be performed on values of more than one type, were bound to other languages with different behaviour to PHP. When reading the Gang of Four book I came across the statement
An object may have many types, and widely different objects can share the same type. Parts of an object's interface may be characterized by one type, and other parts by other typesThis statement does not apply to PHP as the word "type" only relates to primitive data types as neither classes nor objects have a type other than their class name. If you call the gettype() function on an object the response will never be anything other than "object". I eventually discovered that the proper and unambiguous meaning of polymorphism was nothing more than
when the same method signature exists in more that one class. Notice than I use the term "method signature" (method name and parameter list) instead of interface as that in OOP has a totally different meaning. I quite quickly discovered a way to make use of this feature, but I didn't know its name until I was told years later that my code was wrong!
Note that I do not consider abstraction to be a pillar of OOP for the simple reason that it is not unique to the OO paradigm. It is a mental process which cannot be reproduced in code, although the results of this mental process can assist in the design of efficient code. This is discussed more in The meaning of "abstraction".
It was standard practice in all the code samples which I encountered in my learning phase for each table class to have a separate property for each of its columns. This meant that upon receiving the $_POST array it had to be split into its constituent parts so that each part could then be fed into the dependent object individually one at a time. This required a lot of code which was specific to that particular table and therefore could not be shared, which resulted in tight coupling, so I wondered if it were absolutely necessary. Could the $_POST array be inserted as a single array variable instead of a collection of smaller variables? A quick test showed no difference between using $fieldarray['column'] and $this-column within each method, and as I could use the same single variable as both an input and output argument on every method, as shown in Step2.6, this also meant that those methods calls could also handle any amount of data from any source. This surely is a prime example of loose coupling as it allows those methods in the abstract superclass to be used with any one of the hundreds of concrete subclasses.
This technique could also manage data which was retrieved from the database, which made it possible to use JOINS and so avoid the N+1 problem. There is no rule that says that the result of a SELECT query in a table class can only retrieve columns which are actually defined on that table. It also made it easier to add, remove or update the contents of the array should the business logic demand it. After using this approach for over 20 years I can honestly say that it was one of the best decisions that I ever made as it changed code from being tightly coupled into being loosely coupled. Code which is loosely coupled has huge benefits as it produces more code which is reusable.
I was not aware of any rule which said I HAD to create separate variables for each property and load them in one at a time, so it was easy for me to consider an alternative. An important point which was a factor in my decision was when I noticed how the data arrived - it was presented in groups of elements and not one element at a time. The user fills in all the fields on a screen and presses a SUBMIT button, and all those fields are sent to the software in a single burst. Contrast this with how an aircraft control system works - the aircraft is covered in hundreds of different sensors, and each sensor sends in its reading individually to the central processor instead of in a group.
I also noticed in other people's code samples that they often embedded SQL queries in with their business logic where the table names and column names were hard-coded. This creates code which is not reusable, so I looked for a better method. I saw that each SQL query is nothing but a large string which is comprised of several substrings, some of which are required while others are optional, and I also noticed that PHP's string handling functions were quite extensive. Instead of hard-coding each query I played with the idea of identifying the substrings in the business logic which could then be passed to a method where they could be assembled into a complete string before it was executed. This I documented in Using PHP Objects to access your Database Tables where I show the methods which I created to handle each of the CRUD operations - insertRecord($fieldarray), updateRecord($fieldarray), deleteRecord($fieldarray) and getData($where). You should notice that the table name is provided as an argument, so it can build queries for any table, not just a particular named table.
The original code was tied to the MySQL database using the original mysql_* extension. After MySQL version 4.1 was released with a different mysqli_* "improved" interface I moved these methods to a separate class and changed the original methods to transfer control to a different object depending on which database extension was preferred. This enabled me later to add database objects to support different extensions for PostgreSQL, Oracle and SQL Server.
My first attempt at passing the entire contents of the $_POST array to the method which created an INSERT query failed because it did not recognise a column named after the SUBMIT button. This caused me to create a property called $this->fieldlist in the class constructor which contained an array of the column names which did exist on that table. Soon after that, after I accidentally put a non-numeric character into a numeric field, I realised that I needed to validate each piece of user input to verify that it matched its specifications in the database. This is because a number may be stored as a 4-byte integer in the database where it can hold a value between -2147483648 and +2147483648, but the same number does not appear as 4 bytes in the either of the HTML or SQL protocols, it appears as a human-readable numeric string. When a human user enters what is supposed to be a number into a text string on the screen they may accidentally type in a non-numeric character, and this would cause the query to fail. The sensible thing to do is to check each field before it is sent to the database so that, if it is wrong, it can be returned to the user with a suitable error message.
Instead of inserting code to manually check that each input field contained a valid value I realised that, as each data type required exactly the same validation code, I could replace my $this->fieldlist array with an array of field names and their specifications, and this became my $fieldspec array. It then became possible to write a standard routine that would iterate through $fieldarray, which contains a set of fieldname=fieldvalue pairs, and compare each value with its specifications in the $fieldspec array, which contains a set of fieldname=fieldspecs pairs. This standard routine only covers what I call primary validation, so if any secondary validation is required this requires a separate method.
The technique known as programming-by-difference involves examining program code looking for patterns in either behaviour or structure. This then allows the programmer to separate the similar from the different, the abstract from the concrete so that the similar can be put into reusable modules and the different into unique modules. I was already aware that while each table was different in that it held different data, the way in which that data was handled followed a standard pattern. All the differences between one table and another are described in the database's INFORMATION SCHEMA, and all that data, which is classed as metadata, can be stored in variables within each table class. The code within the table class can then utilise the contents of these variables instead of having their values hard-coded. Within each table class this metadata is stored in the following properties:
| $this->dbname | This value is defined in the class constructor. This allows the application to access tables in more than one database. It is standard practice in the RADICORE framework to have a separate database for each subsystem. |
| $this->tablename | This value is defined in the class constructor and is unique within the database. |
| $this->fieldspec | The identifies the columns (fields) which exist in this table and their specifications (type, size, etc). |
| $this->primary_key | This identifies the column(s) which form the primary key. Note that this may be a compound key with more than one column. Although some modern databases allow it, it is standard practice within the RADICORE framework to disallow changes to the primary key. This is why surrogate or technical keys were invented. |
| $this->unique_keys | A table may have zero or more additional unique keys. These are also known as candidate keys as they could be considered as candidates for the role of primary key. Unlike the primary key these candidate keys may contain nullable columns and their values may be changed at runtime. |
| $this->parent_relations | This has a separate entry for each table which is the parent in a parent-child relationship with this table. This also maps foreign keys on this table to the primary key of the parent table. This array can have zero or more entries. |
| $this->child_relations | This has a separate entry for each table which is the child in a parent-child relationship with this table. This also maps the primary key on this table to the foreign key of the child table. This array can have zero or more entries. |
| $this->fieldarray | This holds all application data, usually the contents of the $_POST array, but it could also contain rows of data fetched from a database. It can either be an associative array for a single row or an indexed array of associative arrays for multiple rows. This removes the restriction of only being able to deal with one row at a time, and only being able to deal with the columns for a single table. This also avoids the need to have separate getters and setters for each individual column as this would promote tight coupling which is supposed to be a Bad Thing ™. |
In my prototype I manually transcribed this metadata into these variables, but I later automated it by building a Data Dictionary.
My method of building an abstract superclass was quite straightforward - I built a concrete class for my first table and then duplicated it for my second table. Instead of hard coding the different attributes I stored them in the common table properties mentioned previously. I then moved all the duplicated code from each concrete class into an abstract superclass which left no code in each concrete class except for the class constructor as everything else was shared through inheritance. The abstract superclass contained code such as the following:
| Methods called externally | Methods called internally | UML diagram |
|---|---|---|
| $object->insertRecord($_POST) | $fieldarray = $this->pre_insertRecord($fieldarray); if (empty($this->errors) { $fieldarray = $this->validateInsert($fieldarray); } if (empty($this->errors) { $fieldarray = $this->commonValidation($fieldarray); } if (empty($this->errors) { $fieldarray = $this->dml_insertRecord($fieldarray); $fieldarray = $this->post_insertRecord($fieldarray); } return $fieldarray; |
ADD1 Pattern |
| $object->updateRecord($_POST) | $fieldarray = $this->pre_updateRecord(fieldarray); if (empty($this->errors) { $fieldarray = $this->validateUpdate($fieldarray); } if (empty($this->errors) { $fieldarray = $this->commonValidation($fieldarray); } if (empty($this->errors) { $fieldarray = $this->dml_updateRecord($fieldarray); $fieldarray = $this->post_updateRecord($fieldarray); } return $fieldarray; |
UPDATE1 Pattern |
| $object->deleteRecord($_POST) | $fieldarray = $this->pre_deleteRecord(fieldarray); if (empty($this->errors) { $fieldarray = $this->validateDelete($fieldarray); } if (empty($this->errors) { $fieldarray = $this->dml_deleteRecord($fieldarray); $fieldarray = $this->post_deleteRecord($fieldarray); } return $fieldarray; |
DELETE1 Pattern |
| $object->getData($where) | $where = $this->pre_getData($where); $fieldarray = $this->dml_getData($where); $fieldarray = $this->post_getData($fieldarray); return $fieldarray; |
ENQUIRE1 Pattern |
Here the methods called externally are the ones which are called from the Controller while the methods called internally are called only from within the abstract table class which is inherited by every concrete table (Model) class. Each external method then acts as a wrapper for a group of internal methods.
Note that this code can perform all the basic CRUD operations on any table up to and including any primary data validation. Additional secondary validation can be added in later.
As I began to develop transactions that required the processing of logic which was unique to a particular table class I realised that I would require a mechanism which allowed me to insert custom logic into the relevant table class and to have that logic executed in the correct place in the processing flow. Due to the fact that every concrete subclass inherits its standard code from an abstract superclass, and that each public method in the superclass is a wrapper for a group of sub-methods which perform discrete steps in the processing flow, I realised that I could implement the Template Method Pattern which would enable the use of customisable "hook" methods. These are methods which have been added into the processing flow within the abstract superclass but which do not actually do anything but return the input data untouched. Some of these are shown with the "pre_" and "post_" prefix in common table methods. They have the following format:
function _cm_whatever ($fieldarray) // interrupt standard processing with custom code // if anything is placed in $this->errors the operation will be terminated. { // customisable code goes here return $fieldarray; } // _cm_whatever
Any of these methods, which do nothing, can be copied into individual subclasses so that they can be programmed to do something which is specific to that subclass. The variable $fieldarray will contain whatever application data is being processed by the current task, and the contents of this array can be examined and/or modified at will. This only works because I am using a dynamic array and not a static structure or a group of class properties.
In the early sample code that I looked at I could see that, after a Model class was created using its own set of methods, it was common practice to then hand-craft a Controller component in order to instantiate the Model class into an object so that its methods could then be called. This produced code similar to the following:
<?php require 'screens/person.detail.screen.inc'; require 'classes/person.class.inc'; $dbobject = new Person(); $dbobject->setUserID ( $_POST['userID'] ); $dbobject->setEmail ( $_POST['email'] ); $dbobject->setFirstname ( $_POST['firstname']); $dbobject->setLastname ( $_POST['lastname'] ); $dbobject->setAddress1 ( $_POST['address1'] ); $dbobject->setAddress2 ( $_POST['address2'] ); $dbobject->setCity ( $_POST['city'] ); $dbobject->setProvince ( $_POST['province'] ); $dbobject->setCountry ( $_POST['country'] ); if ($dbobject->insertPerson($db) !== true) { // do error handling } ?>
This code is tightly coupled (which is a bad thing!) because of the following:
insert method (insertPerson) is specific to that class.These factors make it impossible to use this controller with any other class. If the purpose of OOP is to increase reusability then this is an abject failure.
I played around with my code in order to alleviate these shortcomings and discovered the following:
These revelations enabled me to create code such as the following:
Every script in the application is executed using a combination of 3 types of component - a Model, a View and a Controller. While each one of these may be resued several times, each combination of the three is unique. So when a user transaction is selected how is that selection translated into identifying which of the possible combinations is the one that is required? By using a simple component script as shown below. The URL for each web page in the browser's address bar is in the format <domain>/<subsystem>/<table>(<pattern>)<suffix> where:
<?php // component script $table_id = "person"; // identify the Model $screen = 'person.detail'; // identify the View require 'std.add1.inc'; // activate the Controller ?>
This identifies each component used is a user transaction, as shown below:
It plays the part of a dependency injection container. Note here that none of the dependencies is instantiated into an object. All I do is load their names into global variables. I do not instantiate the Controller into an object and use any of the recognisable methods of injection, instead I simply load the file which contains the code for the Controller which then self-executes. It then uses the contents of the global variables to deal with the dependencies as it sees fit.
<?php // page controller script for the ADD1 pattern require 'classes/$table_id.class.inc'; require 'screens/$screen.screen.inc'; $dbobject = new $table_id; $result = $dbobject->insertRecord($_POST); if ($dbobject->errors) { // do error handling } ?>
This code is loosely coupled (which is a good thing!) because of the following:
Notice here that the Controller has been split into two parts:
Each Controller can produce no more than one View. HTML views use a screen structure file while PDF view use a report structure file. While HTML is is the most common, some Controllers produce CSV output, some produce PDF while a small number do not produce any visible output at all. This is because they do something in the background, such as updating the database or sending an email, then return to the calling screen.
Once practice I saw in other people's code samples which I decided NOT to follow was to use one script to build a web page, but to send the $_POST data to a different script. In my code each Controller handles both the GET and POST requests.
Some of the early PHP samples scripts which I encountered were very primitive in that they would spit out fragments of HTML code while the script was running, which meant that every web page had to be built by hand. I did not like this idea. My previous experience of building hundreds of screen-based desktop programs taught me that all screens contained repeating patterns. However, the ability to take advantage of such patterns was limited by what facilities the programming language offered. The first language to provide screen templates was UNIFACE, which I commented on in The Power of Component Templates. When the language was upgraded to include a web interface it also provided ways to create XML documents and perform XSL transformations, but this was limited by only being able to transform one XML document into a different XML document. When I played with these two new technologies I discovered that XSL could also be used to transform XML into HTML, and the more I played with it the more I liked it. After checking that PHP also had the ability to perform XSL transformations I decided to build all my web pages from XSL templates.
It was relatively easy to create a single object which performed all the processing to create an HTML document of any format for any Model as the steps where identical:
In my first iteration I create a separate XSL stylesheet for each screen as I had to have inline code to identify which piece of data went where on the screen and with what HTML widget. Documentation for this can be found in Generating dynamic web pages using XSL and XML.
After a bit of refactoring I managed to create a list inside the XML document of what data went where on the screen which could then be processed automatically by logic within the stylesheet. This is documented in Reusable XSL Stylesheets and Templates. This replaced the need for a separate stylesheet for each screen with a library of just 12 stylesheets which could be used to produce any screen required for any application component. This is done with the aid of a screen structure file which is initially generated by the framework, but which can be customised by the developer. This is copied into the XML document so that it can be processed during the XSL transformation.
The prototype was so successful I then set about adding the features that would turn it into a reusable framework. This was done in the following stages over a period of time:
I took the database design that I had first used in my COBOL and then UNIFACE implementations and built a new version using MySQL. As I was already very familiar with relational databases and the rules of Data Normalisation this was something I could do with my eyes shut.
Having built the MENU data I then set about creating the screens to maintain its contents. I built the scripts by hand based of those which I had created in my earlier prototype. This involved some additions to my library of Controllers and XSL stylesheets.
My prototype could be accessed by anybody as it did not have a logon screen, so that was another important addition. This involved entering a user_id and password which was checked against the USER table. Later on I added the option to use an email address instead of an id. A system administrator has to create a USER record, so users are not allowed to register themselves.
After passing through the logon screen I created a Home page to display the first set of menu buttons as well as any messages. This involved creating a TASK (or user transaction) with a type called 'menu' instead of 'proc', coupled to a MENU table which contained the list of options for each menu page. This allowed the system administrator to create whatever hierarchy of menu pages that was appropriate for his users.
Instead of allowing every user to access every transaction with the system I needed a system in which the system administrator could define who had access to what. I had encountered various solutions in the previous 20 years, but I decided to build a system based on ROLES, as discussed in A Role-Based Access Control (RBAC) system for PHP. In this way access to individual TASKS is given to ROLES, and then each USER is given access to one or more ROLES using a separate USER-ROLE table.
This then enabled me to modify the code which extracted the options for each menu, as well as the navigation buttons, to only include those options which were accessible by that user. If the user cannot see an option he cannot select it. In this way it is not necessary to create separate sets of menu and navigation buttons for each USER, or even each ROLE, as a single set can be used by everybody, but they will only see what hey are allowed to see.
In my COBOL days it was not unusual for a customer to ask for an audit log which showed what changes had been made to the database. While the design used by others had a separate audit table for each live database table which was populated by a database trigger, I decided that this was too clunky and required too much effort, so I designed an Audit subsystem which used a single set of audit tables to store any changes to any application table. This single set of tables can then be viewed by a single set of screens. Writing to the Audit database is performed automatically by code within the framework. This means that after creating a database table and the transactions around it the developer does not have to do anything extra to perform audit logging. This design also means that the structure of any live table can be changed without having to make any changes to any audit tables. I have also found this to be a useful aid when testing a transaction, especially one that changes several database tables, as you can run the transaction and then examine the audit log to see what affect it had on the database.
The structure of the tables in the AUDIT database does not have to change despite how many tables appear in any application databases, neither is it affected by any structural changes to any application databases. This means that the existing set of screens which view the contents of the audit database do not have to change.
A colleague noticed that several activities involved running a particular series of tasks in the same sequence, and he asked me if I could automate the movement between tasks. He suggested that perhaps I could create a workflow engine based on Petri Nets. When I looked at the description I noticed that each workflow had first to be defined using Transitions, Places and Arcs, and it struck me straight away that the description of each transition matched that of a transaction (use case or activity) in my framework. This enabled me to design and build my own Activity-based Workflow System.
This subsystem has a set of tables which define each available WORKFLOW, which includes PLACE, TRANSITION and ARC, and a set which are used for each workflow CASE which includes TOKEN and WORKITEM. Note that every transition must point to a transaction which performs a database COMMIT as this is the only way that a transaction can be marked as being successfully completed. It is only then that a token can be moved from the input place for that transition to its output place.
Note that when transactions are built they do not require any special code to make them aware that they are part of a workflow. They can be built in the same standard way and may (or may not) be mentioned in a workflow at a later date. All the logic required to handle active workflows is handled by code within the framework.
I originally built the table class files and the table structure files by hand, but as these always followed the same pattern I decided that it would be better in the long run to write some software which could automate this process. I already knew that I could write code to extract information from the application database via its INFORMATION SCHEMA, but as I wanted more information than it could provide I decided to import this data into a new database which I designed called a Data Dictionary. After the data had been imported into this new database I built a series of screens to view this data, and possibly add in some other details, before I exported it into files which could then be referenced whenever a class was instantiated into an object.
Note that this works in the opposite direction to the UNIFACE implementation where the Application Model is built first, then used to export the CREATE TABLE scripts which are required to build the physical database. When application components are constructed they directly reference the contents of the Application Model.
One common complaint I often hear from other programmers is that once they have created a table and the corresponding software that making changes to the table's structure requires complicated and tedious changes to the software. I do not have this problem. Once I have generated the scripts for a database table I can change the table's structure at any time, and all I have to do is re-import the amended structure into my Data Dictionary and regenerate the table structure file. I do not have to change any application logic unless the amended columns are mentioned in any "hook" methods.
Because I had managed to use my powers of observation to spot patterns of similarities in both page controllers and screen structures, thus allowing me to create a small library of completely reusable modules, I was able to document all the possible combinations in Transaction Patterns for web applications. This meant that after creating the class file for a new database table I only needed to create some small scripts in the file system, plus some updates to the MENU database, to produce working transactions to maintain the contents of that table. This again was repetitious work, so I decided to automate it as well. I added some new functions to my Data Dictionary which enabled me to select a database table, link it to a Transaction Pattern, and at the press of a button it would generate the necessary scripts and perform the necessary database updates.
This meant that time between creating a database table and generating the tasks to maintain that table was reduced to just FIVE MINUTES. This was possible because the framework covered 100% of the boilerplate code, so I did not have to write any code whatsoever - no PHP, no HTML and no SQL.
Note here that the framework was developed as a modular system where each subsystem has its own database, its own directory in the file system using a common file structure, and its own entries in the MENU database. Other subsystems, either as additions to the framework or end-user applications, can be added very easily.
It is one thing to create a toolkit for building web applications, but without adequate documentation it can be difficult for developers to become productive with it. As well as the extensive documentation which can be found at https://www.radicore.org/documentation.php I have also produced the following:
My first commercial contract was from a design agency who had been asked to build an administrative application for a Scottish distillery. It included a requirement for a Role Based Access Control system for which they had no knowledge. Having read what I had published on the internet regarding this very topic, and realising that they had no knowledge of how to use the framework, they asked me If I could write this application for them. This I did, and it was delivered on time and within budget. The end-user was pleased with the result, which made the design agency pleased with the result.
The design agency then spoke to me about another opportunity. They had several other clients asking for similar administrative applications, but instead of writing a separate bespoke application for each one they asked me if I could build a general purpose ERP software package that could be used by multiple clients which would result in a lower cost for each one. I was up for the challenge, so I agreed.
As I knew that the heart of any database application is the database design (NOT the software as that is just an implementation detail), I started by picking out some databases from Len Silverston's Data Model Resource Book. I had been introduced to that book a few months earlier, and I immediately recognised how comprehensive and flexible they were. I picked six databases from this book as the starting point for my new endeavour - PARTY, PRODUCT, ORDER, INVOICE, INVENTORY and SHIPMENT - then went through the same procedure for each one:
I started this development process in early 2007, and at the end of six months I had my first working prototype ready to demonstrated to the client. That is six subsystems in six months, which equates to an average of one man-month for each subsystem. Does that qualify for the title "Rapid Application Development" or what?
This package was given the name TRANSIX and the design agency and myself joined as partners in a new company in October 2007 called Transition Engineering. After this prototype was demonstrated to the first customer I spent the next six months converting their existing front-end e-commerce application. This involved transferring all the data from their old database to the new one so that it could be maintained using the new back-office functions. I then updated their existing application to replace all the functions which accessed the old database to switch to the new one. I also added in some new functionality which would have been difficult to add into the old system but not so difficult with the new one. This exercise took another six months, and the new software went live in May 2008.
Shortly after I was asked to add several more subsystems - WORK_EFFORT (for timesheets), REQUESTS/REQUIREMENTS and CONTENT. Each of these required their own database, so they were easily added as new subsystems.
My partnership with Transition Engineering ended in 2014 after which I joined Geoprise Technologies as R&D Director. They had originally used my framework to build a small application of their own, but when I gave them a demonstration of my ERP application they were so impressed that they suggested a partnership so that they could market it across the globe instead of being limited to the UK. It now goes under the name GM-X Application Suite and has been enhanced with the addition of several new subsystems:
This helped it being adopted by multi-national corporations in the Far East as well as the USA.
In 2017 I enhanced the framework by adding in an option to switch all the HTML screens from the traditional interface to responsive web so that the functions could be used on tablets and mobiles as well as desktops. This involved creating a new set of XSL stylesheets which use the Bootstrap library and a small modification to the View component to alter some data which is inserted into the XML document. This was completed in one man-month and was instantly effective across all the application subsystems. How many developers can say that they upgraded 4,000 classic HTML forms in one man-month to include a responsive interface?
In 2018 I enhanced the framework by adding in an option to send database updates from nominated tables to collaborating organisations over a private blockchain. This can be used, for example, for an organisation to communicate with its suppliers so that it can send Request for Quotations (RFQs), receive Quotations, send Purchase Orders, Receive Advance Shipment Notices (ASNs) and receive Invoices. Once the organisation creates a private blockchain other collaborating organisations can be invited to join it, so that messages can be exchanged over a secure network. This involved creating a new subsystem to identify what pieces of data should be sent and under what circumstances and did not involve changing any application code.
A more recent enhancement allowed Geoprise to announce in August 2026 the First-Ever OpenAPI Bridge To Fully Connect ERP and Agentic AI, which makes it the first ERP system to expose every one of its functions to Model Context Protocol (MCP) servers through application programming interfaces (APIs) that are compatible with the OpenAPI Specification (OAS).
Note that unlike its legacy counterparts GM-X is licensed per server, so the number of users is not a factor. It is also a modular system whereby organisations need only pay for the modules which they actually use.
Trying to learn which programming practices are good and which aren't is a difficult process when some of those practices are badly written or which are decades behind the times. Something written specifically for a strictly typed language can be totally irrelevant in a dynamically typed language. I have identified in this article where polymorphism is an essential ingredient to dependency injection (DI) which in turn contributes to code which can be reused instead of duplicated, but I have found the definition of these practices to be less than helpful. I often use wikipedia as my go-to source of useful information, but some it contents are bordering on the edge of useless. Take the following as examples:
In programming language theory and type theory, polymorphism allows a value or variable to have more than one type and allows a given operation to be performed on values of more than one type.
In object-oriented programming, polymorphism is the provision of one interface to entities of different data types.
The phrase "values of more than one type" seems ridiculous to me as a data item can have only one type where the choice is between those shown in the PHP manual. A data item cannot have several types as they are mutually exclusive.
As for classes and objects, the manual at says the following:
Classes are types, that is, they are blueprints for actual variables. You have to create a variable of the desired type with the new operator.
The idea that an object can not only have a type but can have several different types is also an alien concept to me. If you use the gettype() function on an object the only value you will ever see is "object". There is no documented mechanism whereby you can give an object a different type let alone more than one type.
In Polymorphism and Inheritance are Independent of Each Other it says the following in one place:
Polymorphism is the ability to send a message to an object without knowing what its type is.
Yet in an example a few lines down it says:
The cars array is of type Car and can only hold objects that derive from Car (VolkswagenBeetle and SportsCar) and polymorphism works as expected. If you give it a Jalopy object which contains the common start() method but which is not derived from Car it will generate a type error.
In PHP objects do not have discernible types, therefore polymorphism is neither allowed nor restricted by type. All that is required is that a group of objects share the same method signature. This is usually achieved through inheritance but need not be. It is possible to duplicate the same methods manually in several classes without inheriting them from a superclass. While some poorly trained programmers have problems with inheritance that is because they have failed to use it correctly, which is to only ever inherit from an abstract class.
In software engineering, dependency injection is a programming technique in which an object or function receives other objects or functions that it requires, as opposed to creating them internally. Dependency injection aims to separate the concerns of constructing objects and using them, leading to loosely coupled programs. The pattern ensures that an object or function that wants to use a given service should not have to know how to construct those services. Instead, the receiving "client" (object or function) is provided with its dependencies by external code (an "injector"), which it is not aware of.
The idea that this is connected to the principle of Separation of Concerns (SoC) (which, incidentally, is the same as the Single Responsibility Principle) is totally wrong. Those principles were not created to separate two simple lines of code. It shows that the author came to the wrong conclusion after looking at samples of how this principle could be implemented. In compiled languages you cannot instantiate a class into an object without specifying the class name as a literal, as in the following:
require 'classes/person.class.inc'; $dbobject = new Person();
PHP, being dynamically typed, does not have this restriction, so it is possible to supply the class name in a variable, not a literal, as in the following:
require 'classes/$table_id.class.inc'; $dbobject = new $table_id;
The contents of $table_id is defined elsewhere in a component script. In my ERP application which has 400 table classes, there are 400 variations of this other script. This is how I take advantage of what polymorphism has to offer.
Note here that the creation of an object does not require anything other than the new operator. I do not need to waste time with a factory method as each class only one configuration, and that is taken care of in the class constructor.
It is well documented that there may be several different wasys in which a dependency can be injected into a client object. If an object has several dependencies an alternative approach to injecting them individually is to use a Dependency Injection Container (DIC) instead. The DIC is an object in which all the dependencies are constructed and then this single object is injected into the client where the dependencies are extracted one by one. As example of this is shown in An orthodox version of a DI Container. My own method of specify an object's dependencies is unorthodox. ???
In all the articles and blog posts I have read on polymorphism and dependency injection I have never seen a link between the two. While providing various descriptions of what polymorphism is, absolutely no-one has stated what you can do with it once you have created it.
While static structures do not exist in PHP at the moment there have been several RFCs which have attempted to address this, such as this one in 2020 and this one in 2024. I totally oppose this for the reasons I have stated above, that static structures produce tight coupling which then eliminates software reuse via polymorphism, as does the use of separate class properties for each table's column. As stated in Designing Reusable Classes which was published by Ralph E. Johnson & Brian Foote in 1988, a major motivation for object-oriented programming is software reuse, so anything which reduces the production of reusable software is a move in the wrong direction. Anyone who cannot see that should never aspire to becoming a rock star programmer as they will never be anything more than a rocks-in-the-head programmer.
Spotting code that can be converted from duplicated into reusable appears to be a skill that few have mastered. Application code can be split into two basic categories - business logic which is unique and therefore unsuitable for reuse, and non-business logic (often called boilerplate code) which appears in multiple places. It is this non-business logic which is a prime candidate for conversion into reusable modules, and I have used my own meagre skills to create a framework which provides 100% (yes, ONE HUNDRED PERCENT) of this boilerplate code out of the box. This is why a developer can create a database table, then generate and then run the scripts to maintain that table in under 5 minutes and without having to write a single line of code - no PHP, no HTML and no SQL. Although this only provides basic functionality and data validation, my implementation of the Template Method Pattern means that custom code can be added very easily using any of the pre-defined "hook" methods.
I have been told by my critics, of whom there are many, that I do not "get" what OO is and, by not following their interpretation of best practices, that my methods are totally wrong and the code I produce is rubbish. According to them the "correct" approach is for each Model to have its own Controller and its own Repository/Mapper. That idea strikes me as being contrary to the aims of OOP as each Controller is tied to a single Model, and each Model is tied to a single Repository, and this arrangement has absolutely zero reusability. This is because there is zero polymorphism and zero opportunity to inject different Models into the same Controller.
Using my RADICORE framework I have developed an ERP application which contains over 400 database tables with a separate Model class for each. If I were to follow the "traditional" approach which is advocated by my critics I would end up with 400 Controllers and 400 Repositories, but instead I have just 45 reusable Controllers and 1 Repository for each supported database. These are all pre-written, built into the framework, and can be reused by any application component. I think you should agree that this represents a huge reduction in the amount of code a developer has to write in order to get his application up and running. This takes care of all the common boilerplate code and leaves the developer with nothing to do but add in the unique business logic.
Below is a summary of the simple steps I went through to create this outcome:
A Car and a Train and a Truck can all inherit behavior from a Vehicle object, adding their subtle differences. A Firetruck can inherit from the Truck object, and so onwhich is taken to mean that each type of vehicle requires its own (sub)class. This is utter nonsense. In my database I have a VEHICLE table which contains a column called VEHICLE_TYPE. This means that every vehicle, regardless of its type, has its data on the same database table. This single database table can be handled by a single class. I can add to the list of possible vehicle types without having to create a new class and without having to change any code which decides which class to use. I would never create a separate table for each vehicle type, so why should I create a separate class?
I do not consider myself to be superior to other developers, just less incompetent. If I can follow a few simple steps and eliminate 100% of boilerplate code then why can't this be matched by any of the so-called "experts" out there? Answers on a postcard to .....