I think this is a necessary point. We keep going round in circles:
Tony: This is how I do $whatever, isnât it great?
Everyone else: That approach can be improved/is outdated/causes issues
Tony: No it canât STOP TALKING ABOUT MY CODE!
Incorrect. I simple said that DI is evil when used in inappropriate circumstances. I showed that in my framework I actually DO use DI when the appropriate circumstances exist, but where those circumstances do not exist I do not use DI. I never said that where I do not use DI the code that I use is better than DI.
Are you going to defend your claim that a statement on wikipedia (With [citation needed], I might add) is more authoritative than peer reviewed academic papers or will you concede that academic papers are more likely to be correct?
Your view is that I must be breaking SRP simply because I have a class with 120 methods. Coming to that opinion based on nothing more than a count is not an acceptable method. That class represents nothing more than the Model in MVC. It does not contain any control code as that is held is separate Controllers. It does not contain any view code as that is held in separate Views. It does not contain any Data Access code as that is held in separate Data Access Objects. It does not contain any code which does not belong in the Model, so it does not violate SRP. Others may have a different opinion, but that is their concern, not mine.
You are again talking about SoC and not SRP. They are different. One is about the architectural split of main tasks or services within a software and the other is about single reason for change within a class.
SoC
SRP
You said,
The model in MVC holds a good bit of different functionalities for the application. Actually, it holds all of it really, or it is extended to hold the rest of the functionality. This goes seriously against SRP stated in Wikipedia.
every class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class.
So I donât have to do much more proving. You prove you break SRP on your own, through your own statement.
No, it breaks SRP because it has more than one reason to change
Youâre generating a PDF. If this PDF generation logic needs to change, you need to change the class. For example
var $pdf_destination; // I=Inline (browser), D=Download (browser), F=Filename (on server), S=String
If you need to add another option to this, the class needs to change
Youâre generating a CSV:
var $no_csv_header = false;
If you want to change the way the CSV is generated you need to change this class
var $no_display_count = false;
Whatever this does, if you want to change the way the display count is used you need to change this class
var $pageno;
If your pagination logic changes, you need to change this class
var $picker_subdir; // subdirectory for the File Picker
var $picker_filetypes = array(); // array of file types
If you want to use a different file picker or change the way the file picker works you need to amend this class. For instance adding a file-size limit as well as a file type limit here.
var $report_structure; // report structure
If you add a new report structure, this class needs to change
var $wf_case_id; // workflow case id
var $wf_context; // workitem context
var $wf_workitem_id; // workflow workitem id
var $wf_user_id; // update workitem with this value, not $_SESSION['logon_user_id']
If the âworkflowâ structure changes, you need to change this class
// the following are used to construct SQL queries
var $default_orderby = null; // default for table, may be overridden by $sql_orderby
var $default_orderby_task = null; // default for task, may be overridden by $sql_orderby
var $sql_from;
var $sql_groupby;
var $sql_having;
var $sql_no_foreign_db = false; // if TRUE _sqlProcessJoin() method will skip tables in other databases
var $sql_orderby; // sort field
var $prev_sql_orderby; // previous sort field
var $sql_orderby_seq; // 'asc' or 'desc'
var $sql_orderby_table; // tablename qualifier for optional sort criteria
var $sql_search; // optional search criteria from a search screen (modifiable)
var $sql_search_orig; // original search criteria (unmodified)
var $sql_search_table; // tablename qualifier for optional search criteria
var $sql_select; // fields to be selected
var $sql_selection; // selection passed down from previous task
var $sql_union; // optional UNION clause
var $sql_where; // additional selection criteria
If you want to support a different query grammar you need to change this class
var $dirname_dict; // directory name where '*.dict.inc' script is located (optional)
If you want to support a different dictionary format, this class has to change
var $inner_table; // used in an outer-link-inner relationship
To add different relationship types, this class has to change
There are dozens more and thatâs just looking at the variables.
You mean you have to write your own code to get your application going? How quaint! How so-o-o-o last century! All 2,500 user transactions in my application are started from a script such as this:
<?php
$table_id = "person"; // identify the Model
$screen = 'person.detail.screen.inc'; // identify the View
require 'std.enquire1.inc'; // activate the Controller
?>
And guess what? Each of these scripts is generated by the framework from a GUI screen. The Controller scripts are part of the framework, and each Model class is generated by the framework from another GUI screen. The $screen script specifies which XSL stylesheet will be used by the standard View component. This is how I can generate the code for a user transaction, and run it immediately from an online menu, without having to write a single line of code - no PHP, no HTML, no SQL. This transaction will automatically include all default behaviour, and the developer only has to write code when he wants to alter this behaviour.
Neither does anyone else - the difference is they create small REUSABLE objects that end up in many different applications whereas you have written objects that canât be reused and so are stuck with the version you have got.
Why not just accept that your idea of good programming is different to everyone else in the world and stop trying to convert everyone else to your view when you absolutely refuse to even consider that some of what everyone else is saying might be right.
All of that is well and good, but none of it has anything to do with the definition of a framework. Iâm happy you think youâve done some great work on your application, but again, one of the definitions of a framework is as follows:
Inversion of Control: In a framework, unlike in libraries or normal user applications, the overall programâs flow of control is not dictated by the caller, but by the framework.
I highlight âthe callerâ here because that phrase is important. It means we, the application developer call the framework, and then the framework runs the application. It does not mean we donât have to write any code.
Iâm not sure what the relevance of your applicationâs structure is to this conversation about what a framework is. Whether you think writing code to run a framework is quaint or not doesnât change the fact that, for a framework to be a framework, you have to write code to call it.
If in RADicore, you donât have to write code to make it do anything, it would be more appropriately termed an application in and of itself. Similarly, WordPress is an application, as it doesnât require anyone to write any code for it to run.
Itâs probably worth also looking at what the big players call frameworks. Microsoftâs .NET Framework? Does it work without providing any code? Nope, you need to provide code to use it (At minimum you need to write an entry point). Googleâs WebApp2 framework: https://cloud.google.com/appengine/docs/python/gettingstartedpython27/usingwebapp Oh, look at that, the first example shows that you have to call a method on the framework to register your classes with it:
[self.homeManager addHomeWithName:@"My Home" completionHandler:^(HMHome *home, NSError *error) {
if (error != nil) {
// Failed to add a home
} else {
// Successfully added a home
}
}];
So thatâs an academic journal from CERN relating to work on the large hadron collider, an academic paper from Manchester University, Google, Microsoft and Apple who all disagree with Tonyâs statement
You have obviously forgotten that the title of this thread is âWould you agree that this is the definition of a PHP framework?â In post #4 you referred to a definition of a framework in https://en.wikipedia.org/wiki/Software_framework and also http://ifacethoughts.net/2007/06/04/difference-between-a-library-and-a-framework/. In post #15 I agreed with the definitions in those articles but not with some of your other comments. In post #16 I described how Radicore met the four characteristics of that wikipedia definition but without discussing the code that I used to do it. If you read the subsequent posts you will clearly see that it is YOU and your partner-in-crime @TomB who wandered off the topic in this discussion and started to attack my coding style and my failure to adhere to your version of âbest practicesâ.
If you want this discussion to stay on-topic then I suggest that YOU stop making posts which are off-topic. As long as you keep attacking me I reserve the right to defend myself.
You also claim that my abstract Model class breaks SRP/SoC simply because it has 120 methods. Everybody knows that SRP/SoC has nothing to do with counting methods or lines of code, it is about the separation of responsibilities or concerns. Robert C. Martin had this to say on that subject in his article http://blog.8thlight.com/uncle-bob/2014/05/01/Design-Damage.html
He is saying quite clearly that in a âgood designâ the logic for GUI. business rules and database should be separated. This description matches the 3-Tier Architecture EXACTLY and which is EXACTLY what I have implemented. Not only that I have also incorporated the MVC design pattern for good measure. My implementation matches Robert C. Martinâs description to a tee, so when you say that my implementation is wrong you are also saying that Robert C. Martin is wrong.
What is YOUR definition of SRP/SoC and why is it so much better than Robert C. Martinâs?
This is an excerpt from the book Clean Code by Robert C. Martin:
Classes Should Be Small!
The first rule of classes is that they should be small. The second rule of classes is that they
should be smaller than that. No, weâre not going to repeat the exact same text from the
Functions chapter. But as with functions, smaller is the primary rule when it comes to
designing classes. As with functions, our immediate question is always âHow small?â
With functions we measured size by counting physical lines. With classes we use a
different measure. We count responsibilities.1
Listing 10-1 outlines a class, SuperDashboard, that exposes about 70 public methods.
Most developers would agree that itâs a bit too super in size. Some developers might refer
to SuperDashboard as a âGod class.â
He specifically says that 70 methods is too much. He goes on to say:
Five methods isnât too much, is it? In this case it is because despite its small number
of methods, SuperDashboard has too many responsibilities.
The name of a class should describe what responsibilities it fulfills. In fact, naming
is probably the first way of helping determine class size. If we cannot derive a concise
name for a class, then itâs likely too large. The more ambiguous the class name, the more
likely it has too many responsibilities. For example, class names including weasel words
like Processor or Manager or Super often hint at unfortunate aggregation of
responsibilities.
We should also be able to write a brief description of the class in about 25 words,
without using the words âif,â âand,â âor,â or âbut.â How would we describe the
SuperDashboard? âThe SuperDashboard provides access to the component that last held the
focus, and it also allows us to track the version and build numbers.â The first âandâ is a
hint that SuperDashboard has too many responsibilities.
and
To restate the former points for emphasis: We want our systems to be composed of
many small classes, not a few large ones. Each small class encapsulates a single responsibility,
has a single reason to change, and collaborates with a few others to achieve the
desired system behaviors.
You have repeatedly stated that your system is âa few large onesâ. And letâs be clear, he called a 70 method class too large, your 120 method class is nearly double that.
He also says:
Classes should have a small number of instance variables. Each of the methods of a class
should manipulate one or more of those variables. In general the more variables a method
manipulates the more cohesive that method is to its class. A class in which each variable is
used by each method is maximally cohesive.
Your class has about 50 variables, some of which arenât used in the class and itâs impossible to sum up. So letâs turn it around: What is YOUR definition of SRP/SoC and why is it so much better than Robert C. Martinâs?
No, they are NOT different. They both talk about âseparationâ and breaking down code into smaller modules. If you ask the average programmer to specify the difference between a âconcernâ and a âresponsibilityâ you will find that there are none. You cannot apply these two principles to the same piece of code and get different results so they are the same.
I prove no such thing. I have clearly implemented the MVC design pattern as I have different components for the Models, Views and Controllers and this conforms to the definition of SRP. I do NOT have a monster Model class for the entire application, I actually have a separate Model class for each table in my database (and my application has over 300 tables). So each Model class is responsible for the validation and business rules for a SINGLE database table, so again it matches the âSingle Responsibility Principleâ.
Not according to Robert C. Martinâs definition of âreason to changeâ.
Wrong. That is a variable in the Model which is passed to the View object which is responsible for the production of PDF documents.
Wrong. That is a variable in the Model which is passed to the View object which is responsible for the production of CSV files.
All your accusations are wrong. Those are simply variables which are defined in the Model but which are passed to other objects for the actual processing. It is these other objects which contain the logic which deals with the contents of those variables so to say that my Model class contains too much logic is completely bogus.
Excellent then you also have broken encapsulation. Youâve quoted this exact definition before:
Encapsulation is the packing of data and functions into a single component. The features of encapsulation are supported using classes in most object-oriented programming languages, although other alternatives also exist.
A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data.
You have just said you have the data in the model and the functions in the view. The data and functions are in different components. So thatâs two for two.
Completely wrong, as usual. In the first place it is my framework which contains the most reusable components as I have used it to build several different applications. It is the framework that supplies the Controllers, Views and Data Access Objects, while each application provides nothing but the Models.
In the second place my main enterprise application is comprised of 9 modules each of which has its own database as well as being able to share components from other modules.
You can use my framework to create you own applications, but you cannot take one of my application components and reuse it in your application.
Nowhere in the Wikipedia definition of a framework does it say that the developer has to write code to call the framework before the framework takes control. While a little code may be necessary in order to tell the framework which application component to run, it should be so little and so simple that the framework should be able to generate it for you. That is exactly what Radicore does.
You arenât reading what I wrote. I said that you donât have to write any code in order to generate components which have basic and default behaviour, but you DO have to write code in order to change or enhance that default behaviour.