Ever since I published The Model-View-Controller (MVC) Design Pattern for PHP which explains how I implemented this popular design pattern in my open source framework I have been told by numerous "experts" that my understanding of this design pattern is totally wrong, my implementation is totally wrong, everything I do is wrong, et cetera, et cetera, ad infinitum, ad nauseam, yada yada yada, blah blah blah.
I ignore all claims that my methods are wrong for one simple reason - they work! Anyone with more than two brain cells to rub together will be able to tell you that something that works cannot be wrong just as something that does not work cannot be right. Not only do my methods work, but they produce results which are more cost effective than any of the alternative implementations that have been thrust under my nose. If you think that this claim is bogus and your methodology is better then I suggest you prove it by taking this challenge. If you cannot do this in five minutes or less, and without writing any code, then you have failed.
Why are there so many alternative opinions? It is not just my implementation of MVC which is questioned, if you care to search the internet for opinions on any aspect of OO programming, design patterns or so-called "best practices" you will find that everyone (and his dog, apparently) has a different opinion. Almost to a man everyone thinks that their opinion is the only one which has been sanctioned by the programming gods and that anything different should be treated as heresy and their practitioners should be burned at the stake.
The idea that there is only one version of "best practices" which should be allowed to exist will never work. What certain individuals describe as "best practices" which the entire programming community should follow is nothing more than "common practices" among their particular group, and different groups have their own idea of what is best for them. If any one group tries to force their opinions on another group then they will quickly hit a wall of opposition.
I never set out to implement the MVC design pattern in my framework at all. By this I mean that I did not read about it and then decide to implement it, I simply wrote the code in my usual inimitable style, and one day a colleague pointed out that what I had produced contained three components which carried out the responsibilities of the Model, the View and the Controller. What I started to build was based on the 3 Tier Architecture which I had encountered and successfully implemented in my previous language, but what I did was to split the Presentation layer into two parts by creating a single module which put the data into an XML file and then transformed it into HTML using XSL stylesheets. This became the View in my framework, and what was left over became the Controller. Unlike standard MVC the 3 Tier Architecture has a separate component for all data access, and this effectively split the Model into two parts, as shown in this diagram.
I often tell people that I implemented the MVC design pattern by accident, not by design.
Because I started by building my framework according to the rules of the 3 Tier Architecture it was quite obvious to me all business rules should be processed in, and only in, the Model. The idea that I should validate user data in the Controller before I inserted it into the Model just did not exist in my universe. I have a separate object for each database table, and I inject data into one of these objects using a standard insertRecord() method which validates that data BEFORE it is written to the database. If this data fails any validation checks then it is returned to the user with suitable error messages and it is NOT written to the database.
My Controllers are "skinny" by virtue of the fact that they DO NOT contain any business logic, any data access logic, or any view logic. All they do is receive requests from the user, translate those requests into one or method calls on one or more objects, and when those objects have finished their processing they are handed to the view object which extracts the raw data (which at this point is nothing more than a PHP array) and then transforms it into a document which is readable by the user. The document format could be HTML, PDF or CSV.
My Models are "fat" by virtue of the fact that they contain all the business rules which can be applied to the data for which they are responsible. Each Model is responsible for a single table in the database, but does not contain any logic which communicates with the physical database as this is handled by a separate Data Access Object. The idea of putting the business rules into separate objects did not occur to me as it violated two fundamental principles of OOP:
There are other features of my implementation which I have not seen anywhere else which would therefore make them totally unique:
While teaching myself PHP from various books and articles on the internet I saw the hand-crafted HTML being output in small chunks as the script progressed through its processing. While this may be OK for small and simple programs I knew that the applications which I would eventually be building would benefit from something more sophisticated, so I looked for an alternative approach. I had already encountered XML and XSL in my previous language and was impressed with its power and flexibility, and after verifying that the necessary processing was available in PHP I decided to use these in my templating engine. While I did start off with a separate XSL stylesheet for each web page, after a period of refactoring I managed to create a small collection of reusable XSL stylesheets which could be used to generate any number of web pages. This meant that I could create a single View object which could extract the data from one or more Model classes and transform it into a web page whose structure was defined in one of my 12 XSL stylesheets. This method also became useful when it was decided to convert the GM-X application to provide responsive web pages. All 2,700+ screens were converted in one man-month, as documented in GM-X: The World's First Mobile-First ERP.
All this was made possible because of certain design decisions which I made at the start of my PHP development. I have subsequently been told by several OO "experts" that these design decisions were totally wrong, but as these decisions have produced nothing but excellent results I can only conclude that these "experts" are either barking up the wrong tree or are barking mad.
These design decisions were influenced by the following observations:
I do not follow the instructions contained in Domain Driven Design (DDD) where it says that every use case should have its own method in a Model as this would completely remove the ability of my framework to have such large amounts of reusable code. Instead each use case has its own entry on the MNU_TASK table which then provides the following abilities:
It should be obvious to any competent programmer who understands OO theory that having a huge number of unique non-sharable methods immediately removes any opportunities for polymorphism, without which you cannot have Dependency Injection (DI). If you do not have a choice of dependencies which you can inject into an object then you cannot reuse the functionality provided by that object. Thus instead of having 40 pre-written and reusable Page Controllers I would need to write thousands of custom controllers to deal with each of those unique methods.
While the description of the MVC pattern clearly identifies three separate elements - the Model, The View and the Controller - and identifies the responsibilities that should be carried out by each, there are continuous and often heated debates about what pieces of logic (program code) should go where. This debate often boils down to three different options:
As you should already be aware I favour the first option where the Controller does not contain any business logic, data access logic or view logic as these are handled by totally separate components. All the Controller does is as follows:
I have performed a quick search on the internet on this topic and found numerous different opinions, some of which are listed below along with my reasons for either liking or disliking them.
Up to this point, the examples in this book have been applying the opposite of a fat model, skinny controller, which is a fat controller, skinny model. The term "fat" implies the presence of business logic; "skinny" implies the lack thereof.It also states the following:
No matter which approach you take, the end goal of the fat model is to place all of your business logic in the M of MVC. The M should be able to stand alone as a complete application (without a user interface). The V and C that interact to make it MVC can be a console application, a RESTful API, a web application, etc. It shouldn't matter to the M.This to me is so blindingly obvious I simply do not understand why other people struggle with it. Each Model can be accessed by any number of Controllers, each for a different use case, and it is vitally important that every use case has access to the same business logic for the same Model. The only way to absolutely guarantee that different Controllers which act upon the same Model has access to the same business logic is to put that logic in the Model and NOT to duplicate it across several Controllers.
What is the single responsibility of models? Is it to hold business logic? Is it to hold non-response-related logic?I'm afraid he has this backwards. Models are the same as domain objects as they hold all the business logic for the domain. All business logic resides in the Business layer while data access logic resides in the Data Access layer. The names "business layer" and "data access layer" already contain hints as to the type of logic which each layer should contain, so there should be no excuse for this level of confusion.
No. Its responsibility is to handle the persistence layer and its abstraction.
Business logic, as well as any non-response-related logic and non-persistence-related logic, should go in domain objects.
I do believe that it's better to have a fat model than a fat controller, as controllers are notoriously difficult to test and even more difficult to DRY up ("don't repeat yourself"). But the problem with this approach is that, as your application grows, it will end up with god objects - huge, monolithic models with thousands of lines that are very difficult to maintain.I disagree with the idea that as your application grows the Models get fatter and fatter. I have a separate Model class for each table in the database, and as my application grows I add more database tables, and create a new Model for each new table. I do not have to amend any existing Models, Controllers, Views or Data Access Objects.
There are times when a particular Model requires several different tasks which require different sets of custom code, and sometimes this custom code would like to occupy the same "hook" method as another task. I solve this problem by creating a subclass of the Model where the base class contains the code for the common tasks and the subclass contains only that code which is required by a specialist task. By "base class" and "subclass" I mean the following:
The author misunderstood "model" in MVC. It's a layer, not a class.Where on earth did this idea come from? None of the articles which I have read concerning MVC have ever said that any of those three objects is anything other than a single object. While some individuals may choose to split any of those objects into smaller parts it is an option and not a requirement. The fact that in my own implementation I have put the processing of primary validation into a separate class is my own personal choice and not because I was following the "advice" of some gormless guru.
The only way I can justify referring to the Model as being a layer and not just a single class or object is when all database access is stripped out of the Model and placed in a separate Data Access Object (DAO). In my own framework I have a different version of this object for each supported DBMS, which then allows me to switch my application from one DBMS to another simply by changing one line of code in my config file.
Some people seem to think that by putting ALL the business rules in a Model would make them too fat, so they suggest splitting out all this logic into collections of different service objects. This violates the primary purpose of encapsulation which states that
ALL the data and ALL the methods which operate on that data should go into a SINGLE class. If you separate them then you are creating anemic domain models which are considered to be an anti-pattern.
MVC is a USER INTERFACE design pattern, not an application or architectural design pattern.
In the same comment he said:
The M in MVC is the Model that holds the data for the VIEW, not the application data that you store in a database!I disagree most strongly. In any software application the data does not simply exist in the Model waiting to be displayed in the View, it is persisted in a database so that it can be maintained over a period of time, which could be many years. That data is also subject to different sets of business rules during the input process and also the output process, and it is the Model which also contains these business rules. It is the Model which is at the heart of every application. The data which it holds is written to and read from the database, and it is also read from and written to the user interface.
Consider the following statement:
Some people know only what they have been taught while others know what they have learned.
When I made the transition to an Object Oriented language (PHP) after 20 years of working with COBOL (procedural) and UNIFACE (model driven, component based) I already had vast experience with designing and building database applications. I had been taught different ways of doing things, some better than others, and I learned to separate the wheat from the chaff. When I came across a different idea I learned to evaluate it to find out whether it led me down the path to higher productivity or the road to hell. Working for a software house where I worked on one new project after another for different clients the primary consideration was cost-effectiveness not code purity. The former is easy to measure while the latter is purely subjective as different people have totally different ideas as to what "purity" and "perfection" actually mean.
I created a set of personal development guidelines which were later adopted as the company standards. I developed a framework in COBOL which immediately made every developer in the company more productive. I rewrote that framework in UNIFACE when the company switched to that language. When I switched to using PHP as a self-employed contractor I rewrote that framework for a second time. With each of these rewrites I found that I could use the features of the new language to become even more productive. For example, in order to develop a common family of forms the amount of time taken was 5 (five) days in COBOL, 1 (one) day in UNIFACE and 5 minutes (yes, FIVE MINUTES) in PHP. So when other developers have the audacity to tell me that my methods are wrong, even though their levels of productivity are way below mine, is it any wonder that I question their competence?
Instead of going on courses to be taught the "right" way to implement the concepts of Object Oriented Programming I taught myself using just three sources: the PHP manual, online tutorials, and various books. I had no idea at that time that I was not following the rules of Object Oriented Design (OOD), Domain Driven Design (DDD), Design Patterns and the SOLID principles. I did not follow these rules simply because I did not know that they existed, and after rewriting my framework to take advantage of these new concepts called Encapsulation, Inheritance and Polymorphism I saw that it made me more productive than ever before. When people started to tell me that I should refactor what I had done in order to follow their version of "best practices" I refused to do so for one simple reason - it would have ruined what I had done and replaced simple code with vast swathes of complicated and inefficient code and obliterated all my gains in productivity. That did not strike me as a good idea.
Every time you ask a different person how to implement MVC you will get a different answer, and different reasons why one person's answer is superior to another's. In reality there is no such thing as a single definitive answer which is 100% right for 100% of the population, so all you can really do is follow the answer with which you feel the most comfortable and which gives you the best results. Sometimes this means trying different approaches so that you can compare the results and reach your own conclusions instead of picking one answer out of a hat and running with it regardless of the consequences, only to discover at a later date that the option you chose was not actually the best.
Anyone who follows a rule simply because it was the only one which they were taught is in great danger of becoming nothing more than a Cargo Cult Programmer, a Copycat or a Code Monkey. Such people are incapable of having an original thought as they rely on other people to do the thinking for them. They will never be leaders, only followers. They will never be innovators, only immitators. A good developer should not be afraid to question every rule, to question why it should be followed, to compare it with the alternatives and to then make up their own minds as to which is actually best for them. If you can achieve better results by not following a particular rule then how can that rule be justified? Following a bad rule just to be consistent will do nothing but make every follower consistently bad.
I consider my implementation to be more "correct" than the alternatives simply because it allows me to create and maintain application components at great speed. My ERP application currently covers over 16 business domains, contains 450+ database tables, 1,200+ relationships and 4,000 tasks (use cases). As the application was built using a combination of the 3 Tier Architecture and MVC design patterns, as shown in this diagram, it is comprised of the following groups of components:
These components can either be regarded as services or entities.
Note the following:
You may think that my methods are wrong, but unless you can prove that your methods are better by taking this challenge and producing results of the same quality in the same (or less) time then I shall continue to ignore you.
Here endeth the lesson. Don't applaud, just throw money.