There are many disciplines in life in which there may be more than one way of achieving an objective. Computer programming is no different in that it depends on what resources are available. Just as the internal combustion engine could not be invented until parts could be manufactured to tight tolerances and a suitable fuel supply became available, the things that a programmer can achieve are limited by the resources which are available:
There is also a third resource, and that is the intellect of the individual programmer. Programming is an art, not a science, and to be a good artist one must have talent. While a talented programmer can write code which is cost-effective, which also means that it is elegant, a hacker will just hammer out code by copying what other people have done and assume that just because it works that he has done all that is required. Not so. If two programmers write similar programs, but one writes better code in half the time, then who will be considered to be the better, more productive programmer? It is the result which counts, not the amount of code, nor the number of design patterns which are used which should be the deciding factor.
In this article I shall compare two different sets of practices - the official set of "best practices" which are backed by so-called OO "experts", and my personal practices - and explain why my personal practices are better for the simple reason that they achieve superior results with less code and make me more productive. The importance of productivity is explained in more detail in Programmer Productivity takes Precedence over Paradigm Purity.
Before I began my journey into PHP with its OO capabilities I asked the question "What is OOP?" and I found the following answer:
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.
I then asked the question "How is it different from Procedural Programming?" and I found the following answer:
Object Oriented programming is exactly the same as Procedural programming except for the addition of encapsulation, inheritance and polymorphism. They are both designed around the idea of writing imperative statements which are executed in a linear fashion. The commands are the same, it is only the way they are packaged which is different. While both allow the developer to write modular instead of monolithic programs, OOP provides the opportunity to write better modules.
In his paper Encapsulation as a First Principle of Object-Oriented Design (PDF) the author Scott L. Bain wrote the following:
OO is routed in those best-practice principles that arose from the wise dons of procedural programming. The three pillars of "good code", namely strong cohesion, loose coupling and the elimination of redundancies, were not discovered by the inventors of OO, but were rather inherited by them (no pun intended).
These descriptions had great influence on the code which I subsequently developed. I chose those techniques which increased the amount of reusable code at my disposal, which produced high cohesion and low coupling. Any practice or principle which failed to meet these objectives was flushed down the toilet. I am a pragmatist, not a dogmatist, which means that I am results-oriented, not rules-oriented.
In the first 20 years of my programming career, which is before I switched to PHP with its OO capabilities, there was no such thing as a catalog of "best practices" which were universally applicable. Each team of developers was responsible for its own standards, and when I became team leader in a software development company I was directly responsible for creating the company standards, first in COBOL and then in UNIFACE. When I switched to developing with PHP in 2002 I saw no reason why I should not carry on this tradition. I explored the different ways in which the language could be used to achieve results, and out of the numerous possibilities I chose the practices and methods which followed the KISS principle. The steps that I took are outlined in the following
While learning PHP I had found some valuable resources on the internet, so I tried to return the favour by publishing my own articles, and even a small sample application, to demonstrate my approach. Imagine my surprise when I was attacked by fellow developers for daring to write software without following "best practices". They did not realise that I *AM* following a set of "best practices", but ones which are not the same as theirs. I examined their recommended practices and quickly saw that by following them I would not improve my codebase in any way but instead degrade it by filling it with useless bloat.
The biggest problem I see with these "best practices" is that they were constructed by different people, with different skill sets, using different languages, at different times. A lot of ideas were published by researchers and academics experimenting with languages rather than building commercial applications, so they spent their time solving theoretical problems rather than "real world" problems.
There has never been a single repository for all these ideas. Before the rise of the internet some of them were published as papers by organisations such as OOPSLA or individual universities which were subject to peer review. Since the internet has burst onto the scene it seems that anyone and his dog can throw their own unfiltered ideas into the mix, and I'm afraid that this situation now qualifies as too many cooks spoil the broth. Quite often someone creates a principle which had already been written about before but with a different name (such as the Single Responsibility Principle (SRP) and Separation Of Concerns (SoC)), or sometimes used the same name to describe a different principle (such as Inversion of Control (IoC) which was originally meant to invert the flow of control but was then corrupted by the Java community to mean dependency injection, or object composition which sometimes means the alternative to inheritance and sometimes means the response to the "HAS_A" test). More areas of confusion can be found in From Oop to Poop, from Excellent to Excrement.
While some general principles can be universally applicable, such as KISS, COUPLING, COHESION, YAGNI and DRY, those which were developed for particular languages may not be applicable in other languages. For example, practices written for compiled, strictly typed languages which use structs may be totally out of place in those which are scripted, dynamically typed and which use arrays. Practices written for bitmapped GUIs may be totally out of place for HTML processing. Practices written for simple file systems may be totally out of place for modern relational databases.
When somebody criticises me for not following best practices I can legitimately ask the question "Which best practices?" When they say "the ones published here" I can legitimately say that I am using "those which were published somewhere else". The fact that I am following practices which were not personally approved by you is irrelevant. I follow those practices which allow me to achieve the best results, and all the while I can achieve better results and be more productive than you I do not see why I should switch to following an inferior set of practices just to be consistent with you.
Below I list the savings which I made by NOT following their "bad practices":
I did not need to change my design process just because my development language had changed. My previous experience had taught me that in a database application the most important part is the database design, so I still design my database first, then build the software to work with that design. As far as I am concerned the programming language used is just an implementation detail. As I progressed from COBOL to UNIFACE to PHP the facilities of each language allowed me to develop faster and with more options, but the overall design process remained the same.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
This approach dictates that the structure and language of the software code (class names, class methods and class variables) should match the business domain where each "domain" covers a different subject area or sphere of knowledge. I have been writing database applications for businesses, known as enterprise applications, for 40 years, and while they can cover a large number of different subject areas, such as customers, product, orders, invoices, inventory, shipments, etc, I do not regard these as requiring different approaches in their design. They are nothing more than sub-domains within a larger domain which is that of a database application, the rules for which are absolutely identical apart from the structure of each database. That is why they are developed as different sub-systems within a larger system under the RADICORE umbrella.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
I had always assumed that Object Oriented Programming was exactly the same as Procedural Programming except for the addition of Encapsulation, Inheritance and Polymorphism. They are both designed around the idea of writing imperative statements which are executed in a linear fashion. The commands are the same, it is only the way they are packaged which is different. While both allow the developer to write modular instead of monolithic programs, OOP provides the opportunity to write better modules. Imagine my surprise when I was told that it was much more complicated than that. I have replied to this ridiculous idea in What is the difference between Procedural and OO programming?
More details can be found in A minimalist approach to Object Oriented Programming with PHP
I do not design my software first using questionable OO practices and then design my database using the rules of Data Normalisation as I know that the two approaches would produce incompatible results known as Object-Relational Impedance Mismatch. By designing my database first, then building my software around this design, I avoid the mismatch and thus avoid the need for any sort of mapper.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
I do not need to go through the list of design patterns before I decide which ones to use in my code for the simple reason that all the relevant patterns have already been built into the framework. These are as follows:
Unlike Design Patterns which are nothing but descriptions of designs which you have to implement yourself I get greater results with my Transaction Patterns which provide pre-written and reusable code. Using the facilities in my Data Dictionary I can build new transactions (use cases) by pressing a few buttons instead of writing code.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
This is made up of the following:
This is made up of the following:
The first time I came across the rule favour composition over inheritance I thought it had been written as an April Fool's joke. I could not understand how one of the three pillars of OOP could interfere with one of the other pillars. Nobody could explain exactly what the problem was, so I treated it as a joke. Eventually I discovered that the problem was not within the concept of inheritance itself, but the faulty way in which it was being implemented. In other words a good idea was being trashed because of bad programming.
The correct way to use inheritance and so avoid any problems is to only ever inherit from an abstract class, which is exactly what I did when I wanted to share code between several concrete table classes.
More details can be found in Composition is a Procedural Technique for Code Reuse and Inheritance is NOT evil.
A lot of programmers are told that "decoupling" their software is a good idea, but this shows a complete lack of understanding of what the term coupling actually means. Several different ways are given to achieve this decoupling:
If one module calls another then those two modules are coupled. This coupling can either be tight (bad) or loose (good). Decoupling means to remove the coupling which means to remove the call.
More details can be found in Decoupling is delusional and Confusion about the word "coupled".
The traditional method requires far too much effort and produces objects which are tightly coupled instead of being loosely coupled. My personal method, which was devised after observing the Standard patterns in every database application, is far quicker because it uses reusable code which allows the Model classes to be generated by the framework instead of being manually created by the developer.
Some people say that a Model can only be accessed by a single Controller. I disagree. It is a feature of my framework that any Model can be accessed by any number of Controllers.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
As soon as I noticed that data from both an HTML form and an SQL database appears in a PHP script in an array I wondered why far too many programmers were wasting time and effort in splitting the array into its component parts and feeding each part in one at a time. Because each column then requires to be named explicitly in separate lines of code this has the effect of requiring all objects which use that data to be tightly coupled. This is bad as it eliminates the possibility of having polymorphic methods without which you cannot take advantage of dependency injection which then eliminates the possibility of having reusable modules. This then defeats the purpose of using OOP in the first place as it is supposed to help the developer increase the amount of reusable code. Practices which help create code which cannot be reused are therefore bad and should be avoided. Developers should always aim to produce code which is loosely coupled.
By using a single $fieldarray variable to hold all application data I totally eliminate all these obstacles and allow the framework to pass data from one module to another with standard code which does not mention any column names. This then increases the amount of polymorphism in my application which in turn means that I can employ dependency injection in my Controllers and Views which makes them reusable with any Model. It also means that I can vary the contents of this array at any time without having to amend any method signatures.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
I often see sample code for table classes in which the method names for the CRUD operations is a combination of the operation and the table name, as in insertCustomer()
, getCustomer()
, updateCustomer()
and deleteCustomer()
. This is bad because by including the table name in the method name you are forcing the Controller which calls those methods to be tightly coupled to the Model which contains those methods. This destroys any chance of polymorphism as those methods are not reusable.
In order to switch to loose coupling and make every method in every Model polymorphic I created a set of common table methods which are inherited into every model class by being inherited from an abstract table class. The contents of the abstract class are reusable, and because of the resulting increase in polymorphism I can use dependency injection to inject any Model into any Controller. In this way I have been able to build a fixed set of reusable Controllers into my framework, one for each Transaction Pattern.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
The traditional method requires a separate Controller to be manually constructed for every Model. This is normally the result of each Model having its own set of setters and getters which results in each Controller being tightly coupled to its one-and-only Model. Another mistake is to have all the use cases for a Model being handled by a single Controller.
Instead of having a separate Controller for each Model, which prevents the Controller from being shared, my own technique is to have a separate Controller for a particular use case which can then linked with any Model in the application. This is made possible because of my loosely coupled design.
Some people say that a Controller can only access a single Model. I disagree. It is a feature of my framework that a Controller can access any number of Models.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
Some people design and build each HTML page by hand, then write lots of code to fill it with data. My decades of experience has allowed me to spot repeating patterns which I have turned into reusable code. While each screen is different, in a large collection of screens there are similar structures which I provide using pre-written templates. There are also similar patterns of behaviour, which I provide using pre-written Controllers. Each screen has data which is obtained from an application database, and that is supplied by any of the Model classes. Because I can extract all the application data from a Model using the single getFieldArray() method I do not need to write any code to extract data before I inject it into the template and transform it into HTML.
By combining different combinations of structure and behavior I have created a series of reusable Transaction Patterns which I can link with any Model to provide a working user transaction. I have used 45 patterns to create over 4,000 different user transactions.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
Some developers create a separate DAO for each Model class. Some developers claim that a Model class can only read data from the one table that it supports, thus preventing any SQL query from performing a JOIN. Some developers claim that a Model class can only deal with one row at a time. Some developers create a query object that requires a whole series of methods to help build complex queries.
Those are all the acts of amateurs. I do not build in any of those limitations in my software, instead I build my software to take advantage of all the facilities that an SQL database provides. I have a separate DAO for each supported DBMS which can handle any valid SQL query, which includes JOINS, Common Table Expressions (CTE) and multiple rows. I do not waste time building an SQL object to construct any queries as a query is just a string which is comprised of substrings, and PHP's string handling functions are more than adequate for the task.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
Far too many developers have to insert code into each Model class to validate user input. This is required in order to prevent an SQL query failing because a column's value does not match its specifications in the database. Clueless newbies don't know how this process can be automated, which is why they keep doing it manually.
An experienced programmer knows how to extract useful information from the INFORMATION_SCHEMA which exists in every database and place it in a table structure file so that it can be easily accessed within the software. Coupled with a single $fieldarray variable to hold all application data means that I can have a standard procedure within the framework to handle all data validation.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
Separate methods require separate components to call those methods, and vast collections of unique method names eliminate the possibility of sharable code.
My personal choice is to rely on separate component scripts in the file system which are generated and handled using standard code within the framework.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
Class hierarchies are created when following the "IS-A" rule in order to create a hierarchy of types and subtypes.
This is not how databases work as there is never a separate table for each subtype, so there is no reason to have a separate class for each subtype. Each subtype is nothing more than a different row in the same table. This class hierarchy also causes problems as it inherits from a concrete superclass. You can avoid such problems by only ever inheriting from an abstract class.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
The definition of Association states that it defines a relationship between classes of objects that allows one object instance to cause another to perform an action on its behalf.
This gives the novice programmer the idea that there must be special code inside one (or more) of the associated objects in order to deal with the association.
Databases do not have associations, they have relationships, and every relationship requires nothing more than the child table having a column which contains the primary key of an entry on the parent table. This column is then known as the foreign key. All the processing for any relationship can be carried out by standard code in the framework, therefore there is no need for any special code to be inserted into a table class,
I have one simple rule when creating classes which represent database tables - just as a table can only be a container for columns, a table class can only contain properties for its columns. A table cannot contain another table, therefore a table class cannot have another table class as a property.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
An Aggregation implies that the contained class can exist independently of the container. If the container is destroyed, the child is not destroyed as it can exist independently of the parent. An aggregate will have one of its component objects be the aggregate root. Any references from outside the aggregate should only go to the aggregate root. The root can thus ensure the integrity of the aggregate as a whole. Objects outside the aggregate are allowed to hold references to the root but not to any other object of the aggregate. The aggregate root checks the consistency of changes in the aggregate.
This is not how databases work, so it is not how my software works. An aggregation is nothing more that a collection of one-to-many or parent-child relationships, and I have standard mechanisms built into my framework to deal with relationships, so I do not need custom code within any Model class. In this example no entity has a foreign key to its parent as it may have multiple parents. The existence of any relationship is therefore maintained on a separate table which has two foreign keys, one for the parent and one for the child, which point to the same entity table.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
A Composition implies that the contained class cannot exist independently of the container. If the container is destroyed, the child is also destroyed. Each contained class may also be a container for other classes.
Unlike the aggregation described above each entity has its own foreign key which points to just one entry in its parent table, and this foreign key cannot be null. An entry on a parent table cannot be deleted unless all related entries on the child table(s) have already been deleted.
More details can be found in A minimalist approach to Object Oriented Programming with PHP
I stated earlier that each program, which implements a particular user transaction (use case), follows a similar pattern by executing one or more CRUD operations on one or more database tables, perhaps with some extra business logic thrown in for good measure. The standard boilerplate code is provided in pre-written modules (the abstract class for every Model, a pre-written set of Controllers, and a pre-written set of XSL stylesheets for HTML screens (the View). So how does a developer create a transaction from all these components? By using the functions which have been provided in the Data Dictionary.
Using the RADICORE framework I am able to build new user transactions in minutes rather than hours because of my library of Transaction Patterns which provide all the boilerplate code which is necessary to put data into and get data out of the database. This leaves me with nothing to do but insert business logic into the pre-defined "hook" methods. It should therefore follow that when an analyst comes to write a detailed program specification for a programmer to follow that it should not be necessary to describe all that sharable boilerplate code as this never changes. It also has its own documentation. The description of each Transaction Pattern covers such things as the look and feel of any screens or reports and how the program should behave. All that should be necessary should be as follows:
Note that UML diagrams for each of the CRUD operations are also available.
My critics are quick to point out that I developed my original codebase in PHP4 and have not embraced any of the new and "cool" OO features that have appeared in PHP5 and beyond. They claim that the object model in PHP4 was totally inadequate, but I strongly disagree. It supported Encapsulation, Inheritance and Polymorphism, which, according to Bjarne Stroustrup (who designed and implemented the C++ programming language) was all that was necessary. In section 3 of his paper called Why C++ is not just an Object Oriented Programming Language he said the following:
A language or technique is object-oriented if and only if it directly supports:
- Abstraction - providing some form of classes and objects.
- Inheritance - providing the ability to build new abstractions out of existing ones.
- Runtime polymorphism - providing some form of runtime binding.
As far as I am concerned the only thing missing in PHP4 was the term "abstract" from class definitions, but that did not stop me from creating what I called a generic table class which is inherited by every one of my concrete table classes. Everything added to PHP5 onwards I regard as an optional extra, and as I cannot find a good reason to use them in my code I choose not to use any of them. There are two reasons for this:
Below I list some of these features which I don't use and explain why I don't use them.
A lot of programmers are taught to produce program documentation by putting docblocks in their code so that it can be extracted and either printed or converted into HTML pages.
I have never used docblocks for one simple reason - while the result may be technically accurate it is too sparse and only describes the input and output arguments for individual functions and methods. I am used to writing (and reading) documentation which describes the big picture and not individual components.
I have written further on this topic in A minimalist approach to Object Oriented Programming with PHP
The argument for adding object interfaces to PHP was given as Other languages have interfaces, so PHP should have then too
. This is a pathetic argument as they are as useful as a chocolate teapot. They were designed to deal with a problem which does not exist in PHP, therefore they have no useful purpose. I personally think that abstract classes are miles better.
I have written further on this topic in the following:
When these were originally added to PHP5 I assumed that the word "hint" meant that you could declare against each function parameter what its type should be for no other purpose than to have that hint displayed in the function signature when it was displayed by your IDE. I had no idea that it actually meant "type enforcement" even though originally it could only work with object names.
As I had already been taught to give names to all my arguments, parameters and variables which hinted at their types I saw no reason to go back to my codebase and change it to include a feature that did not serve a useful purpose.
PHP was designed from the outset to be a dynamically typed language, as explained in RFC: Strict and weak parameter type checking where it says the following:
PHP's type system was designed from the ground up so that scalars auto-convert depending on the context. That feature became an inherent property of the language, and other than a couple of exceptions - the internal type of a scalar value is not exposed to end users.
This was because PHP was designed to work with HTML forms at the front end and SQL databases at the back end, and both of these technologies present their data to PHP in the form of arrays of strings. If you pass one of these string values to a function which requires a value of a particular type then PHP will use its Type Juggling capabilities, so there was absolutely no need to include code to convert each value into a particular type. The only requirement is to include code to check that each piece of user input is consistent with its type in the database so that the generated SQL query will not fail, but it is not necessary to perform any type conversions. In the RADICORE framework there is a standard validation object which performs this procedure automatically.
I have written further on this topic in the following:
Namespaces were designed specifically to deal with name clashes when importing a third party library into your application, so are only required in those third party libraries.
RADICORE is not a library, it is an extendable application, so does not need namespaces as the only clashes could be with PHP classes, functions or constants Any such clashes would cause a compilation error, so would be detected and corrected before the code was released.
Further discussion on this topic can be found in the following:
Autoloaders were designed to solve the problem of developers having to write long lists of include/require statements at the beginning of each script before their classes can be instantiated into objects. This "problem" is created by the fact that developers fail to follow the principles of encapsulation and cohesion (and hence the Single Responsibility Principle) and split what should be a single class for each entity into a series of micro classes. Even worse, instead of maintaining each of these classes in the same directory they are spread over a hierarchy of subdirectories.
I see this as a bad solution to a self-inflicted problem caused by clueless newbies not understanding the basic practices of good programming.
I have not written any include/require statements for nearly two decades for the simple reason that they only exist in my reusable Controller scripts, and they were all written years ago. This is a case of I don't have that problem, therefore I do not need that solution
.
Further discussion on this topic can be found in the following:
The idea of using comments in code to define metadata which affects runtime behaviour goes against everything I have ever learned in my career in IT. Code is code, data is data, comments are read by humans, but are never executed.
I found a way 20 years ago to incorporate this metadata into my code in a traditional way without using comments and without having it embedded it in my code. I export this metadata from the database's INFORMATION_SCHEMA and write it to a table structure file which is loaded into the object using standard code in the class constructor. I do not have to process this metadata through the Reflection APIs before I use it, and I can update it at any time without having to change any class files.
Further discussion on this topic can be found in the following:
Value objects are used for class properties instead of scalars to satisfy the whims of those OO purists who cling to the belief that "everything is an object". Value objects are not supported in PHP as all the data sources (HTML at the front end and SQL at the back end) present their data as arrays of primitive values or scalars. It is possible to build and maintain value objects in userland code, but that takes a great deal of effort.
I can achieve what I need to achieve using scalars, and have done for 20 years, so changing my code to convert scalars to objects and then back again would not add value, it would just add bloat.
I have written further on this topic in Value objects are worthless.
Object identity is the fundamental property of every object that it is distinct from other objects. If it is fundamental then what is its format? When is it created? Where does it come from? Why is it not created each time I instantiate a class into an object?
Object identities are not mentioned in the PHP manual, nor were they mentioned in any online tutorials or books that I read when I was learning PHP. They do not exist in the real world, they are a myth.
I have written further on this topic in A minimalist approach to Object Oriented Programming with PHP.
Generators provide an easy way to implement simple iterators without the overhead or complexity of implementing a class that implements the Iterator interface.
I have never required the services of a generator, so I don't use then as that would be a violation of the YAGNI principle.
Enumerations are a restricting layer on top of classes and class constants, intended to provide a way to define a closed set of possible values for a type.
I first came across the enum datatype in MySQL where they provide an associative array of internal values and their external representations for use in populating dropdown lists or radio groups. I stopped using them when I began supporting other DBMS engines which did not recognise that datatype. I worked out a simple solution using bog standard code over 20 years ago, and I see no reason to switch to something which is far more complicated.
I have written further on this topic in A minimalist approach to Object Oriented Programming with PHP.
Fibers represent full-stack, interruptible functions. Fibers may be suspended from anywhere in the call-stack, pausing execution within the fiber until the fiber is resumed at a later time.
That sounds very clever, but it gives me no idea of the circumstances under which they would be useful. If I don't know where they would provide benefits in my application