The purpose of this document is to answer my critics who insist on claiming that my methods of implementing the principles of OOP, as shown in my RADICORE framework, are inferior, wrong, impure and "not proper OOP" despite the fact that I can prove that my results are superior to theirs. They claim that I am not following "best practices" when what they actually mean is that I am not following the same set of practices as them. By constantly promoting their questionable versions of "best practices" and miscomprehension of basic programming principles, by constantly criticising me for having the audacity to voice an opinion which is different from theirs, by constantly promoting pedantry and dogmatism over pragmatism, these people are steering the next generation of computer programmers down the wrong path. This will, in my humble opinion, prevent them from creating efficient and cost-effective software, so can have nothing but a detrimental effect on the whole of our industry.
I did not create my RADICORE framework in a single moment of inspiration, it evolved over a period of several decades after building one database application after another while being part of different teams in different organisations using several different programming paradigms. I was exposed to several different variations of "best practice", but after concentrating on those ideas which produced the best results with the fewest problems I graduated from creating libraries of reusable code to creating frameworks which increased the productivity of all the programming teams which I led. You can read the full story in Evolution of the RADICORE framework.
All of today's novice programmers are taught that object-oriented programming languages are better than non-OO languages, but is this true? While they are different (as explained in What is the difference between Procedural and OO programming?) their use does not guarantee that the results will be automatically superior. Only someone who has spent time developing software in a non-OO language and then switched to developing the same type of software in an OO language is actually qualified to make that kind of judgement. I spent the first 20 years of my software career in the development of database applications using non-OO languages such as COBOL and UNIFACE, and then the last 20 years developing the same type of application using PHP with its OO capabilities. I know from personal experience that simply using a language that has certain capabilities does not guarantee that you will automatically produce good software, it is how you make use of those capabilities which counts. It is possible for a crap programmer to write crap code in any language just as it is possible for a good programmer to write good code in the same languages. It is not what you use that counts, it is the way that you use it.
It is simply because that I have been developing database applications for 40 years using different languages and different paradigms that I feel qualified in judging if one one language is better than another. Because each new language has new capabilities it should be possible to use these new capabilities to be more productive. If this is not the case then you must be doing something wrong.
Switching from one programming paradigm and/or language to another should not be undertaken lightly. There should be some discernible benefits otherwise you will be taking a step backwards. In some cases your employer may want to switch to a new language as the current one may not provide the facilities that make your applications more attractive to customers. This is why in the 1990s my employer switched from COBOL, with its simple green screen technology, to UNIFACE which provided a GUI which supported additional controls such radio buttons, checkboxes and dropdown lists as well as being able to access quite easily a variety of relational databases. I switched from UNIFACE to PHP in 2002 after I saw that the future lay in web-based applications, and a particular project convinced me that UNIFACE was too clunky to be of practical use. I looked for a replacement language and chose PHP as it was better suited to the development of web-based applications. I was also very impressed with how easy it was to produce results with simple code.
Using a language with OO capabilities is no good unless you learn how to make proper use of those capabilities. I had heard about this new paradigm called Object-Oriented Programming, but I didn't know exactly what it was nor why it was supposed to be better. I read various descriptions, as shown in What is Object Oriented Programming (OOP)?, but none of them seemed to hit the nail on the head as much as 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.
Using a new paradigm just because it is different is one thing, but this new object-oriented approach was claimed to be better because it supposedly provided benefits such as:
The power of object-oriented systems lies in their promise of code reuse which will increase productivity, reduce costs and improve software quality.
OOP is easier to learn for those new to computer programming than previous approaches, and its approach is often simpler to develop and to maintain, lending itself to more direct analysis, coding, and understanding of complex situations and procedures than other programming methods.
So much for the promises, but what about the reality? Could OOP live up to all this hype? How easy would it be to write programs which are Object Oriented? Would I actually be able to achieve the objectives which were promised?
I did not go on any training courses, instead I read the PHP manual, bought some books, and found some articles on the internet which other developers had written as an example of how things could be done. I noticed straight away that each author's ideas were completely different from everybody else's, so I experimented on my home PC to find the best solutions for me. My objective was to produce as many reusable components as possible, thus being able to achieve results by having to write less code. This I have done, as shown by the Levels of Reusability which are provided in my framework. However, my critics (of whom there are many) insist that my results are invalid simply because I am not following their interpretations of "best practices". I am results-oriented, not rules-oriented, and my customers pay me for the results I achieve, not the rules which I follow. I refuse to follow their rules for the simple reason that it would degrade the quality of my work.
Here is a definition which I found for "best practices":
Best practices are a set of guidelines, ethics, or ideas that represent the most efficient or prudent course of action in a given business situation.
Best practices may be established by authorities, such as regulators, self-regulatory organizations (SROs), or other governing bodies, or they may be internally decreed by a company's management team.
A best practice is a method or technique that has been generally accepted as superior to any alternatives because it produces results that are superior to those achieved by other means or because it has become a standard way of doing things, e.g., a standard way of complying with legal or ethical requirements.
Notice here that it uses the term guidelines and not rules which are set in concrete and must be followed to the letter by everybody. Note also the phrase represent the most efficient or prudent course of action in a given business situation - if my business situation is different to yours then why should I follow your practices? I also do not recognise any governing bodies who have the authority to dictate how software should be written. There is no such thing as a "one size fits all" style as each team or individual is free to use whatever style fits them best. There are different guidelines for different languages (such as strictly typed vs. dynamically typed). There are different guidelines for different types of application (database applications vs. non-database applications). Different groups of programmers have their own ideas on what is best for them, so I choose to follow those ideas which are best for me and the type of applications which I write, ideas which have been tried and tested over several decades using several programming languages.
It was not until several years after I had starting publishing what I had achieved that some so-called "experts" in the field of OOP informed me that everything I was doing was wrong, and because of that my work was totally useless. When they said "wrong" what they actually meant was "different from what they had been taught" which is not the same thing. What they had been taught, and which is still being taught today, is that in order to be a "proper" OO programmer you must follow the following sets of rules:
I have documented criticisms of some of these rules in the following:
Basically I look at the method which I have chosen and compare the amount of reusable code which it produces with the amount which could be produced by the "officially approved" practices, and in all cases I see that my personal method produces the most reusable code, therefore it *MUST* be better. It should be obvious that the more reusable code you have then the less code you have to write, and there is nothing less than no code at all. With my framework it is possible, as shown in this video, to create a database table, then create the tasks to maintain the contents of that table without writing any code at all - no PHP code, no HTML code, no SQL code - as the framework automatically performs all the standard processing in its collection of reusable modules. The only thing left for the application developer to do is insert the code for any business rules into the relevant "hook" methods.
My reply to these critics can be summed up as follows:
If I were to follow the same methods as you then my results would be no better than yours, and I'm afraid that your results are simply not good enough. The only way to become better is to innovate, not imitate, and the first step in innovation is to try something different, to throw out the old rules and start from an unbiased perspective. Progress is not made by doing the same thing in the same way, it requires a new way, a different way.
If my development methodology and practices allow me to be twice as productive as you, then that must surely mean that my practices are better than yours. If my practices are better then how can you possibly say that your practices are best?
Any methodology which helps a programmer to achieve high rates of productivity should be considered as a good methodology. This can be done by providing large amounts of reusable code, either in the form of libraries, frameworks or tools, which the programmer can utilise without having to take the time to write his own copy. It should be well understood that the less code you have to write then the less code you have to test and the less time it will take. Being able to produce cost-effective software in less time than your competitors means that your Time to Market (TTM) is quicker and, as time is money, your costs will be lower. Both of these factors will be appreciated by your paying customers much more than the "purity" of your development methodology.
So how much reusable code do I have? Take a look at a simplified diagram of my application structure in Figure 1:
Figure 1 - A simplified view of my application structure
As you should be able to see this is a combination of the 3-Tier Architecture and the Model-View-Controller (MVC) Design Pattern. A more detailed diagram, with explanations, can be found in RADICORE - A Development Infrastructure for PHP.
The ability to write code to create classes and objects would be totally wasted unless you create classes for the right things. It would appear that my original choices were correct because, quite by accident, I created objects which matched the categories identified in the article How to write testable code and When to inject: the distinction between newables and injectables:
A Value Object is an immutable object whose responsibility is mainly holding state but may have some behavior. A Value Object has no conceptual identity separate from its attributes. Example of Value Objects might be Color and Temperature.
PHP does not have value objects as simple values are all represented as scalars or primitive data types.
An Entity's job is to hold state and associated behavior. Entities differ from Value Objects in that an Entity does have an identity separate from its contents. Examples of Entities could be Account or User. In a database application each entity exists as a table in that database.
A Service performs an operation. It encapsulates an activity but has no encapsulated state (that is, it is stateless). Examples of Services could include a parser, an authenticator and a validator.
The components in the RADICORE framework fall into the following categories:
It should also be noted that:
This arrangement helps me to provide these levels of reusability. This means that after creating a new table in my database I can do the following simply by pressing buttons on a screen:
Note that the whole procedure can be completed in just 5 minutes without having to write a single line of code - no PHP, no HTML, no SQL. If you cannot match THAT level of productivity then any criticisms that my methods are wrong and will always fall on deaf ears.
Note that some people claim that my framework can only be used for simple CRUD applications. These people have obviously not studied my full list of Transaction Patterns which provides over 40 different patterns which cover different combinations of structure and behaviour. I have used these patterns to produce a large ERP application which currently contains over 4,000 user transactions which service over 400 database tables in over 20 subsystems. While some of these user transactions are quite simple there are plenty of others which are quite complex.
I have often been told that you shouldn't be doing it that way, you should be doing it this way
. When I look at what they are proposing and see immediately that it would have a negative impact on either the elegance of my code and/or my levels of productivity then I simply refuse to follow their "advice". I have yet to see any suggestion which would improve my code, but I have seen many that would degrade it beyond all recognition. Rather than saying "let's run it up the flagpole and see who salutes it" these ideas fall into the category of "let's drop it in the toilet bowl and see who flushes it".
What is the cause of these bad ideas? Ever since I have been perusing the internet reading other people's ideas and posting ideas of my own on various forums I have come to the conclusion that there are two contribution factors - poor communication and poor comprehension.
These problems are exacerbated by peculiarities in the English language:
This means that when being read by a clueless newbie the meaning of a sentence can be ambiguous instead of exact, and if there is any room for ambiguity then some people will always attach the wrong meaning to a word and therefore end up with a corrupted meaning for the sentence which contains that word. If that same person uses different words to explain that corrupted meaning to a third party then it can become even more corrupt. The more people through whom the message passes the more likely it is that it gets more and more corrupted, just like it does in the children's game called Chinese Whispers.
There are also some other problems which can add to the confusion:
By attempting to apply the rules of one type of software to a different and incompatible type of software leads to claims such as OOP is not suitable for database applications. This shows a complete lack of understanding by the claimant - he doesn't know how databases work, and he doesn't know how to apply the mechanics of OOP to work with databases. By "mechanics" I mean nothing more than how to use the principles of encapsulation, inheritance and polymorphism in order to write cost-effective software. I built my own software while being totally unaware of these third-party rules, and my software has not suffered because of it. On the contrary, my development framework has flourished because of it as it has allowed me to become more productive than the users of any other framework, so that just shows how valuable (NOT!) these third-party rules are.
There are two ways in which an idea can be implemented - intelligently or indiscriminately.
Those who apply an idea or principle indiscriminately, who apply it in inappropriate circumstances, or who don't know when to stop applying it, are announcing to the world that they do not have the brain power to make an informed decision. They simply do it without thinking as they assume that someone else, namely the person who invented that principle, has already done all the necessary thinking for them. This leads to a legion of Cargo Cult programmers, copycats, code monkeys and buzzword programmers who are incapable of generating an original thought.
This problem also manifests itself with the inappropriate use of design patterns.
Listed below are some of the stupid ideas, or misinterpretations of good ideas, which I believe can result in crap code:
If you ask 10 different programmers what OOP really means you will get 10 different answers, and almost all of these will be so far off the mark I am truly amazed that their authors can get away with calling themselves "professional OO programmers". I have highlighted some of these goofy ideas in What OOP is NOT.
The only simple description I have ever found for OOP goes like this:
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.
Note here that I am only describing those three features which differentiate an OO language from a Procedural language. Some people seem to think that OO has four parts, with the fourth being abstraction. I do not agree. If the language manual does not show the keyword(s) which implement one of these parts the that part cannot be a feature of the language, it is only a design concept.
Many other descriptions of the "requirements" of OOP refer to additions which were made at a later date to different OO languages. I do not regard these additions as being part of the founding principles, so I ignore them if I don't like them.
Anybody who takes the time to study my framework in detail, either by reading the copious amounts of documentation or by examining and running the sample application or the full framework which can be downloaded, should very quickly see that the amount of reusable code which is provided means that new user transactions can be created very quickly. More reusable code equates to higher levels of productivity, and methodologies which directly contribute to higher productivity should be regarded as being superior to those which don't.
When I am told that I should be following the same set of rules and practices as other "proper" OO programmers just be "be consistent" and not "rock the boat" I refuse as, in my humble opinion, the dogmatic adherence to a series of bad rules will do nothing but make me "consistently bad". Further thoughts on this topic can be found at:
I disagree. OO programming and Procedural programming are exactly the same except the former supports encapsulation, inheritance and polymorphism while the latter does not. They are both concerned with writing imperative statements which are executed in a linear fashion with the only difference being the way in which code can be packaged - one uses plain functions while the other uses classes and objects. Further thoughts can be found at:
I disagree. A person called Yegor Bugayenko made the following dubious statements in various blog articles:
Inheritance is bad because it is a procedural technique for code reuse. .... That's why it doesn't fit into object-oriented programming.
I disagree. Inheritance does not exist in procedural languages, therefore it cannot be "a procedural technique for code reuse". Inheritance is one of the 3 pillars of OOP, so to claim that "it doesn't fit into object-oriented programming" is ridiculous beyond words.
Code is procedural when it is all about how the goal should be achieved instead of what the goal is.
I disagree. You are confusing imperative programming, which identifies the steps needed to perform a function, with declarative programming, which expresses the rules that a function should follow without defining the steps which implement those rules.
A method is procedural if the name is centered around a verb, but OO if it is centered around a noun.
I disagree. Classes in the business/domain layer, which represent the Model in MVC, represent entities, and entities are nouns, Methods represent the operations that can be performed on that entity, and operations (functions which can be performed) are always verbs.
Having used both procedural and OO languages for nearly 20 years apiece I have observed the following:
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 article All evidence points to OOP being bullshit John Barker says the following:
Procedural programming languages are designed around the idea of enumerating the steps required to complete a task. OOP languages are the same in that they are imperative - they are still essentially about giving the computer a sequence of commands to execute. What OOP introduces are abstractions that attempt to improve code sharing and security. In many ways it is still essentially procedural code.
By "abstractions" he means the ability to create concrete classes which can inherit (share) code which is defined in abstract classes.
In his paper Encapsulation as a First Principle of Object-Oriented Design (PDF) Scott L. Bain wrote the following:
Object Orientation (OO) addresses as its primary concern those things which influence the rate of success for the developer or team of developers: how easy is it to understand and implement a design, how extensible (and understandable) an existing code set is, how much pain one has to go through to find and fix a bug, add a new feature, change an existing feature, and so forth. Beyond simple "buzzword compliance", most end users and stakeholders are not concerned with whether or not a system is designed in an OO language or using good OO techniques. They are concerned with the end result of the process - it is the development team that enjoys the direct benefits that come from using OO.
This should not surprise us, since 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).
The notion of abstraction has been a confusing concept for a long time, not just for me but for many others as well. After performing a search on the interweb thingy I found many descriptions, but nothing good enough to be called a "definition" which could explain the concept to a novice in unambiguous terms. That was until I came across Designing Reusable Classes which was published in 1988 by Ralph Johnson and Brian Foote in which they described abstraction as the process of separating the abstract from the concrete, the general from the specific
. This is performed by examining a group of objects looking for both similarities and differences where the similarities are common to all members of that group while the differences are unique to individual members. If there are common protocols (operations or methods) then class inheritance allows these methods to be placed an abstract superclass so that they can be inherited and therefore shared by every concrete subclass which then need only contain the differences.
In a separate article called The meaning of "abstraction" I reveal how it is actually both a verb (process) and a noun (entity) which produces a result in two forms:
I have seen many descriptions of encapsulation which insist on including data hiding which, in my humble opinion, is derived from a misunderstanding of the term implementation hiding. Encapsulation, when originally conceived, did not specify data hiding as a requirement, and when PHP4 was released with its OO capabilities it not not include property and method visibility, so I never used it. Even though it was added in later versions of PHP I still don't use it. Why not? Simply because my code works without it, and adding it would take time and effort with absolutely no benefit. I have always thought that the idea of data hiding seems nonsensical - if the data is hidden then how are you supposed to put it in and get it out? Who are you supposed to be hiding it from, and why?
The true definition of encapsulation is as described in What is Encapsulation? as follows:
In object-oriented computer programming languages, the notion of encapsulation (or OOP Encapsulation) refers to the bundling of data, along with the methods that operate on that data, into a single unit. Many programming languages use encapsulation frequently in the form of classes. A class is a program-code-template that allows developers to create an object that has both variables (data) and behaviors (functions or methods). A class is an example of encapsulation in computer science in that it consists of data and methods that have been bundled into a single unit.
Encapsulation may also refer to a mechanism of restricting the direct access to some components of an object
Note that the second paragraph includes the word may, so the ideas of object visibility are optional, not a requirement.
My own personal definition of encapsulation is concise and precise:
The act of placing data and the operations that perform on that data in the same class. The class then becomes the 'capsule' or container for the data and operations. This binds together the data and functions that manipulate the data.
Note that this definition states that ALL the data and ALL the methods which operate on that data should be defined in the SAME class. Some clueless newbies out there use a warped definition of the Single Responsibility Principle to say that a class should not have more than a certain number of properties and methods where that number differs depending on whose definition you are reading.
This has a fairly simple definition:
The reuse of base classes (superclasses) to form derived classes (subclasses). Methods and properties defined in the superclass are automatically shared by any subclass. A subclass may override any of the methods in the superclass, or may introduce new methods of its own.
Note that I am referring to implementation inheritance (which uses the "extends" keyword) and not interface inheritance (which uses the "implements" keyword).
While it is possible to create deep inheritance hierarchies this is a practice which should be avoided due to the problems noted in Issues and Alternatives. People who encounter problems say that the fault lies with the concept of inheritance itself when in fact it lies with their implementation. This is why they Favour Composition over Inheritance. In Object Composition vs. Inheritance I found the following statements:
Most designers overuse inheritance, resulting in large inheritance hierarchies that can become hard to deal with. Object composition is a different method of reusing functionality. Objects are composed to achieve more complex functionality. The disadvantage of object composition is that the behavior of the system may be harder to understand just by looking at the source code. A system using object composition may be very dynamic in nature so it may require running the system to get a deeper understanding of how the different objects cooperate.
[....]
However, inheritance is still necessary. You cannot always get all the necessary functionality by assembling existing components.
[....]
The disadvantage of class inheritance is that the subclass becomes dependent on the parent class implementation. This makes it harder to reuse the subclass, especially if part of the inherited implementation is no longer desirable. ... One way around this problem is to only inherit from abstract classes.
This tells me that the practice of inheriting from one concrete class to create a new concrete class, of overusing inheritance to create deep class hierarchies, is a totally bad idea. This is why in MY framework I don't do this and only ever inherit from an abstract class. While inheritance itself is a good technique for sharing code among subclasses, the use of an abstract class opens up the possibility of being able to use the Template Method Pattern which is described in the The Gang of Four book as follows:
Template methods are a fundamental technique for code reuse. They are particularly important in class libraries because they are the means for factoring out common behaviour.
Template methods lead to an inverted control structure that's sometimes referred to as the Hollywood Principle, that is, "Don't call us, we'll call you". This refers to how a parent class calls the operations of a subclass and not the other way around.
Not only do I *NOT* have any problems with inheritance, by using it wisely I not only have the benefits of sharing code contained in an abstract class I have the added benefit of increasing the amount of code I can reuse by implementing the Template Method Pattern for every method which a Controller calls on a Model.
If I am following the advice of experts and only inheriting from an abstract class and making extensive use of the Template Method Pattern, both of which provide a great deal of reusable code, and you are not, then how can you possible say that your practices are better?
Some clueless newbies claim that inheritance is now out of date and that I am not following the latest "best practices" by still using it. I dismissed these ridiculous claims in Your code uses Inheritance. Other ridiculous claims can be found at the following:
I read this statement in several places but immediately dismissed it as hogwash as there was no explanation as to how inheritance breaks encapsulation. The author obviously had the wrong end of the stick regarding either one or both of these terms. I eventually found this description in wikipedia:
The authors of Design Patterns discuss the tension between inheritance and encapsulation at length and state that in their experience, designers overuse inheritance. They claim that inheritance often breaks encapsulation, given that inheritance exposes a subclass to the details of its parent's implementation. As described by the yo-yo problem, overuse of inheritance and therefore encapsulation, can become too complicated and hard to debug.
This description immediately tells me that inheritance itself is not a problem, it is the overuse of inheritance, especially when it results in hierarchies which go down to many levels, which is the problem. The notion that "inheritance exposes a subclass to the details of its parent's implementation" also strikes me as being hogwash. If you have class "B" which inherits from class "A" then all those methods and properties defined in class "A" are automatically available in class "B". That is precisely how it is supposed to work, so where exactly is the problem? If you have any bugs in your code which use inheritance then I'm afraid that there must be bugs in your code and not the concept of inheritance itself.
This so-called "problem" also appears under the name Fragile Base Class which is described as follows:
The fragile base class problem is a fundamental architectural problem of object-oriented programming systems where base classes (superclasses) are considered "fragile" because seemingly safe modifications to a base class, when inherited by the derived classes, may cause the derived classes to malfunction. The programmer cannot determine whether a base class change is safe simply by examining in isolation the methods of the base class.
As has already been stated earlier, inheritance does not cause problems when used properly, which means don't inherit from concrete classes, don't create deep inheritance hierarchies, only inherit from abstract classes
.
A clueless newbie called TomB criticised my use of inheritance with the following statement:
Your abstract class has methods which are reusable only to classes which extend it. A proper object is reusable anywhere in the system by any other class. It's back to tight/loose coupling. Inheritance is always tight coupling.
I debunked his claim in this article.
The first time I came across the Composite Reuse Principle (CRP) several questions jumped into my mind:
I could see no answers to any of these questions, so I dismissed this principle as being unsubstantiated.
This is supposed to be a solution to the problem that Inheritance breaks encapsulation. As that problem does not exist in my framework I have no need for that solution. Object Composition would not give me anywhere near the same amount of reusable code with so little effort, and as one of the principle aims of OOP is to increase the amount of reusable code I fail to see why I should employ a method which does the exact opposite.
My main gripe about object composition is that it plays against one of the primary aims of OOP which is to decrease code maintenance by increasing code reuse. Directly related to this is the amount of code you have to write in order to reuse some other code - if you have to write lots of code in order to take an empty object and include its composite parts then how is this better than using inheritance which requires nothing but the single word extends?
Another advantage to inheritance is that inheriting from an abstract class enables you to use the Template Method Pattern which the Gang of Four describe as:
Template methods are a fundamental technique for code reuse. They are particularly important in class libraries because they are the means for factoring out common behaviour.
As this powerful pattern cannot be provided with object composition then, for me at least, object composition is a useless idea.
Another reason to dismiss this so-called "principle" as being illogical is the fact that it proposes replacing inheritance with composition which, according to what has been written about OO theory elsewhere, are totally incompatible concepts and therefore incapable of being used to achieve the same result. Inheritance is supposed to be the result of identifying "IS-A" relationships while composition is supposed to be the result of identifying "HAS-A" relationships. I challenge anyone to show me an example where two objects can exist in both an IS-A and HAS-A relationship at the same time. The two concepts are not interchangeable, therefore you cannot substitute one for the other.
I have yet to see any sample code which demonstrates that something which can be done with inheritance can also be done with composition, so until someone provides proof that these two ideas are actually interchangeable I shall stick with the idea that works and consign the other to the dustbin.
When attempting to discover a meaningful definition of this concept which showed how it could be used to provide reusable code I came across the following statement in this wikipedia article:
In programming languages and type theory, polymorphism is the provision of a single interface to entities of different types or the use of a single symbol to represent multiple different types.
I did not find this description useful at all due to my confusion with the words interface and type. I was even more confused with the different flavours of polymorphism. Which flavors could I use in PHP? Which flavors should I use in PHP? Which flavour provided the most benefits? Instead of attempting to implement polymorphism according to a published definition (which I could not find) I just went ahead and implemented the concepts of encapsulation and inheritance to the best of my ability and hoped that opportunities for polymorphism would appear somewhere along the line.
It just happened that after building my first Page Controller which operated on a particular table class, where the name of that table class was hard-coded into that Controller, I wanted to use the same Controller on a different table class but without duplicating all that code. I quickly discovered a method whereby, instead of hard-coding the table's name I could inject the name of the table class by using a separate component script which then passes control to one of the standard Page Controllers which are provided by the framework, one for each Transaction Pattern.
Eventually I came across a less confusing description (I forget where) which simply defined polymorphism as:
Same interface, different implementation
Note that I take the word "interface" to mean method signature and not object interface.
This enabled me to expand it into the following:
The ability to substitute one class for another. This means that different classes may contain the same method signature, but the result which is returned by calling that method on a different object will be different as the code behind that method (the implementation) is different in each object.
This meant that, because of the architecture which I had designed, and the way in which I implemented it, I had stumbled across, by accident and not by design, an implementation of polymorphism which provided me with enormous amounts of reusable components. The mechanics of the implementation are as follows:
In this way I satisfy the "same interface" requirement by having the same methods available in every concrete table class via inheritance from an abstract table class.
I satisfy the "different implementation" requirement by having the constructor in each concrete table class load in the specifications of its associated database table, with various "hook" methods being available in every subclass to provide any custom processing.
This means that if I have 45 Page Controllers which can be used with any of my 400 table classes then I have 18,000 (yes, EIGHTEEN THOUSAND) opportunities for polymorphism. How many do you "experts" have?
Yet there are still some clueless newbies out there whose understanding of polymorphism is so warped that they have the audacity to criticise my implementation. If you take a look at What Polymorphism is not you will see false arguments such as:
Rubbish. Polymorphism does not require a parent/child relationship, only that multiple classes contain the same method signature. The same method can be defined manually instead of being inherited.
Rubbish. If I have 400 concrete table classes which inherit methods from the same abstract table class then those 400 classes are siblings which means that they are related by virtue of the fact that they all have the same parent. They all inherit and therefore share the same methods from that abstract class, and it is the sharing of method signatures which provides polymorphism.
Rubbish. Polymorphism does not require that the same method signature exists in multiple classes through inheritance, it only requires that it exists. This includes being defined manually instead of being inherited.
Many years ago I remember someone saying in a newsgroup posting that Object Oriented Programming (OOP) was not suitable for database applications. As "evidence" he pointed out the fact that relational databases were not object oriented, that it was not possible to store objects in a database, and that it required the intervention of an Object Relational Mapper (ORM) to deal with the differences between the software structure and the database structure. I disagreed totally with this opinion for the simple reason that I had been using OOP to build database applications for several years, and I had encountered no such problems. As far as I was concerned it was the blind following of OO theory which was the root cause of this problem. OO theory states that, in a database application, it is the design of the software which takes precedence and that the design of the database should be left until last as it is nothing more than "an implementation detail". You then end up with the situation that, after using two different design methodologies, you end up with two parts of your application which are supposed to communicate seamlessly with one another yet cannot because they are incompatible. This incompatibility is so common that it has been given the name Object-Relational Impedance Mismatch for which the only cure is to employ that abomination called as Object-Relational Mapper (ORM).
As far as I was concerned it was not that OOP itself was not suitable for writing database applications, it was his lack of understanding of how databases work coupled with his questionable method of implementing OO concepts in his software which was causing the problem. You have to understand how databases work before you can build software that works with a database. I had the distinct impression that all these "rules" for OOP were written by people who had never written large numbers of components in a database application therefore had no clue as to how to achieve the best result.
I was designing and building database applications for 20 years before I switched to an OO language, so I knew how to design databases by following the rules of data normalisation. I also learned, after attending a course on Jackson Structured Programming (JSP), that it was far better to design the database first, then design the software to fit that database structure, than it was to design the software by completely disregarding the database structure. This echoes the words of Eric S. Raymond, the author of The Cathedral and the Bazaar who put it like this:
Smart data structures and dumb code works a lot better than the other way around.
The incompatibilities between OO design and database design manifest themselves in the different ways they deal with such things as associations, aggregations and compositions which are described in UML modeling technique as follows:
How you identify and then deal with the classes which are affected by these relationships is then covered by the following:
In OO theory class hierarchies are the result of identifying "IS-A" relationships between different objects, such as "a CAR is-a VEHICLE", "a BEAGLE is-a DOG" and "a CUSTOMER is-a PERSON". This causes some developers to create separate classes for each of those types where the type to the left of "is-a" inherits from the type on the right. This is not how such relationships are expressed in a database, so it is not how I deal with it in my software. Each of these relationships has to be analysed more closely to identity the exact details.
Please refer to Using "IS-A" to identify class hierarchies and Confusion about the word "subtype" for more details on this topic.
Objects in the real world, as well as in a database, may either be stand-alone, or they have associations with other objects which then form part of larger compound/composite objects. In OO theory this is known as a "HAS-A" relationship where you identify that the compound object contains (or is comprised of) a number of associated objects. There are several flavours of association:
This is discussed in more detail in Using "HAS-A" to identify composite objects and Object Associations are EVIL.
There are some OO programmers out there who seem to think that it is forbidden to have your software components being aware of your database structure. Take the following as examples:
By following the "rules" of Object Oriented Design (OOD) they therefore produce an object structure which is totally out of sync with their database structure. Being "out of sync" produces a condition known as Object-Relational Impedance Mismatch. One proposed solution for this problem was the invention of an Object-Oriented Database (OODBMS), but their adoption and market share is minimal when compared with Relational Databases which have grown in sufficient power to lessen the need for a radically different approach. As a substitute the OO world has chosen to add in is an extra piece of software known as an Object-Relational Mapper (ORM).
In my humble opinion this is a train wreck of a solution, or as someone else put it The Vietnam of Computer Science. Instead of writing code to deal with the after effects of this train wreck my approach is to adopt a design methodology which prevents the train from being wrecked in the first place. This approach is known as Prevention is better than Cure. Instead of wasting my time using one methodology to design my database and a different methodology to design my software I have completely ditched the need for OOD and instead create a class structure which is a mirror image of my database structure, one class for each table. This means that there is no mis-match, therefore no need to include code which deals with that mis-match.
I do this by first designing and building my database, then creating a separate concrete class for each database table. Some people say that this would produce huge amounts of duplicated code, but they obviously have not understood the concept of sharing code through inheritance. My method of only inheriting from an abstract class also means that I can make extensive use of the Template Method Pattern which is yet another mechanism of reusing code. The full list of savings which I am able to achieve is discussed further in Having a separate class for each database table *IS* good OO.
Further criticisms of ORMs can be found at Object Relational Mappers are EVIL.
Do you remember Hungarian Notation? This was invented by a Microsoft programmer called Charles Simonyi, and was supposed to identify the kind of thing that a variable represented, such as "horizontal coordinates relative to the layout" and "horizontal coordinates relative to the window". Unfortunately he used the word type instead of kind, and this had a different meaning to those who later read his description, so they implemented it according to their understanding of what it meant instead of the author's understanding. Thus they used it to differentiate between data types such as strings, integers, decimal numbers, floating point numbers, dates, times, booleans, et cetera. The result was two types of Hungarian Notation - Apps Hungarian and Systems Hungarian. You can read a full description of this in Making Wrong Code Look Wrong by Joel Spolsky.
In wikipedia the word "type" is defined as:
Noun
A grouping based on shared characteristics
In the world of OOP which has classes and objects the word "type" is often used as a synonym for the word "class" which are used as follows:
When controlling or dealing directly with real-world entities such as CUSTOMER, PRODUCT and ORDER it would be reasonable to assume that each of those entities requires its own class as each entity has an entirely different set of methods and variables. However, when writing a database application, such as an enterprise application, you are not communicating with any entities in the real world, you are only communicating with information about those entities in a database, and that information is held in entities called tables. It is also obvious to any programmer who has experience with working with databases that every table, regardless of its contents, is subject to exactly the same set of operations/methods, and these methods are Create, Read, Update and Delete (CRUD). It would be inefficient, as well as bad OOP, for each table class to redefine the same set of CRUD operations as this would be against one of the aims of OOP which is to create as much reusable software as possible. It would therefore be a good idea to define these common operations in a superclass so that they can be inherited by each subclass.
But how can this be done in OOP? The answer was provided in 1988 by Ralph E. Johnson & Brian Foote in their paper Designing Reusable Classes in which they described a technique known as programming-by-difference. This involves the creation of an abstract class to hold the similarities which can then be inherited by a group of concrete subclasses which identify the differences. This is supported by the following statement which, believe it or not, was given as an argument against my practice of creating a separate class for each database table:
The concept of a table is abstract. A given SQL is not, it's an object in the world.
In the RADICORE framework the abstract table class contains all the common table methods while each concrete table class provides its own values for the common table properties.
Note that inheriting from an abstract class is supposed to be the best way of using inheritance. It also opens up the possibility of using the Template Method Pattern in which the abstract class contains the invariant methods while each individual subclass can contain its own set of variable "hook" methods to override the standard processing.
It is therefore wrong to say that in a database application each physical table is a different "type" when in fact it is a different implementation of the same abstract type. Each concrete table class shares the methods which it inherits from the abstract table class and is therefore a subclass of the abstract superclass.
Far too many programmers jump to the wrong conclusion when they try dealing with the "IS-A" test to identify class hierarchies. When they encounter such statements as "A VolkswagenBeetle is-a Car, a Sportscar is-a Car" they automatically assume that "Car" is a type and "VolkswagenBeetle" and "Sportscar" are subtypes that then require separate subclasses which are related through inheritance.
In the article Polymorphism and Inheritance are Independent of Each Other I came across the following sample C++ code which follows this train of thought:
// C++ polymorphism through inheritance class Car { // declare signature as pure virtual function public virtual boolean start() = 0; } class VolkswagenBeetle : Car { public boolean start() { // implementation code } } class SportsCar : Car { public boolean start() { // implementation code } } // Invocation of polymorphism Car cars[] = { new VolkswagenBeetle(), new SportsCar() }; for( I = 0; I <; 2; i++) Cars[i].start();
In this example Cars
is a type while VolkswagenBeetle
and SportsCar
are subtypes because they inherit from the Cars
class. Note that each of these subtypes has it own class. Note also that while a subtype can add extra methods to those which are already defined in the supertype it cannot remove any of those methods. This may cause problems if a subtype inherits a method which it cannot use (refer to the circle-ellipse problem for an example).
This idea simply does not work in a database application as each physical table should have its own class, so if each subtype has its own subclass then each subtype should have its own table. In the real world there would be a single table called VEHICLE which could hold the details of any number of different vehicles, and this table would have separate properties/columns for manufacturer, model and vehicle_type, seat_count, door_count, et cetera. The columns for manufacturer, model and vehicle_type would be be foreign keys to other tables which contain the list of available options for each of those columns. The ability to add another option to each foreign key column would require no more effort than adding an entry to the respective foreign table. It certainly would NOT involve creating a new (sub)class as this would involve changing code to access this new class. When I see an OO programmer using the word "subtype" I invariably translate this to mean "foreign key".
In a database application each physical table is not a separate "type" which requires its own collection of "subtypes" - the concept of a database table can be described in an abstract class while each physical table is a concrete implementation of that abstract type. Consider the following:
It should therefore be obvious that both are different blueprints for what is essentially the same type of entity, so there should always be a one-to-one relationship between "table" and "class". Furthermore, each and every table in a database, regardless of its contents, is subject to exactly the same set of Create, Read, Update and Delete (CRUD) operations, which means that, by following the advice given in Designing Reusable Classes which was published in 1988 by Ralph E. Johnson & Brian Foote, those common operations should be placed in an abstract class so that they can be shared by every concrete table class using the mechanism of inheritance. This was blindingly obvious to me when it came time to write the OO code for my second database table, but that was because I had 20 years of previous experience of writing database applications and had not been exposed to the misleading thoughts of OO "experts" who had no such experience. Only people who have direct experience of designing and working with databases which have been properly normalised are qualified to formulate principles for creating database applications.
The only difference between one table and another is its structure (the columns), so the only difference between one table class and another should be the description of that structure. By using an abstract class I am able to implement the Template Method Pattern which in turn means that all standard processing is carried out by invariant methods which are inherited from the abstract class while any custom processing can be carried out by "hook" methods in each concrete subclass.
The word "state" has several meanings, among which are:
state (condition) - as in "The building was in a state of disrepair".
However, in computer science a system is described as stateful if it is designed to remember preceding events or user interactions; the remembered information is called the state of the system. This is in contrast to a stateless system which does not maintain any memory of its state between function calls.
In 2018 I came across an article called Objects should be constructed in one go in which Matthias Noback said:
When you create an object, it should be complete, consistent and valid in one go.
When I had the audacity to challenge this statement Matthias Noback, being a snowflake who cannot tolerate opinions which are different from his own, promptly deleted my response, which forced me to create my own article at Re: Objects should be constructed in one go. As far as I am concerned the true definition of a constructor is as follows:
The purpose of a constructor is to initialize an object into a sane state/condition so that it can accept subsequent calls on any of its public methods.
Notice here that the word state means condition. It does NOT mean that all the object's properties must be loaded with pre-validated data. It is perfectly acceptable to load and validate data using separate public methods.
Matthias Noback's opinion is in total contrast to that of Yegor Bugayenko who wrote an article called Constructors Must Be Code-Free. It is simply not possible for both of these opinions to be right, and as they both disagree with the true definition of a constructor I consider them both to be completely wrong and not worth the value of the toilet paper on which they are written.
Before I became involved in OOP I understood the word "interface" to be shorthand for Application Programming Interface (API) which has the following definition:
An application programming interface (API) is a connection between computers or between computer programs. It is a type of software interface, offering a service to other pieces of software. A document or standard that describes how to build or use such a connection or interface is called an API specification. A computer system that meets this standard is said to implement or expose an API. The term API may refer either to the specification or to the implementation.
[....]
One purpose of APIs is to hide the internal details of how a system works, exposing only those parts a programmer will find useful and keeping them consistent even if the internal details later change. An API may be custom-built for a particular pair of systems, or it may be a shared standard allowing interoperability among many systems.
All the API documentation which I read contained a list of function calls (sometimes called function or method signatures) which identified the function name and its input and output arguments, plus a description of what the function actually did. The code behind the function, the implementation, was never revealed.
Later, while reading articles on OOP, I came across some confusing references to the term "interface" which had a different meaning. I did not understand this meaning as PHP4 did not support this idea. I later discovered this meaning when PHP5 was released. I looked at how much additional code was required to implement this feature, then I looked for the benefits. Guess what? There ARE no benefits, just costs. All my existing code, which calls method signatures inside concrete classes, would not work any differently or faster by creating abstract classes using the word interface then modifying the concrete class to use the word implements. No matter how many articles I read which said that these new-fangled interfaces were the best thing since sliced bread I just could not see the point. As I already made extensive use of an abstract class in my framework I could see no need for abstract interfaces.
Those programmers who are aware of the history of OOP should know that interfaces were only added to early statically typed languages to get around the problem of not being able to provide polymorphism without the use of inheritance. PHP, being dynamically typed, does not have this problem and can provide polymorphism without the use of either inheritance or interfaces. This means that interfaces are the solution to a problem which does not exist in PHP, which makes them totally redundant and a violation of the YAGNI principle. This topic is discussed in Object Interfaces.
I later came across the principle of program to the interface, not the implementation which confused me even more. If I am writing an application which has been divided into multiple smaller modules instead of a single huge block of monolithic code then I am automatically calling each module by its method signature without being concerned about that method's implementation. I know what the method does (or is supposed to do) but I do not know or even care about how it does it.
If this is the way that all modular software has behaved since computers were invented, then why is it expressed as a new rule just for OOP?
I often read in various articles, blog posts or newsgroup comments about how certain practices allow programmers to write code which is "decoupled" as against "coupled", where the latter is supposed to be a bad thing. This is a typical example:
Dependency injection is a programming technique that makes a class independent of its dependencies. It achieves that by decoupling the usage of an object from its creation.
As far as I am concerned the term "coupling" has absolutely nothing to do with separating the place where an object is instantiated from where a method on that object is called. A dependency between two objects only exists if object "A" contains a call to a method in object "B". This means that object "A" is dependent on the contents of object "B" in order to carry out its processing. It would be wrong to say that object "B" is dependent on object "A" simply because there is no call from object "B" to object "A".
Some people seem to think that coupling can be eliminated by "decoupling", which involves replacing a call from Object "A" to object "B" with an intermediate call through object "X" which then calls object "B". Because there is no direct call from "A" to "B" then "A" and "B" are not coupled, right? WRONG! Object "A" is still dependent on object "B" because it requires the services of object "X" which in turn requires the services of object "B". The coupling may be indirect instead of direct, but it is still there. All you have done is replace one method call with two, which doubles the number of places which may have to be updated due to the ripple effect caused by tight coupling. I have written more on this topic in Decoupling is delusional.
It is also wrong, in my humble opinion, to state that inheritance produces tight coupling between the superclass and the subclass. When the subclass in instantiated into an object the result is a single object which combines the methods and properties from both classes - it does not result in two objects with method calls from one to the other. If the subclass does not contain a call to a method in the superclass there where is the coupling? Where is the dependency? The fact that when a method is called on an object the signature of the method being called may be taken from either the subclass or the superclass cannot be classed as a problem which is to be avoided as that is the very nature of inheritance, the way that code is being shared.
Two objects are said to be "coupled" because one of them calls a method signature that exists in the other. They cannot become decoupled unless that method call, and therefore the dependency, is removed. Whether two objects are coupled or not, either directly or indirectly, is therefore a binary condition - it is either TRUE or FALSE, they are either COUPLED or NOT COUPLED. The fact that with Dependency Injection the identity of the dependent (called) object can be swapped at runtime does not remove the dependency between those two objects or remove the coupling as the call from object "A" to object "B" still exists.
In OOP when two objects are coupled it is considered to be good practice to aim for loose coupling instead of tight coupling so as to avoid the ripple effect where a change to a method signature in one object requires a change in all the places where that method signature is called. This means that certain statements are wrong, such as this one which I found at Decoupling Patterns:
A powerful tool we have for making change easier is decoupling. When we say two pieces of code are "decoupled", we mean a change in one usually doesn't require a change in the other.
WRONG! WRONG! WRONG! What you have described here is loose coupling, not decoupling.
In The Importance Of Decoupling In Software Development I found this definition of decoupling:
Decoupling is isolating the code that performs a specific task from the code that performs another task.
This seems to imply that all software modules are automatically coupled unless you take steps to decouple them, when in reality the inverse is true - by default all modules are automatically decoupled unless you deliberately insert a call from one module to another. Later on in the same article it says:
A common design pattern for solving problems like these is called Inversion of Control (IOC). IOC is a software architecture pattern where control flow goes against traditional methods. Instead of having modules dependent on each other, IOC works by having modules depend on an intermediary module with abstracted services. This intermediary module seamlessly manages all operations and allows you to switch between different service providers.
Here he is mixing up the terminology so much that all he is doing is creating buzzword soup.
switch between different service providersis known as Dependency Injection where the identity of the dependent object is not known until run time. A dependent object is still called, therefore there is coupling, but it is wrong to say that control is inverted as the call between the two modules remains the same and does not change direction.
This is yet another case where a single word has different and unrelated meanings:
Classes should favor polymorphic behavior and code reuse by containing instances of other classes that implement the desired functionality
When I looked for an example which proved the superiority of composition over inheritance I found the following code in Inheritance vs. Composition in PHP:
class Vehicle { public function move() { // ... } } class Car extends Vehicle { public $engine; public function __construct(Engine $engine) { $this->engine = $engine; } public function move() { $this->engine->start(); // ... } } class Engine { public function start() { // ... } } $car = new Car(new Engine()); $car->move();
This to me is total nonsense as methods like $engine->start
and $car->move
simply will never appear in a database application in which you are NOT communicating with objects in the real world as all you are doing is maintaining information about those objects in a database. The objects in a database are called "tables", and the only operations which can be performed on a table are Create, Read, Update and Delete (CRUD). Because of this I will use examples from my own code, as shown below:
class default_table { public function insertRecord($fieldarray) { // ... return $fieldarray; } public function updateRecord($fieldarray) { // ... return $fieldarray; } public function deleteRecord($fieldarray) { // ... return $fieldarray; } public function getData($where) { // ... return $fieldarray; } } class product { public function __construct ( $this->default_table = new default_table; } public function insertRecord($fieldarray) { $fieldarray = $this->default_table->insertRecord($fieldarray); return $fieldarray; } public function updateRecord($fieldarray) { $fieldarray = $this->default_table->updateRecord($fieldarray); return $fieldarray; } public function deleteRecord($fieldarray) { $fieldarray = $this->default_table->deleteRecord($fieldarray); return $fieldarray; } public function getData($where) { $fieldarray = $this->default_table->getData($where); return $fieldarray; } }
As you can see this still requires a great deal of code in the product class as each method in the default_table
class requires a corresponding method in the product
class in order to call it. Now look at how much code we can remove yet still produce exactly the same effect. Note the use of the keywords abstract and extends:
abstract class default_table { public function insertRecord($fieldarray) { // ... return $fieldarray; } public function updateRecord($fieldarray) { // ... return $fieldarray; } public function deleteRecord($fieldarray) { // ... return $fieldarray; } public function getData($where) { // ... return $fieldarray; } } class product extends default_table{ public function __construct ( // ... } }
The actual contents of my abstract table class are listed in more detail at common table methods.
Notice that this method requires nothing in the concrete subclass except the constructor, so that's a huge amount of code that I don't have to write.
Note also that there is a significant loss of functionality when replacing inheritance with composition - the inability to use the Template Method Pattern and its "hook" methods. This pattern implements Inversion of Control (IoC) which is also known as the Hollywood Principle (Don't call us, we'll call you) which is a distinguishing factor of all frameworks. Without it the RADICORE framework would not be much of a framework, so on that fact alone object composition is not a viable alternative.
A composition relationship is where one object (often called the constituted object, or part/constituent/member object) "belongs to" (is part or member of) another object (called the composite type), and behaves according to the rules of ownership.
As is usual true OO afficionados like to make things more complicated than they really are by inventing several types of composition, but in the context of database applications I have seen only two possibilities. Figure 2 shows the idea of a single object known as an ORDER which, following the rules of data normalisation, is broken down into a group of tables which are related in such a way as to form a fixed hierarchy. In the database this is not a single object, it is a group of tables which are joined together in a series of one-to-many or parent-child relationships.
Figure 2 - an aggregate ORDER object (a fixed hierarchy)
This is explained in more detail in Object Associations are EVIL - Figure 5.
Figure 3 shows what looks like a similar structure, but it is completely different in that each of those entities - Car, Engine, Piston, Spark Plugs, Stereo, Door, et cetera - are NOT separate tables in the database, they are separate rows in a single PRODUCT table. The relationship between one product and another is maintained on a separate PRODUCT-COMPONENT table, as shown in Figure 4.
Figure 3 - an aggregate BILL-OF-MATERIALS (BOM) object (an OO view)
The idea that each of these objects is regarded as a separate entity, thereby requiring a separate class, is bonkers. They are simply separate rows in the PRODUCT table, therefore can be handled by a single PRODUCT class.
This is explained in more detail in Object Associations are EVIL - Figure 6.
Figure 4 - an aggregate BILL-OF-MATERIALS (BOM) object (a database view)
This structure shows two one-to-many relationships where the PRODUCT-COMPONENT table has two foreign keys - product_id_snr and product_id_jnr, which both point back to different entries on the PRODUCT table. The primary key of the PRODUCT table is a combination of these two foreign keys. The maintenance tasks for the PRODUCT table and PRODUCT-COMPONENT table are totally separate. The complete BOM in its entirety can be viewed using a task built from one of the TREE VIEW patterns.
This is explained in more detail in Object Associations are EVIL - Figure 7.
I have seen far too many instances where someone with experience says "do not overuse/misuse/abuse X" where "X" can be almost anything, and this is immediately translated into "do not use X" by those who do not understand the difference in meaning. Here are some examples:
Why not? What are the problems with global variables? Are these "problems" down to fault with the concept or their implementation? Please refer to Your code uses Global Variables for a more detailed discussion.
Why not? Singletons have been among the list of well known design patterns for over a decade, so what can possibly be wrong with them? I have read many blog and newsgroup posts which echo this rule, but few provide any sort of proof that the rule has any substance. When I eventually found a list of reasons I studied them and came to the conclusion that it is not the idea of singletons which is at fault, it is their choice of implementation. Everybody follows the same idea that each class must contain a getInstance()
method which forces every instance of that class to be a singleton whether you like it or not.
I use a totally different approach. I have a single static getInstance()
function within a standalone singleton
class. This means that I can obtain an instance of any class using either of these two lines of code:
$object = new classname; $object = singleton::getinstance('classname');
Please refer to Singletons are NOT evil for more details.
Why not? What are the problems with inheritance? What is the alternative? How is it better? If you read What is the meaning of Inheritance? you will see that any so-called "problems" are down entirely to the overuse of inheritance and not the concept itself. The solution to these problems is to follow these steps:
This rule is a complete non-starter for me as without inheritance I would not be able to use the Template Method Pattern which is a fundamental technique for code reuse and which plays a major role in my framework.
Although these three words are different they mean virtually the same thing:
Some while ago one of my critics, of whom there are many, said that the the existence of a method called formatData() in my abstract table class was proof that the class was doing too much and therefore violated SRP. He focussed his entire attention on the method name and did not look at what the method does or the volume of data on which it operates. In some cases a formatting operation works on only a single column of data while in other cases it operates on a whole file of data, as shown by the following functions in the PHP manual:
In his article Test Induced Design Damage? Robert C. Martin summarised his Single Responsibility Principle (SRP) as follows:
GUIs change at a very different rate, and for very different reasons, than business rules. Database schemas change for very different reasons, and at very different rates than business rules. Keeping these concerns [GUI, business rules, database] separate is good design.
This means, to me at least, that the code for each of those three areas - GUI, business rules, database - in your software should be maintained in separate modules and should not be allowed to mix. By building my framework around the 3 Tier Architecture I have done just that. Claiming that a method in the business layer with the name formatData() "proves" that I am violating SRP shows that the claimant does not fully understand what SRP means or how it is implemented in my framework.
In the context of the 3-Tier Architecture the presentation/display logic in the Presentation layer is responsible for transforming the data obtained from the Business layer from its internal format, which is a PHP array, into a different format which is more presentable to the user, such as HTML, CSV or PDF. There is no code in the Business layer which performs this transformation or outputs any HTML, so it is completely wrong to say that there is presentation logic in the Business layer. The "formatting" logic in the Business layer does not transform the PHP array, it does nothing but format dates and decimal numbers within the array according to the user's language preferences, and that is business logic..
The first two functions in the above list are used by that method to change the contents of individual columns of data according to the business rules for that particular installation. The processing of business rules belongs in the Business layer.
The third function, the XSL Transformation process operates on a collection of values which are pulled from the application components (one or more Models) in the form of PHP arrays and other data which is maintained by the framework. The HTML output which it produces is part of the GUI or Presentation layer. The conversion of raw data (PHP arrays) into the XML document, loading of the XSL stylesheet and transformation into HTML are all performed within a single View component. Note that there are separate components which produce CSV and PDF output.
You should therefore be able to see that in my framework all business logic is contained within the Business layer and all presentation logic is contained in the Presentation layer. This conforms to the separation of concerns identified by Robert C. Martin.
If you still think that my code breaks SRP then as far as I am concerned your opinion is not worth the toilet paper on which it is written.
Here are some similar claims which I have rejected:
I have seen far too many instances where as soon as someone says "you can do so-and-so" a lot of newbie programmers act as if it was an instruction instead of a suggestion and rush to obey this new directive, even if it means amending code that already works. I have even been personally accused of being someone who still writes legacy code because I do not keep up with changes to the language and adopt a new feature or new syntax as soon as it becomes available and fashionable in the language. The fact that I still write code that uses a great deal of PHP4 syntax does not mean that my code will ONLY run in PHP4, it simply means that either I have no need for the new syntax or I cannot see the point in expending effort in changing code that works to exactly the same thing but differently. Any long-term user of PHP should be aware that 99% of the syntax which was available in PHP4 is still available in the current PHP8 version. The only time I change my code is in order to replace PHP4 syntax which has been removed in the latest version, so because my code still runs on the current version it cannot be classed as legacy code. I am a follower of the tried and tested It if ain't broke then don't fix it philosophy. If there are no tangible benefits to changing my code then why should I expend the cost? The following is a list of all those things that I could do, but which I refuse to do simply they do not offer the best solution.
My philosophy of not jumping on the bandwagon and refactoring my code as soon as a new feature comes along avoids the problem highlighted in When is Enough, Enough? I am not the only one who thinks that using the latest features in the language simply because they are shiny and new may not actually be a good idea. This is known as the Magpie Syndrome and is discussed by Matt Williams in his article Oooh Shiny! Magpies don't know what's just enough! as well as Does Your Team Have STDs?
This is only advisable if you are writing software which interacts directly with objects in the real world, such as elevator systems, missile control systems, robotic machines or domestic appliances, etc. If like me you are writing nothing but enterprise applications which have electronic forms at the front-end and a relational database at the back-end you are most certainly NOT interacting or controlling any physical object, you are interacting with information about physical objects which is held in a relational database, and the only objects in a database are called tables. Regardless of what operations can be performed on a physical object, the only operations which can be performed on a database table are Create, Read, Update and Delete (CRUD).
It does not matter if a database contains hundreds of tables each of which represents a totally different external object, the structure of each and every table follows the same rules, and the structure of the SQL queries used to read and write that structure also follows the same rules. It does not matter that a person in the real world has operations such as stand, sit, walk, run, eat, sleep and defecate, for a "person" table in the database the only operations are Create, Read, Update and Delete. It does not matter if you are holding information on a variety of different physical products each of which has a totally different set of operations, for a "product" table in the database the only operations are Create, Read, Update and Delete.
I find this idea to be one of those things that sounds fine in theory but not so good in practice. In pre-OO procedural languages it was quite acceptable to treat every value as a primitive, such as integer, float, decimal, character string, date and time, which could be manipulated using functions. Then OOP came along and some purists decided that this approach was not good enough, that all values should be objects and could only be manipulated using object methods. For example:
Although both lines of code will produce exactly the same result there is one glaring problem which is hidden from view - PHP does not have value objects, so it requires a lot of work in the background before you can use them. In my humble opinion this extra effort is a complete waste of time as there is no benefit, only costs. The idea that "everything is an object" is a complete fallacy because when writing a program with an HTML front-end and an SQL back-end with some PHP code in the middle the following conditions exist:
This therefore means that if you wish to use value objects in your PHP code you have to do the following:
You then end up with lots of extra code to convert strings into objects and then objects back into strings, but where is the benefit? Does your code run faster? No. All this extra code guarantees that it will in fact be slower. Does it have fewer bugs? No. All this extra code provides the opportunity for more bugs, not less.
Some OO purists complain that my code is not 100% object oriented because it does not use value objects, but I ignore them for the simple reason that OOP does not require the use of value objects, and that I can still write cost-effective software without them.
I read a blog post some while ago in which the author claimed that value objects were absolutely essential for "proper" OO programming. To reinforce this statement he pointed out that numerous software applications, such as Order Processing, cater for a monetary value which includes a currency code. He insisted that this can only be dealt with "properly" by having a value object which combines both an amount and a currency code. The hole in this argument is that such a value object cannot be represented in either a relational database or an HTML document. In both they are separate fields with no physical connection, only a logical relationship. I have been developing such applications for 4 decades, and I have had no problem with dealing with currency amounts using two separate fields. Not only has there never been a need to combine them, none of the languages I have used have ever provided the ability to combine them.
This follows on directly from the previous point. I have seen too many instances of a clueless newbie designing his first Sales Order Processing (SOP) system coming up with statements such a "we deal with customers, and each customer is a person, so we will need a Person class from which we can inherit to form a Customer class". This to me is total nonsense. I would never make such a division in my database design, and I see no reason why I should make that division in the design of the software which accesses that database design. The problem with trying to follow the description of an "IS-A" relationship on OO theory is that newbie programmers start from the wrong place and keep going in the wrong direction.
I never made this mistake for the simple reason that from my very first foray into the world of OOP, after several decades of writing database applications in non-OO languages, I recognised that every object in a database IS-A table, which is precisely why I create a separate class for each database table. I have been told by several clueless newbies that this means duplicating the code for each of the CRUD operations in each class, but I shoot this argument down in flames by pointing out that the sharing of common code among multiple classes is precisely why inheritance was invented. This is why I have created an abstract table class which contains the code which is common to every database table, and extend this class into a concrete subclass for each physical table to contain the code which is unique to that physical table. This arrangement of an abstract superclass and numerous concrete subclasses also means that I found it incredibly easy to implement the Template Method Pattern which is another technique for sharing code.
Ever since the first book on design patterns was published there have been numerous clueless newbies who think that since these patterns were written by "experts" all they have to do to write "export" code is to employ as many of these design patterns as possible. Please read Design Patterns - a personal perspective to see why this idea is wrong. People who employ principles indiscriminately without understanding the reasons behind those principles will always end up as being nothing more than Cargo Cult Programmers.
The essence of Domain Driven Design (DDD) is that you should model your software around the particular domain which is being covered by your application. A domain is described as:
Domain in the realm of software engineering commonly refers to the subject area on which the application is intended to apply. In other words, during application development, the domain is the "sphere of knowledge and activity around which the application logic revolves.
Domain: A sphere of knowledge, influence, or activity. The subject area to which the user applies a program is the domain of the software.
Under domain-driven design, the structure and language of software code (class names, class methods, class variables) should match the business domain.
A question arises when you are building a large enterprise application which encompasses a number of different areas of business, such as orders, invoices, shipments, inventory, surveys, work effort, finance, et cetera. The data required by each of these areas is different, the business rules are different, and they are managed by different groups of users, so is each of those areas a different domain which requires its own design? In 2007 I started writing an ERP application called TRANSIX which went live with its first customer in 2008. This originally comprised of the following subsystems:
This has subsequently grown into a much larger ERP application called GM-X which now has over 20 subsystems. If I were to follow the "advice" given in Domain Driven Design (DDD) I would be forced to design each of these domains/subsystems differently, but that is not what I choose to do. Despite the fact that each subsystem has its own set of unique aspects I see enough similarities to regard them as different instances of the same super-domain which is that of a database application. An experienced developer should see that they can be covered by the same architectural structure and therefore share a great deal of repeatable and sharable boilerplate code. Regardless of the different data and individual business rules the user transactions within each subsystem follow exactly the same pattern:
The biggest difference with each subsystem is the database design. Each subsystem has its own database with its own set of tables, and each table has its own unique structure of columns, primary keys, candidate keys and foreign keys. There are no such things as aggregate tables in a database, so I do not have aggregate objects in my software. Each table is a separate entity which follows the same basic rules as every other table and is accessed in exactly the same way as every other table. Every table, regardless of its contents, is subject to exactly the same set of operations - Create, Read, Update and DELETE (CRUD) - so these common methods are prime candidates for inclusion in an abstract table class. The unique aspects of each table are then confined to a separate concrete table subclass which has different values for its common table properties.
Although each table has a different set of columns the data types for each of those columns come from a predefined list, and the framework provides a standard validation object to perform all primary validation. Any secondary validation can be performed in the "hook" methods in each table's subclass. I have been told many times that this is wrong and not the way that "proper" OO programmers do it, but I have yet to see any other implementation which is as efficient and effective as this.
I could, but I don't. This is another part of Domain Driven Design which I ignore for the simple reason that it instantly disables a huge amount of reusability, via polymorphism, which is supposed to be one of the benefits of OOP in the first place. In my large ERP application I have over 4,000 use cases (which I call user transactions or tasks) and I never in a million years dream of creating a separate and unique method for each one. Every user transaction, regardless of its domain/subsystem follows the same pattern by performing one or more CRUD operations on one or more tables. Each task produces no more that one visible response, which could be either HTML, CSV or PDF. Some tasks do not display their results in the browser.
Instead of a separate method for each task I have a separate component script in the file system. This small script does nothing but identify which Model, View and Controller component are required to carry out the designated task. The Controller communicates with its Model(s) using the common table methods which are inherited from the abstract table class. Note that any Controller can communicate with any Model via the power of polymorphism. Each of these scripts has its own row in the MNU_TASK table in the MENU database so that it can be added to a menu screen and the Access Control List (ACL).
The use of an abstract class allows me to implement the Template Method Pattern in which the sharable invariant methods are defined in the abstract class while each concrete subclass can provide unique behaviour by utilising any of the available "hook" methods.
I could, but I don't. Every task (use case) performs one or more CRUD operations on one or more tables, and each of these operations can be dealt with by the common table methods which are provided in the abstract table class which is then inherited by every concrete table class. Having personally built thousands of user transactions over several decades I noticed a number of patterns emerging where a task which performed a series of operations on a particular database table needed to be copied so that it could perform the same set of operations on a different database table. Instead of duplicating the Controller code and hard wiring it to a particular database table (Model), which would have resulted in tight coupling, I created a separate reusable Controller for each Transaction Pattern which could then be used to call those methods on any Model within the application, thus producing loose coupling.
The idea of moving data between the software and the screen and between the software and the database one piece at a time, as with getters and setters, is something which I never encountered in any of my pre-OO languages. With COBOL all data was moved around in blocks called buffers, and each buffer had to be subdivided into its individual elements. With UNIFACE each database table was defined as an entity in the Application Model, and when building a form component you first painted a rectangle on the screen as an entity frame, then filled this frame with controls for each of that table's columns which you wished to be displayed. You could even paint a second entity frame within the first in order to display columns from a different table. Each screen could contain as many entity frames as you liked in whatever hierarchy you liked. After activating the "Retrieve" trigger UNIFACE would automatically read each table one record at a time starting with the outer-most entity and terminating with the inner-most entity. The data would automatically be loaded into the form component, and each columns value from the current record could be referenced using the column name, which could be prefixed with the table name if there was any ambiguity.
While COBOL had primitive arrays and UNIFACE had lists, I found PHP arrays to be much more powerful and flexible. When I noticed that data from an HTML form was presented to a PHP script in the form of the $_GET or $_POST array, and data from a database table was returned as an associative array using mysqli_fetch_assoc my instinctive reaction was to keep all application data in an array when passing it between the HTML form and the database. The idea that I not only could but should be using getters and setters to pass data around one column at a time never entered my head. When I saw example code that was written this way I immediately saw a bucket load of disadvantages, so I stuck to my original idea of passing all application data around in a single variable called $fieldarray, and is a decision which I have never regretted.
Another idea which I refuse to employ is to define each individual column as an argument on a method call. This has similar disadvantages as with using getters and setters. My method of using a single argument called $fieldarray which contains an unknown amount of data in an associative array (or an indexed array of associative arrays) has the following advantages:
Here is an example of the code which I use to insert data into any of the 400+ tables in my ERP application:
<?php require "classes/$table_id.class.inc"; // $table_id contains 'user' $dbobject = new $table_id; $fieldarray = $dbobject->insertRecord($_POST); if (!empty($dbobject->errors)) { // do error handling } // if ?>
The $dbobject->insertRecord($fieldarray) method is the start of a Template Method which has several steps. Some of those steps are the invariant methods which have standard implementations built into the abstract class while the others, those with a "_cm_" prefix, are customisable "hook" methods which can have different implementations is each table subclass.
Here is an example of the code which I use to read data from any of the 400+ tables in my ERP application:
<?php require "classes/$table_id.class.inc"; // $table_id contains 'user' $dbobject = new $table_id; $fieldarray = $dbobject->getData($where); ?>
The $dbobject->getData($where) method is the start of a Template Method which has several steps.
Please notice the following:
insertRecord()
may contain columns which we inserted either by the object itself, or the database (such as autoincrement keys).getData()
may contain any number of columns from the target table, and may include columns either from other tables by using a JOIN in the generated SQL query, or from database functions.$dbobject->errors
variable is an array which can contain as many error messages as necessary.Because neither of these scripts contain any hard-coded table names or column names they can operate on any of the 400+ database tables in my ERP application. I can add and remove tables and columns at will without having to make any corresponding changes to these scripts. This would be an example of loose coupling which is supposed to be a good idea. The use of getters and setters would require the use of scripts containing hard-coded column names, and this would be an example of tight coupling which is supposed to be a bad idea.
Please refer to Don't use getters and setters for user data and Getters and Setters are EVIL for more details.
It now seems that all OO programmers are taught to use exceptions for every error, that they are a standard feature of OO, but this is not the case. They were invented to solve the Semipredicate problem where a function can only return a single output value which is either a valid result or an indication of failure (such as boolean FALSE) but without the ability to identify the actual reason for that failure. The solution is to change the function so that when it detects an error it can throw an exception which is separate from the normal result and which can then be caught by the calling code. While every OO language supports the use of exceptions with the try/catch
block and the throw
commands, it is completely wrong to use exceptions for every possible type of error. In this technopedia page it says the following:
An exception is an abnormal or unprecedented event that occurs after the execution of a software program or application. It is a runtime error of an undesired result or event affecting normal program flow.
An exception is also known as a fault as it requires corrective action from a programmer.
Note that unless an error signifies an abnormal or unprecedented event then it should NOT be classed as an exception and should be dealt with in a different manner. Exceptions should only be used for software bugs which require corrective action by a developer and not for common occurrences such data validation errors. All user input should be validated before it is processed, and it is a common occurrence for a fat-fingered user to enter a wrong value into a field on the screen. The software should therefore check every value to ensure that it is of the correct type (number, date, et cetera) and if it is not then it should be rejected with a suitable error message, thus prompting the user to correct his mistake and try again. This type of error is not a fatal error as it does not cause the program to abort.
If you are validating a screen that contains several pieces of data and every one of those pieces is invalid then by throwing an exception on the first error you automatically skip the validation of any remaining pieces. That is why in my own code my data validation routine can return an array of errors so that all the errors can be reported after a single call instead of requiring a separate call for the next error.
The significance of using exceptions for fatal errors only was highlighted many years ago when I read a comment from a developer who was working with an application which recorded each and every exception in a log file, and it was his job to search through this log file and identify every bug that needed to be fixed. Unfortunately for him over 99% of the log file entries were for non-fatal data validation errors which could be fixed by the user and not a developer, so he had a hard time sorting out the wheat from the chaff.
Please refer to the following for more details:
My first OO language was PHP version 4. This did not provide support for object interfaces, so when I read several blog/newsgroup posts which used the word interface I assumed it meant the same as Application Programming Interface (API) which was the same as method signature. It wasn't until PHP5 was updated to include the keywords "interface" and "implements" that I realised there was a difference. My first thought was that the person who decided to use an existing term to means something else deserved a smack on the back of the head. The more I read about object interfaces the more convinced I became that they were a really bad idea and that refactoring my codebase to use them would be a complete waste of time. My reasons for reaching this conclusion were as follows:
Please refer to the following for more details:
Namespaces were designed to solve a problem which I don't have, so I don't use them. They are an option, not a requirement, so I choose not to use them.
Please refer to the following for more details:
Autoloaders were designed to solve a problem which I don't have, so I don't use them. They are an option, not a requirement, so I choose not to use them.
Please refer to A minimalist approach to Object Oriented Programming with PHP - Autoloaders for more details.
The wikipedia page on Software Design Patterns contains the following statements:
In software engineering, a software design pattern is a general, reusable solution to a commonly occurring problem within a given context in software design.
[....]
Design patterns are formalized best practices that the programmer can use to solve common problems when designing an application or system.
The big problem that clueless newbies have with design patterns is that they see the words "reusable solution" and "best practice" and they automatically assume that as those patterns were written by expert programmers then by employing as many patterns as possible in their code it will make it just as good as that produced by those experts. This idea is debunked in Design Patterns - a personal perspective and You don't understand Design Patterns.
In the article How to use Design Patterns there is this quote from Erich Gamma, one of the authors of the GOF book:
Do not start immediately throwing patterns into a design, but use them as you go and understand more of the problem. Because of this I really like to use patterns after the fact, refactoring to patterns.One comment I saw in a news group just after patterns started to become more popular was someone claiming that in a particular program they tried to use all 23 GoF patterns. They said they had failed, because they were only able to use 20. They hoped the client would call them again to come back again so maybe they could squeeze in the other 3.
Trying to use all the patterns is a bad thing, because you will end up with synthetic designs - speculative designs that have flexibility that no one needs. These days software is too complex. We can't afford to speculate what else it should do. We need to really focus on what it needs. That's why I like refactoring to patterns. People should learn that when they have a particular kind of problem or code smell, as people call it these days, they can go to their patterns toolbox to find a solution.
I do not consider Design Patterns to be proper patterns at all for the simple reason that they do not provide anything which is actually reusable. They simply describe a pattern and then force you to provide your own implementation, and each implementation can be different. The only patterns I know of which actually provide implementations, and implementations which are infinitely reusable, are Transaction Patterns. I wrote further on this topic in Design Patterns are dead! Long live Transaction Patterns! In my humble opinion Transaction Patterns are far superior because they provide implementations which are completely reusable - you simply use the functionality provided within the framework to say "Combine pattern X with table Y to produce transaction Z" and you can immediately run transaction Z to access that database table. While this starts off with nothing but the basic functionality you can easily add in extra business rules by using any of the available "hook" methods.
I have been told told by some OO aficionados that Transaction Patterns do not exist simply because no-one famous has ever written about them. Perhaps nobody else has spotted such patterns simply because they have not personally written the same volume of database programs as I have, and I have written thousands for my main ERP program alone. It is only by writing large numbers of programs that you can begin to see the emergence of patterns of similarity, either in the way things behave or in the way things look. It is only after you have identified such areas of similarity that you can take the next step and convert the similar or duplicated code into libraries of reusable code. I have built thousands of HTML pages which I can now produce using only a small number of reusable XSL stylesheets. Each one of those thousands of user transactions uses one of my 45 reusable page controllers, and each page controller communicates with its Model(s) by using the public methods which each database table class inherits from my abstract table class. By using an abstract class I have been able to implement the Template Method Pattern so that all boilerplate code is provided by the framework which means that each table subclass need only contain additional custom code in the various "hook" methods which are defined in the abstract class.
Time after time I see people use the 1972 paper On the Criteria To Be Used in Decomposing Systems into Modules written by D.L. Parnas to "prove" that the term "information hiding" is exactly the same as "data hiding". That paper contains the following words:
The second decomposition was made using 'information hiding" as a criterion.
...
Every module in the second decomposition is characterized by its knowledge of a design decision which it hides from all others. Its interface or definition was chosen to reveal as little as possible about its inner workings.
Notice that I highlighted the words to reveal as little as possible about its inner workings. In my humble opinion the words "inner workings" do not refer to the data which is operated upon but the internal implementation of the module (the operations which are performed on that data). In my experience this has been the way that every subroutine/function in every programming language has ever been documented - it lists a series of APIs which identify nothing but the function name and its input and output arguments (the function signature), plus a brief description of what its does. This description does not include the code which actually implements what it does. This means that the function's internal implementation can be changed at any time without necessarily having to change the function's signature.
Each class has both properties and methods, but it was never intended that properties had to be hidden and could only be accessed via a method instead of directly. If you don't believe me then take a look at the following articles:
This observation is taken from the C2 wiki:
- Encapsulation is a programming language feature.
- Information Hiding is a design principle.
This observation is taken from Nat Pryce's article:
- Encapsulation ensures that the behaviour of an object can only be affected through the object's API.
- Information hiding conceals how an object implements its functionality behind the abstraction of the object's API.
I have been writing database applications for 40 years, the last 20 of which have been dedicated to web applications. In all those pre-OO languages it was standard practice to pass all the table's data in a single argument on the procedure call as once that call had ended the procedure was terminated and all memory dropped. While making myself familiar with PHP I noticed two things:
name=value
pairs.These simple facts led me to the idea of creating object methods such as the following:
Anybody who knows anything about OOP should recognise that these are perfect examples of loose coupling, which is supposed to be a Good Thing. The idea that "proper" OO programmers should use getters and setters for each individual item of data never crossed my mind. Besides, this idea is a perfect example of tight coupling which is supposed to be a Bad Thing.
I have been told several times that my code is too simple, old fashioned, and that I am creating legacy systems. This just demonstrates that these people do not have a clear understanding of the words they are using. According to wikipedia the words "legacy system" means the following:
In computing, a legacy system is an old method, technology, computer system, or application program, "of, relating to, or being a previous or outdated computer system"
This means that it was designed to run on hardware which is no longer supported, uses an operating system which is no longer supported, or uses a language (or a version of that language) which is no longer supported. In order to keep running that system you have to keep using all of those obsolete components. This is only done when the system is still useful and the cost of upgrading is too high. This argument will eventually fall down when the obsolete hardware stops working and it cannot be fixed or replaced.
This description does not fit the RADICORE framework. While it was originally developed on a PC running Windows XP using Apache version 1.3, PHP version 4.1 and MySQL version 3.23, all those components have been regularly updated, and the framework has been constantly adjusted to deal with any incompatibilities. It is currently (as of July 2024) running on Windows 10, Apache 2.4.61, PHP 8.3.9 and MySQL 8.4.1. These are *NOT* the same versions that I started with 20 years ago, and they are *NOT* obsolete.
Some of my critics claim that I am still writing code in "PHP 4 style", but that is an empty argument as the vast majority of the functionality that was available in 2002 is still available in 2024. While some of the features which I originally used have been removed my code has been adjusted to take care of that. While many new features have been added I have only incorporated those for which I can find a genuine use. If I already have code which works I do not see any point in changing it to produce the same result but with different code. If the cost of changing my code does not yield any measurable benefits then I do not waste my time on making that change. This is just common sense.
While these words seem to have completely different meanings there is actually some overlap:
This means that the following sentences mean exactly the same thing:
Provided that the module in question has only one responsibility or concern then neither the Single Responsibility Principle (SRP) nor the Separation of Concerns (SoC) is violated. However, this does not stop some clueless newbies from inventing some perverse reasons why the two words are different which automatically makes the two principles different:
When I was first told "Your code breaks SRP" my first thought was "What the heck is SRP?" After a quick search on the internet I found this wikipedia article which stated:
The single-responsibility principle (SRP) is a computer-programming principle that states that every module, class or function in a computer program should have responsibility over a single part of that program's functionality, and it should encapsulate that part. All of that module, class or function's services should be narrowly aligned with that responsibility.
I then found Robert C. Martin's original article which stated the following:
This principle was described in the work of Tom DeMarco and Meilir Page-Jones. They called it cohesion. They defined cohesion as the functional relatedness of the elements of a module. In this chapter we'll shift that meaning a bit, and relate cohesion to the forces that cause a module, or a class, to change.
SRP: The Single Responsibility Principle
A CLASS SHOULD HAVE ONLY ONE REASON TO CHANGE.
In my humble opinion this shifting of the meaning of cohesion to "reason to change" was a HUGE mistake which caused, and is still causing, enormous amounts of confusion. In a later article, Test Induced Design Damage? he tried to clear up this confusion by using the following words:
How do you separate concerns? You separate behaviors that change at different times for different reasons. Things that change together you keep together. Things that change apart you keep apart.
GUIs change at a very different rate, and for very different reasons, than business rules. Database schemas change for very different reasons, and at very different rates than business rules. Keeping these concerns (GUI, business rules, database) separate is good design.
A few days later he followed this up with The Single Responsibility Principle which stated the following:
This is the reason we do not put SQL in JSPs. This is the reason we do not generate HTML in the modules that compute results. This is the reason that business rules should not know the database schema. This is the reason we separate concerns.
When I read the statement Keeping these concerns (GUI, business rules, database) separate is good design
it immediately struck me that this level of separation is an exact match to the levels defined the 3-Tier Architecture (3TA) with its Presentation layer, Business layer and Data Access layer. As my entire framework is based on 3TA, and 3TA is the same as SRP, then I have automatically followed the principle of SRP. Case closed.
The two articles Test Induced Design Damage? and The Single Responsibility Principle were published in 2014, but in an earlier 2009 article called One Thing: Extract till you Drop he talks about splitting the code in a large function until you end up with a collection of smaller sub-functions which are so small that it is impossible to split them any further. While his last example clearly shows a single class with many small methods there are some programmers who go too far and put each of those sub-methods into separate classes, thus ending up with many small classes which contain a single method which has a single line of code. Because none of these subclasses have any state this is in complete violation of the principle of encapsulation which states that ALL the properties and ALL the methods for an object should be placed in the same class
. This is also a shining example of low cohesion as those tasks which are closely related are not grouped together. An example of this can be found at Too much separation.
I personally do not follow this idea as trying to follow a path through code which constantly jumps from one place to another makes it far too easy to lose track of where you came from, where you are going, and what you are trying to achieve. I prefer not to extract code in a function into a sub-function unless the code in that sub-function needs to be called from multiple places, or if steps performed in a function require such large amounts of code that it makes it more readable to put each of those steps into a sub-function. If all these functions are in fact class methods I *NEVER* put these sub-functions into their own classes as this would violate the principles of both encapsulation and cohesion. For example, in my framework I have a single View object which which is responsible for creating all HTML output for any web page. This involves several distinct steps each of which is performed by its own method, but all these methods are in the same class. The principle of cohesion states that as these functions are closely related (i.e. they are all concerned with some part of the HTML output) then they should all be kept together in the same class as Any attempt to divide them would only result in increased coupling and decreased readability
.
Robert C. Martin's original article on this subject clearly states that SRP is based on the principle of cohesion, yet there are some numpties out there who clearly do not understand what this means. They do not have the mental capacity to tell if a module/class demonstrates either high cohesion or low cohesion, so they resort to a simpler technique - the ability to count. They say that a class should not contain more than n methods, and a method should not contain more than n lines of code. Different people have a different view on what the number n actually is. Even then they demonstrate that they cannot count any higher than 10 without taking off their shoes and socks.
In March 2017 a numpty called Hall_of_Famer created a post on Reddit titled How would you go about maintaining a class with 9000 lines of code like this one? It quickly degenerated into a personal attack on many fronts, so rather than replying in situ I created Response to personal attack on reddit.com
The premise of that Reddit post goes along the lines of "it is so large that it surely must be breaking SRP". Nowhere in Robert C. Martin's definition of SRP, or his subsequent follow-up articles, does it say that the splitting up of a large module with multiple responsibilities should be based on the ability to count, only the ability to think. Each "responsibility" can be summed up as "in which of the three layers - Presentation (GUI), Business or Data Access - does this code belong?" I have followed this interpretation of SRP by dividing my code into separate modules where each module sits in just one of those three layers. Note that I have also split my Presentation layer into separate Controller and View modules.
Before jumping in so quickly to criticise my code not one of these newbies took the time to see how it fits into my framework, otherwise they would have spotted the following:
Most designers overuse inheritance, resulting in large inheritance hierarchies that can become hard to deal with. Object composition is a different method of reusing functionality. Objects are composed to achieve more complex functionality. The disadvantage of object composition is that the behavior of the system may be harder to understand just by looking at the source code. A system using object composition may be very dynamic in nature so it may require running the system to get a deeper understanding of how the different objects cooperate.
[....]
However, inheritance is still necessary. You cannot always get all the necessary functionality by assembling existing components.
[....]
The disadvantage of class inheritance is that the subclass becomes dependent on the parent class implementation. This makes it harder to reuse the subclass, especially if part of the inherited implementation is no longer desirable. ... One way around this problem is to only inherit from abstract classes.
Template methods are a fundamental technique for code reuse. They are particularly important in class libraries because they are the means for factoring out common behaviour.If you look at Sequence of events the column labelled Entry Point identifies the public methods while the column labelled Sequence shows which internal methods are called. The customisable methods have a "_cm_" prefix.
Template methods lead to an inverted control structure that's sometimes referred to as "The Hollywood Principle" that is, "Don't call us, we'll call you". This refers to how a parent class calls the operations of a subclass and not the other way around.
My abstract table class is so large because it contains *ALL* the Template Methods which may be needed by *ANY* of my Transaction Patterns. This means that I can create a new task using a new Transaction pattern at any time, and I do *NOT* have to make any adjustments to any concrete class (except to modify any "hook" methods where necessary). I have been told that this is wrong as each concrete subclass should only inherit those methods that it actually needs, so I should split the single abstract class into smaller classes. This idea is crap for the following reasons:
My current solution gives me the maximum amount of benefits from the minimum amount of code which, in my book, makes it highly efficient. Being a pragmatic rather than a dogmatic programmer I favour code which demonstrates efficiency over paradigm purity any day of the week.
When I was first told "Your code breaks SoC" my first thought was "What the heck is SoC?" After a quick search on the internet I found this wikipedia article which stated:
In computer science, separation of concerns (SoC) is a design principle for separating a computer program into distinct sections. Each section addresses a separate concern, a set of information that affects the code of a computer program. A concern can be as general as "the details of the hardware for an application", or as specific as "the name of which class to instantiate". A program that embodies SoC well is called a modular program. Modularity, and hence separation of concerns, is achieved by encapsulating information inside a section of code that has a well-defined interface.
Notice that it does not say anything about cohesion and coupling.
A few sentences later it says the following:
Layered designs in information systems are another embodiment of separation of concerns (e.g., presentation layer, business logic layer, data access layer, persistence layer).
This arrangement of layers - presentation layer, business layer, data access layer (to me the data access layer and persistence layer are the same thing) - is an exact match to the description of the 3-Tier Architecture (3TA) upon which my entire framework was based from the outset, so it should be perfectly reasonable to conclude that any design which is based on the 3-Tier Architecture automatically satisfies the "layered design" description quoted in the above definition.
You should also note that the description of the Single Responsibility Principle also mentions exactly the same layers, so it should be perfectly reasonable to conclude that as SRP = 3TA and SoC = 3TA then SRP = SoC.
This is not just my opinion. Robert C. Martin himself, in his article The Single Responsibility Principle, actually uses the following words:
This is the reason we do not put SQL in JSPs. This is the reason we do not generate HTML in the modules that compute results. This is the reason that business rules should not know the database schema. This is the reason we separate concerns.
In his article Test Induced Design Damage? he wrote the following:
GUIs change at a very different rate, and for very different reasons, than business rules. Database schemas change for very different reasons, and at very different rates than business rules. Keeping these concerns separate is good design.
If the man who first defined "single responsibility" says that it is the same as the "separation of concerns" then who are you to argue?
It has been said that my abstract class is so big that it must be a God Object, but I have debunked this theory in several other articles:
It has also been said that any class which inherits from that abstract class results in an anemic domain model. Those descriptions are mutually exclusive, so how is that criticism possible?
When I was first told "You're not following the Dependency Inversion Principle (DIP)" my first thought was "What the heck is DIP?" After a quick search on the internet I found this description of the Dependency Inversion Principle which stated:
In object-oriented design, the dependency inversion principle is a specific methodology for loosely coupling software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are reversed, thus rendering high-level modules independent of the low-level module implementation details. The principle states:
- High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces).
- Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.
I did not understand this gobbledygook (I still don't!), so I looked for a more detailed description. The article tried to explain how to use this pattern using a diagram which showed a Policy Layer, a Mechanism Layer and a Utility Layer, but no such layers exist in my architecture. The only layers I have are the Presentation layer, the Business layer and the Data Access layer, so I found the article to be totally useless and so ignored it.
There is a different definition for Dependency Injection which says:
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 which wants to use a given service should not have to know how to construct those services.
This, to me, is a totally inappropriate use of Separation of Concerns (which is the same as the Single Responsibility Principle) which is supposed to be a description of the principle of cohesion which was first used by Tom DeMarco. This was supposed to separate large chunks of code which perform unrelated functions, such as separating GUI logic from business logic from database logic. The construction of an object and the calling of one of its services can take no more than two lines of code, as shown below:
$object = new clsss_name; $result = $object->method();
Anybody who suggests that those two lines of code SHOULD be separated and performed in different places clearly does not understand the principle of cohesion. Some ideas can be tested using the expression Let's run it up the flagpole and see who salutes it
, but in my humble opinion this interpretation is so ridiculous it should be subject to Let's drop it in the toilet bowl and see who flushes it
. This is my response: .
I later discovered that this was also related to the Dependency Injection Principle which again lacked a sensible description, so I ignored that as well. It was not until I read these papers by Robert C. Martin that the light began to dawn and the penny began to drop.
My reading of the example "Copy" program highlighted the following points:
copy
method as follows:
void Copy(Reader& r, Writer& w) { int c; while((c=r.Read()) != EOF) w.Write(c); }
This is known as call-time injection as it calls the copy
method and supplies all the dependent objects in a single command. which is totally different from constructor injection, setter injection and interface injection. These were added later by members of the Let's Make It More Complicated Than It Really Is Just To Prove How Clever We Are brigade.
After reading How to write testable code the following additional points became obvious:
It also breaks down classes into two broad categories:
It then states the following:
The last point tells me that it is permissible to inject entities/newables into services/injectables but not the other way around. This follows the example shown in Robert C. Martin's "COPY" program where the two device objects, which are entities, are injected into the copy program, which is a service. The process would not work if you tried to inject the copy service into a device entity. This is logical to me for the simple reason that the operation performed by each service is unique while the identity of the dependent objects on which that service can be performed is not - it could be any one of the possible dozens of different devices or, in my case, any one of the hundreds of tables in my database. I have implemented this approach in the following ways:
require
statement.Dependency injection is not effective if:
- You will never need a different implementation.
- You will never need a different configuration.
I do not need either of those, therefore in those circumstances DI would be totally ineffective.
Believe it or not there are still some numpties out there who consider that DI can never be inappropriate.
It should also be noted that as each service object, which should be the only one able to provide that service, communicates with its dependent object(s) which could come from any number of numerous entities, with a common API. This means that this common API must be available in all those dependent objects. Thus you cannot have Dependency Injection without sharing a set of common APIs, and this fits the description of polymorphism. In my framework all the Model objects share exactly the same APIs as they are all inherited from the same abstract table class.
This topic is also discussed in the following articles:
Let me make it perfectly clear - Dependency Injection and Dependency Inversion mean exactly the same thing as they are both concerned with the handling of dependencies. If you don't believe me then read this wikipedia article on Dependency Injection:
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.
.....
Dependency injection is often used to keep code in-line with the Dependency Inversion Principle.
Note here the direct link between "dependency injection" and "dependency inversion", and also to the "separation of concerns".
I have read in quite a few places that Inversion of Control, Dependency Injection and the Dependency Inversion Principle mean roughly the same thing and are almost interchangeable. But is this true? The wikipedia article at Inversion of Control states the following:
In software engineering, inversion of control (IoC) is a design pattern in which custom-written portions of a computer program receive the flow of control from a generic framework. The term "inversion" is historical: a software architecture with this design "inverts" control as compared to procedural programming. In procedural programming, a program's custom code calls reusable libraries to take care of generic tasks, but with inversion of control, it is the framework that calls the custom code.
.....
Inversion of control is sometimes facetiously referred to as the "Hollywood Principle: Don't call us, we'll call you".
The term "inversion of control" was first used by Ralph Johnson and Brian Foote in 1988 in a paper called Designing Reusable Classes which stated the following:
White-box vs. Black-box Frameworks
One important characteristic of a framework is that the methods defined by the user to tailor the framework will often be called from within the framework itself, rather than from the user's application code. The framework often plays the role of the main program in coordinating and sequencing application activity. This inversion of control gives frameworks the power to serve as extensible skeletons. The methods supplied by the user tailor the generic algorithms defined in the framework for a particular application.
A framework's application specific behavior is usually defined by adding methods to subclasses of one or more of its classes. Each method added to a subclass must abide by the internal conventions of its superclasses. We call these white-box frameworks because their implementation must be understood to use them.
Note here that the action of adding methods to subclasses to extend the behavior defined in a superclass is a reference to the Template Method Pattern.
Inheritance
Most object-oriented programming languages have another feature that differentiates them from other data abstraction languages; class inheritance. Each class has a superclass from which it inherits operations and internal structure. A class can add to the operations it inherits or can redefine inherited operations. However, classes cannot delete inherited operations.
Class inheritance has a number of advantages. One is that it promotes code reuse, since code shared by several classes can be placed in their common superclass, and new classes can start off having code available by being given a superclass with that code. Class inheritance supports a style of programming called programming-by-difference, where the programmer defines a new class by picking a closely related class as its superclass and describing the differences between the old and new classes. Class inheritance also provides a way to organize and classify classes, since classes with the same superclass are usually closely related.
One of the important benefits of class inheritance is that it encourages the development of the standard protocols that were earlier described as making polymorphism so useful. All the subclasses of a particular class inherit its operations, so they all share its protocol. Thus, when a programmer uses programming-by-difference to rapidly build classes, a family of classes with a standard protocol results automatically. Thus, class inheritance not only supports software reuse by programming-by-difference, it also helps develop standard protocols.
Notice here that it specifies the use of superclasses to provide standard behaviour and subclasses which share this behaviour while allowing a technique called programming-by-difference.
The term "inversion of control" was later used by by Michael Mattsson in his 1996 paper titled Object-Oriented Frameworks - A survey of methodological issues in which he states the following:
The problems with reusing class libraries are that they do not deliver enough software reuse. Software developers still have to develop a lot of application code themselves. Limitations in reusing classes and objects from class libraries comprise [Cot95]:
- Complexity. In large and complex system the class hierarchies can be very confusing. If the developer has no access to detailed documentation it can be tricky to figure out the designers intention with the hierarchy.
- Duplication of effort. Class libraries allow the developers to reuse classes which can be put together by different developers in different ways. This may result in different solutions to the same kind of problems and may cause maintenance problems.
- Flow of control. When reusing class libraries in application development, the program is still responsible for the flow of control, i.e. the control of interactions among all the objects created from the library. This can be a problem since the developer has the responsibility of deciding in which order objects and operations have to be performed and errors can be made.
In the section labelled Object-Oriented Design Patterns he states the following:
When discussing metapatterns, the following classification of methods [Joh91] is used:
- template methods which are based on
- hook methods, which can be
- abstract methods,
- regular methods, or
- template methods.
In the section labelled conclusions he states the following:
The major difference between an object-oriented framework and a class library is that the framework calls the application code. Normally the application code calls the class library. This inversion of control is sometimes named the Hollywood Principle, "Don't call us, we call You".
Notice that he uses the words template methods, hook methods and the Hollywood principle. These are described in the 1995 Gang of Four book Design Patterns: Elements of Reusable Object-Oriented Software under the title TEMPLATE METHOD as follows:
Intent
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.Applicability
The Template Method pattern should be used
- to implement the invariant parts of an algorithm once and leave it up to subclasses to implement the behaviour that can vary.
- when common behaviour among the subclasses should be factored and localized in a common class to avoid code duplication.
- to control subclass extensions. You can define a template method that calls "hook" operations at specific points, thereby permitting extensions only at these points.
Consequences
Template methods are a fundamental technique for code reuse. They are particularly important in class libraries because they are the means for factoring out common behaviour in library classes.Template methods lead to an inverted control structure that's sometimes referred to as "the Hollywood Principle", that is "Don't call us, we'll call you". This refers to how a parent class calls the operations of a subclass and not the other way around.
The Template Methods call the following kinds of operations:
- concrete operations (either on the ConcreteClass or on client classes).
- concrete AbstractClass operations (i.e., operations that are generally useful to subclasses).
- primitive operations (i.e., abstract operations).
- hook operations, which provide default behaviour that subclasses can extend if necessary. A hook operation often does nothing by default.
In another paper by Michael Mattsson called Evolution and Composition of Object-Oriented Frameworks which was published in 2000 he wrote the following:
Operations like the copy operation are often called template methods and operations like read and write are called hook methods.
The use of template and hook methods are a distinguishing feature of an object-oriented framework compared to a conventional library, i.e. the framework is designed for dynamic binding. When a conventional library is used by an application routine, calls are made from the application to the library only. In an object-oriented framework, however, calls can go also in the opposite direction (the inversion of control), see figure 1. This two-way flow of control is made possible by dynamic binding.
.....
This inversion of control is often referred to as the Hollywood principle: "Don't call us-we'll call you."
This link between the terms "inversion of control" and the "Hollywood principle" is also echoed in Martin Fowler's article InversionOfControl.
Note that all the above articles describe "inversion of control" as being linked to the "Hollywood principle", "template methods", and the difference between a library and a framework. I therefore regard any attempt to link IoC with anything else to be a misrepresentation, a serious mistake which shows the confused mind of the author. Note that the abstract table class within the RADICORE framework makes extensive use of the Template Method Pattern, which then allows each concrete table class to contain nothing but "hook" methods.
As well as the correct definition of Inversion of Control the wikipedia article also contains the following:
The phrase "inversion of control" has separately also come to be used in the community of Java programmers to refer specifically to the patterns of injecting objects' dependencies that occur with "IoC containers" in Java frameworks such as the Spring framework. In this different sense, "inversion of control" refers to granting the framework control over the implementations of dependencies that are used by application objects rather than to the original meaning of granting the framework control flow (control over the time of execution of application code e.g. callbacks).
The notion that it is the framework which has control over the implementation of dependencies is totally wrong. The description of Inversion of control container contains the following statement:
The inversion of control (IoC) container is the core container in the Spring Framework. It provides a consistent means of configuring and managing Java objects using reflection. The container is responsible for managing object lifecycles of specific objects: creating these objects, calling their initialization methods, and configuring these objects by wiring them together.
In many cases, one need not use the container when using other parts of the Spring Framework, although using it will likely make an application easier to configure and customize. The Spring container provides a consistent mechanism to configure applications: and integrates with almost all Java environments, from small-scale applications to large enterprise applications.
The programmer does not directly create an object, but describes how it should be created, by defining it in the Spring configuration file. Similarly, services and components are not called directly; instead a Spring configuration file defines which services and components must be called. This IoC is intended to increase the ease of maintenance and testing.
Here you should clearly see that the framework is simply carrying out the instructions which the developer has inserted into the configuration file, so it is the developer who is in control, not the framework. The framework is nothing but a slave carrying out his master's instructions.
In my opinion these dumb Java programmers are guilty of hijacking a principle which had a well-established meaning and using the same name to describe a completely different and totally unrelated principle. Inverting the flow of control by using the Template Method Pattern has absolutely nothing to do with the injection of dependencies. This corruption of OO terminology whereby the same name can mean different things depending on who you talk to or which way the wind is blowing does nothing but spread confusion instead of providing clarity.
I am not the only one who shares this opinion. In an article called Inversion of Control Containers and the Dependency Injection pattern dated 2004 Martin Fowler had this to say:
Inversion of Control
When these containers talk about how they are so useful because they implement "Inversion of Control" I end up very puzzled. Inversion of control is a common characteristic of frameworks, so saying that these lightweight containers are special because they use inversion of control is like saying my car is special because it has wheels.
The question is: "what aspect of control are they inverting?" When I first ran into inversion of control, it was in the main control of a user interface. Early user interfaces were controlled by the application program. You would have a sequence of commands like "Enter name", "enter address"; your program would drive the prompts and pick up a response to each one. With graphical (or even screen based) UIs the UI framework would contain this main loop and your program instead provided event handlers for the various fields on the screen. The main control of the program was inverted, moved away from you to the framework.
For this new breed of containers the inversion is about how they lookup a plugin implementation. In my naive example the lister looked up the finder implementation by directly instantiating it. This stops the finder from being a plugin. The approach that these containers use is to ensure that any user of a plugin follows some convention that allows a separate assembler module to inject the implementation into the lister.
As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection.
Here he is saying that these confuseniks should stop saying "inversion of control" when what they actually mean is "dependency injection". I couldn't agree more.
As I have stated in What is a Framework? RADICORE is a true framework as it is responsible for calling the relevant parts of the application code as and when required. The application developer does not have to write code to call the framework components as it is the framework which calls the application components. How is this achieved? The entire RADICORE framework is built around the Model-View-Controller design pattern which I have combined with the 3-Tier Architecture by extracting all data access logic out of the Model and placing it in a separate Data Access Object (DAO). Every concrete table class inherits from an abstract table class, and every public method in the abstract class implements the Template Method Pattern. All concrete table classes are generated by the framework and automatically include all standard code. The only code that needs to be added are the unique business rules which are inserted into pre-defined "hook" methods. Flow of control passes between the framework and application components as follows:
Please note the following:
With this arrangement you should see that I implement inversion of control by using the Template Method Pattern and an abstract class whereas I implement the dependency inversion principle by injecting Models into Controllers and Models into Views. These two principles are implemented differently therefore they are different principles, yet the use of one without the other would appear to be pointless when you consider the following:
Note that I have absolutely no use for any DI containers, factory methods or service locators.
This means that any Controller can be used with any Model. In my main ERP application I have 40 Controllers and 450 Models (one for each database table), so that gives me 40 x 450 = 18,000 (yes, EIGHTEEN THOUSAND) opportunities for polymorphism. The application has 4,000 HTML screens which are all produced by a single View component. It also has a 100 or so PDF documents which are also produced by a single View component. How's that for reusability?
As far back as the 1970s when I stated my career in computing I learned about the KISS principle (Keep It Simple, Stupid) which states that producing a simple solution which works is far better than producing a complex solution which works. This principle has since been restated as Do The Simplest Thing that Could Possibly Work and followed up with You Ain't Gonna Need It (YAGNI) and Don't repeat yourself (DRY). Yet in spite of these words of wisdom there are still some developers out there who see a simple solution as the work of a feeble mind. These are members of the Let's Make It More Complicated Than It Really Is Just To Prove How Clever We Are brigade who seem to think that they are amongst a small number of elite programmers and have to prove it by writing code that is so complex that only other elite programmers can understand it. What they fail to understand is that by producing code which is more complex than it need be they are more likely to produce solutions which resemble the works of Heath Robinson or Rube Goldberg.
Shortly after I released my RADICORE framework as open source one of my critics made the following complaint:
If you have one class per database table you are relegating each class to being no more than a simple transport mechanism for moving data between the database and the user interface. It is supposed to be more complicated than that.
What this person had failed to understand, probably due to a lack of experience, is that the basic functionality of every task in a database application always follows the same pattern - it starts out as being nothing more than a "simple transport mechanism" as it entails the moving of data between the user interface, through a Business layer, to a Database layer and back again. It is the Business layer which is the heart of the application as this is where all the business rules are processed. In the RADICORE framework all standard functionality, up to and including all primary validation, is provided by components which are built into the framework. Any complex business rules can be added in later by the developer by inserting the relevant code into any of the numerous "hook" methods within any table subclass.
In 2004 I came across this post which identified a study that broke down an application's code into several basic categories - business logic, glue code, user interface code and database code - and highlighted the fact that it is only business logic which has any real value to the company. It compared the productivity of two different teams and found that the team which spends less time writing glue code, user interface code and database code can spend more time writing the "value" code and therefore be more productive. Time spent on writing anything other than the "value" code has a negative effect on a team's productivity. In the RADICORE framework all the developer has to do is insert "value" code into "hook" methods as all other functionality is provided by the framework.
There are two basic approaches to writing a program:
My framework follows approach #2 by providing the following reusable components:
This means that you can define a new database table and produce the family of tasks to view and modify the contents of that table within 5 minutes without having to write a single line of code - no PHP, no HTML, no SQL. If you want anything more complicated than that then you can insert custom code into any of the various "hook" methods, or generate tasks using any of the other Transaction Patterns.
You should be able to see that when using this framework the ONLY code that you have to write is the really important code which deals with the business rules. All the basic unimportant code - the user interface, the database access, the glue code - is provided "out of the box" by the framework. What could be simpler than that? How can this be regarded as too simple?
Amongst the usual components which you DO NOT have to design and build are the following:
If you have to write any code to implement anything in the above list then I would say that rather than MY approach being too simple it is YOUR approach that is too complex.
One of my critics encountered the following code in my framework:
< php //***************************************************************************** // List the contents of a database table and allow the user to view/modify // the contents by activating other screens via navigation buttons. //***************************************************************************** $table_id = 'dict_database'; // identifies the model $screen = 'dict_database.list1.screen.inc'; // identifies the screen structure for the view $sql_select = 'dict_database.database_id, database_name, dict_database.subsys_id'; $sql_select .= ', (SELECT COUNT(database_id) FROM dict_table WHERE dict_table.database_id=dict_database.database_id) as table_count'; $sql_from = null; $sql_groupby = null; require 'std.list1.inc'; // activate page controller ?>
That is an example of a component script which exists in the Presentation layer, but because it is loading values which look like parts of an SQL query into variables that have "sql" in their names he started complaining that I had database logic in my presentation layer, and by doing so I was violating the rules of the 3-Tier Architecture. By making such a complaint he was advertising the fact that he could not tell the difference between "logic" and "information". For your edification here is an explanation:
Database logic is that program code which constructs and then executes an SQL query by calling the relevant <dbms>_query
function. Does that code in the sample above actually execute an SQL query, or does it simply move a string of text into a variable? If it does not execute an SQL query then how can it possibly be called "database logic"?
In a previous blog post entitled In the world of OOP am I Hero or Heretic? there is a section labelled What are the benefits of OO Programming? which contains the following statement from a person who goes by the moniker lastcraft:
I find that OO is best as a long term investment. This falls into my manager's bad news (which I have shamelessly stolen from others at various times) when changing to OO...
1) Will OO make writing my program easier? No.
2) Will OO make my program run faster? No.
3) Will OO make my program shorter? No.
4) Will OO make my program cheaper? No.
The good news is that the answers are yes when you come to rewrite it!
If he really thinks that the benefits of OOP do not appear when first creating an application but only after you rewrite it then as far as I am concerned his approach to OOP is totally wrong. My own implementation has produced superior results with my very first attempt and not with any subsequent rewrite. Note that I have NEVER had to redesign and rewrite my code, all I have done is start from a solid foundation then enhance and expand it.
In Programming is an art, not a science I state that unless a person has the basic talent to begin with it will be very difficult to turn that person into a skilled programmer. Instead you will end up with a bunch of Cargo Cult programmers or Copycats. Being an art computer programming relies on a person's creativity and not the blind following of sets of pre-conceived rules. I managed to make the switch to OO programming by making myself familiar with the basic concepts - that of encapsulation, inheritance and polymorphism - then by reading the PHP manual (which at the time was for version 4) to work how to take advantage of them in my code. I was totally unaware of all the things called "best practices", "principles" and "rules" which is probably why I managed to create a very successful implementation.
This is not the first time that I have ignored other people's so-called "best practices" and achieved a superior result, which begs the question are these best practices really the best? In my humble opinion the answer is an emphatic NO! If you read my definitions of Excellent and Excrement you should be able to see and perhaps understand the points I have made in Ideas which score highly on the Faecal Scale. When I was made aware of all the different OO principles which materialised over the years I had great difficulty in understanding what they meant in practical terms. All I could see was a large number of words with very little substance. Descriptions such as "reason for change", "program to the interface, not the implementation" and "Depend on abstractions, not on concretions" were as clear as mud to me, and the lack of examples which proved they had any benefits could not convince me that they had any benefits at all. I spent most of my software career designing and building bespoke systems for software houses where, in order to win contracts, we had to prove that our solution was the most cost-effective. The quality of our software was judged on the results which it achieved, not on the way in which it was built. What I have attempted to expose in this article is that, in my humble opinion, far too much of what is being taught to today's young programmers is not the best at all, it is much closer to being absolute rubbish. All the while newbie programmers are taught this rubbish they will never be better than rubbish programmers themselves.
Here endeth the lesson. Don't applaud, just throw money.
The following articles describe aspects of my framework:
The following articles express my heretical views on the topic of OOP:
These are reasons why I consider some ideas on how to do OOP "properly" to be complete rubbish:
Here are my views on changes to the PHP language and Backwards Compatibility:
The following are responses to criticisms of my methods:
Here are some miscellaneous articles: