Ever since I started publishing articles on my website I have been told by many people that my approach to OOP is totally wrong, my code is crap, that I am idiot and that I should go back to school and learn how to do things properly. I flatly refuse to follow this "advice" as I consider it to be seriously flawed, and by following it the quality of my work would be seriously compromised. I had over 20 years of experience in the design and development of enterprise applications before I switched to using an OO-capable language in 2002, and during this time I was responsible for writing the company development standards in two programming languages, COBOL and UNIFACE. The "rules" or "standards" or "best practices" that I followed were based on years of practical experience and not some theories that I read in a book but never implemented.
In my early days I was exposed to different sets of standards in different development teams, so I quickly learned that there was no single set of standards which was applicable to everybody. I also noticed that the details in one team's standards completely contradicted that found in another's, so I knew that these standards were not produced by some global wisdom but by local preferences and prejudices. I also noticed that some of these local preferences were based on misconceptions or outdated ideas, so the idea that they represented "best practice" just did not hold water. I remember a particular instance in 1981 where I found that the project standards were actually preventing me from writing effective software, so I abandoned them and followed my own instincts. When my program was examined as part of a project audit I still remember the verdict by the auditor, a senior programmer from a different team:
This program does not conform to the project standards. However, it is the most well written, well structured and well documented program in the whole project.
If the purpose of standards is to help developers write better software, yet I can produce superior software by ignoring them, then what does that say about the quality of those standards? This told me that some standards are worth following while others should be flushed down the toilet. This is why I question every rule and refuse to adopt it unless its benefits can be proved. Being told "Do it this way because I say so" is simply not acceptable.
When I became a team leader and could write my own standards I only included that which could be justified and which could be shown to produce better results than the alternatives. I concentrated on the important points and left out all the tiny nit-picking details. These programming "rules" or "standards" can be summed up as follows:
This thought was epitomised in the following quote:
Programs must be written for people to read, and only incidentally for machines to execute.
Abelson and Sussman, Structure and Interpretation of Computer Programs, 1985
In his blog post Avoiding object oriented overkill Brandon Savage wrote:
Code spends 80% to 90% of its life in maintenance. And in my own experience, the people maintaining the code are not always the same people who wrote it. This means your code is going to have to communicate with more than just a computer processor. It's going to have to communicate intent to developers who have never seen the code before. This is much more challenging than writing code that "just works."
If there is a choice between a simple solution or a complex solution my experience has shown that the simpler of the two will be the easiest to maintain and enhance in the long run. This thought was epitomised in the following quote:
There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies.
A novice programmer can quite easily fall into the habit of writing code that he has already written somewhere else, so ends up by having the same code appearing in multiple places. If that code ever has be changed at a later date this means that each copy of that code has to be located and amended. The best solution would be to put that code into a central library and then call that library routine whenever that code is needed. I started building my first library in 1983, and this expanded into a full blown framework in 1986. If you don't know the difference between a library and a framework you should read What is a Framework?.
The first piece of source code that I ever worked on did not have a proper structure and was littered with GOTOs, which made it difficult to understand how it did what it. The second program was totally different as it used proper procedure calls instead of GOTOs, each procedure had a meaningful name, which made it very easy to draw a structure diagram to quickly identify what happened where and in what sequence. This lesson was later reinforced when I attended a Jackson Structured Programming course in which the benefits of basing the software structure around the database structure became clearly evident.
I have worked on database applications for my entire career, and I have witnessed the results of working with a database which was badly designed and which had data elements in the wrong place. Consequently every database that I design is always properly normalised as I know that this will greatly reduce the possibility of problems appearing later on.
Some programmers like to design their software and leave the database design till last as they consider the database to be a mere "implementation detail". I do not. My experience has taught me that the most important part of a database application is the database, and it is the software which is the implementation detail. This thought was epitomised in the following quote:
Smart data structures and dumb code works a lot better than the other way around.
Eric S. Raymond, "The Cathedral and the Bazaar"
In my early days as a programmer it was common practice to put all the components of a program - the user interface, the business rules, and the database code - in a single unit. When I was later introduced to a layered architecture, first 2-Tier and then 3-Tier, I immediately saw its benefits and have used it ever since.
When breaking a huge monolith into sets of interconnected modules it is important to identify how many modules will be required and what code should go into each one. High cohesion is better than low cohesion. My experience with the 3-Tier Architecture taught me that 3 layers is enough, but after I found myself splitting the Presentation Layer into two parts - a Controller and a View - I also found myself implementing the Model-View-Controller design pattern.
When an application is broken down into collections of small modules which interact with one another the way in which one module calls another is called coupling. Loose coupling is better than tight coupling. If two modules are so tightly coupled that a change in one produces a ripple effect of corresponding changes in the other then this is a bad sign.
I switched to using PHP when I wanted a language that made it easier to build web applications following the disaster I encountered with my previous language. As I played with the language I discovered that it supported this alien concept called Object Oriented Programming, so I needed to know what it meant and how I could use it. The description that I read at the time defined OOP as:
Object Oriented Programming is programming which is oriented around objects, thus taking advantage of Encapsulation, Polymorphism, and Inheritance to increase code reuse and decrease code maintenance.
My first task was to take the framework that I had already developed in two prior languages and redevelop it in a third. I worked on the assumption that an OO language is exactly the same as a procedural language except for the addition of encapsulation, inheritance and polymorphism, so it was all down to how well I utilized these features which would tell if my efforts were successful or not. According to the above definition I reckoned that "success" would be directly related to how much reusable code I created, and one method of reusing code that is not available in a procedural language is inheritance. It was immediately obvious to me that in an application that communicates with objects (tables) in a database there should also be corresponding objects (classes) for each of those tables in the software. It was also immediately obvious that code that was common to every database table could be placed into an abstract table class and then inherited by every concrete table class.
Another method of reusing code is via polymorphism, so I developed a library of page controllers which called methods on an unspecified object where the actual object (class) name was specified at runtime. I then ended up with a collection of table classes which could be called from any controller, and a collection of controllers which could be used with any table class.
My new framework, with its increased levels of reusability, allows me to create new application components at a much faster rate than either of its predecessors, and after using and enhancing it for over 15 years I can safely say that it is not at all difficult to maintain. Because of these results I deem my efforts to be a great success, so imagine my surprise when other developers keep telling me that my methods are wrong! They reach this amazing conclusion not by looking at the results which I achieve but by noticing that my methods are different from theirs. They are under the impression that as they were taught only one method that it must be the only method, the right method, and anything which does not conform to the "right" method, which does not obey the same set of rules, must automatically be "wrong". My methodology cannot be wrong for the simple reason that it works, and anyone should be able to tell you that anything that works cannot be wrong just as anything which does not work cannot be right. Instead of my methods being wrong because they follow a different set of rules I would say that the superior results which I achieve point to their methods being wrong. Inferior results are produced by inferior methods which in turn are caused by following inferior rules. In other words their methods are RUBBISH!
I can think of two major reasons for this proliferation of rubbish rules - mis-interpretation and mis-invention.
By this I mean where someone has taken a documented principle and comes up with an interpretation which goes far beyond what was originally intended. This may be because the original principle was badly phrased, or because the words used have a different meaning in a different context.
Another common problem with misreading a principle is where it is documented as being beneficial in certain circumstances or where appropriate, but where the implementor forgets this and applies it indiscriminately in all circumstances. Sometimes this is because the implementor does not have the brain capacity to work out if the principle is actually appropriate in his circumstances or not, so he takes the lazy option and implements it anyway.
A less common problem is what I documented years ago as the Reverse Imperative Principle (RIP). This is where a programmer must not only follow a rule he must be seen to be following that rule, so he inserts the relevant code as proof without realising that the code actually adds unnecessary complexity to his program instead of providing a genuine benefit.
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. 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.
When defining the primary key for a database table you should first look for a semantic or natural key, and if one cannot be found then use a technical or surrogate key instead. Some novice designers ignore this advice and go straight for a technical key without further thought. Even when you point out those circumstances where a technical key is not the best solution they dismiss your arguments by saying "But technical keys are the rule!"
The original definition stated a class should have only one reason to change, but this was open to so much confusion and mis-interpretation the author later qualified it by saying the following in Test Induced Design Damage:
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.
He followed this in The Single Responsibility Principle by saying:
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.
The three areas of logic - GUI, business rules, database - he identified here was a perfect match for the 3-Tier Architecture. As I was already implementing this architecture in my development framework I decided that no additional work was necessary on my part.
There are some people out there who think that putting an entity's business rules into a single class is wrong - each individual rule should be in a separate class. What these numpties don't realise is that too much separation would break encapsulation, which is why I refuse to go down that route.
Anybody with more than two brain cells to rub together will know that SRP and SoC mean exactly the same thing. There is no difference between "concerned with" and "responsible for". If Robert C. Martin writes articles in which the two terms are interchangeable then who can argue? Yet there are some numpties out there who think that The Single Responsibility Principle and Separation of Concerns do not mean the same thing and A class encapsulates a single responsibility but not a single concern. These people must be suffering from IDD (Intelligence Deficit Disorder).
This is worded as ""software entities should be open for extension, but closed for modification". The idea is that once completed, the implementation of a class can only be modified to correct errors; new or changed features will require that a different class be created. That class could reuse coding from the original class through inheritance.
If I followed this rule it would create nothing but problems, so I choose to ignore it. Every one of my 350+ table classes inherits from a single abstract table class which has a large number of properties and methods, and in the last 15 years I have added numerous methods and properties to this class. If every time I did that I was prevented from changing my base class and had to create a new subclass instead I would end up with a plethora of abstract classes, and this would cause nothing but confusion.
If you read this principle properly you should realise that it only applies when you inherit from one concrete class to create a different concrete class. I don't. All 350+ of my table classes inherits from a single abstract class. I never inherit from one table class to create a new table, so it is irrelevant and I ignore it.
Some people seem to think that they have to be seen to be following this rule, so they create interfaces which they then segregate as "proof". I ignore this rule completely for the simple reason that I don't use interfaces anywhere in my code. I don't use them because (a) they are optional, and (b) they serve no useful purpose. For more details please refer to Object Interfaces.
If you bother to read Robert C. Martin's original documentation on this principle you will see that his example COPY program clearly shows that using DI to inject a dependent object which can be supplied from any one of a number of alternative classes can be very useful. This is precisely how I use DI in my framework. However, where a dependent object can only be supplied from a single source then I do not use DI at all. There is no good reason to provide the ability to switch to a different implementation if there will never be a different implementation.
This is supposed to be a solution to the problem caused by having deep inheritance hierarchies where one class is extended to form another class. If you read the articles on this subject you should see that you can avoid the problem by NOT having deep inheritance hierarchies and by ONLY inheriting from an abstract class. This is precisely what I have been doing in my framework since I created it, so I have absolutely no use for this principle.
By this I mean where someone has invented a rule out of thin air, something which cannot be traced back to a documented source. This may be because of a severe mis-interpretation of a documented rule, one that is so severe that it could be classed as a complete perversion.
As far as I am concerned this idea is being propagated by those who think that OOP is some complicated process that can only be practised by those who have mystic capabilities. This is complete and utter bollocks rubbish. In my opinion OO programming is exactly the same a Procedural programming except for the addition of encapsulation, inheritance and polymorphism.
I have been designing and building database applications for 40 years, and in that time I have used three different languages. Regardless of the language the design process has always been exactly the same, it is only the implementation of that design which has been different. The design process produces two things, a logical database design and a list of Use Cases where each use case identifies the database tables that it needs to access in order to carry out its function. It identifies what should be done (the requirements), not how it should be done (the implementation). It is possible to take the same design and implement it in more than one language, and the choice of language may be affected by several factors, such as speed of development, its toolsets, or the availability of experienced programmers.
When I eventually read what OOD entailed, which was several years after I had completed my framework, I shook my head in utter disbelief. I do not waste my time with this "IS-A" nonsense as each object "is-a" database table. I do not waste my time with this "HAS-A" nonsense where a single class can be composed of more than one database table as this concept does not exist in a database. Each table in the database is a separate entity in its own right, so as far as I am concerned each entity requires its own class.
The language does not (or should not) affect the design, just how that design is implemented. The design is therefore language-agnostic, and the implementation of that design is an entirely separate matter. The language is therefore nothing more than an "implementation detail".
Where was this "principle" published? Who is its author? What are the reasons for the existence of this rule?
If it is so bad then why has Martin Fowler, the author of Patterns of Enterprise Application Architecture defined patterns called Table Module, Class Table Inheritance and Concrete Table Inheritance which specify "one class per table"?
Amongst the pathetic reasons which support this ridiculous claim was the following:
Abstract concepts are classes, their instances are objects. IMO The table 'cars' is not an abstract concept but an object in the world.
Classes are supposed to represent abstract concepts. The concept of a table is abstract. A given SQL table is not, it's an object in the world.
It is quite clear to me that this numpty simply does not understand the words that he wrote:
Each table in a database is a different entity and not just a different instance of the same entity. There is a standard concept called "table" but each physical table has a different implementation - its name and its structure. That is why each concrete class simply identifies its name and its structure while all the standard code is inherited from the abstract class.
Consider the following definition of a "class":
A class is a blueprint, or prototype, that defines the variables and the methods common to all objects (entities) of a certain kind.
If you look at the CREATE TABLE script for a table is this not a blueprint? Is not each row within the table a working instance of that blueprint? Is it therefore not unreasonable to put the table's blueprint into a class so that you can create instances of that class to manipulate the instances (rows) within that table?
Another numpty wrote the following:
This means you write the same code for each table - select, insert, update, delete again and again. But basically its always the same.
Wrong! Any code which can be applied to any table is defined in non-abstract methods within the abstract table class and therefore automatically shared by every concrete table class via that standard OO mechanism called inheritance. I suggest you read up on it and try it out for yourself.
This topic is discussed in more detail in Having a separate class for each database table *IS* good OO.
The idea that I should have different data names in each layer is complete and utter bollocks rubbish. Not only have I never worked on a team which practiced this notion, I have used several languages which were based on the assumption that each data element had the same name in every component. To do otherwise would have created masses of effort, so not only did I never see anyone attempt to do this, I never even heard of anyone discussing the possibility.
Such a ridiculous idea would require extra components to perform data mapping between each layer, so could only come from someone who has been brainwashed into using an Object-Relational Mapper. Such people should be pitied, not emulated.
The idea that the components in the business layer should not be aware that they are communicating with a database is complete and utter bollocks rubbish. It would be like writing a missile control program which is not aware that it is controlling missiles, or an elevator control program which is not aware that it is controlling elevators.
This idea could only come from someone who does not understand the rules of the 3-Tier Architecture where it is only the component in the Data Access layer which communicates with the database. This means that only the Data Access Object (DAO) can construct and execute SQL queries. This allows the DAO to be constructed from a different class at runtime, thus enabling the DBMS to be switched between MySQL, PostgreSQL, Oracle and SQL Server by changing a single line in a configuration file and without changing a single line of code in any of the other components.
Data validation is part of the business rules so belongs in the Business layer. Data which is going to be added to the database can only be validated in a Business layer component if that component knows the structure of that table. If the validation succeeds it does not build and execute an SQL query itself, instead it sends a message to the DAO saying "Add this data to this database table". This means that the Business layer is working with a conceptual model of the database and not a physical model. The Business layer knows that it is working with a database, but it does not know which one.
"Knowing the structure of the database" is not the same as "building and executing SQL queries". One of these is forbidden in the 3-Tier Architecture, the other is not.
This idea is only promoted by those dimwits who don't understand how relational databases work. They deliberately design their software without any regard to the needs of the database which they regard as nothing more than an "implementation detail". They get somebody with brain cells to design their database but guess what? There is now a mismatch between the software design and the database design. How do these dimwits solve that problem? By generating an additional piece of software to perform the mapping between to the two designs. How does an intelligent person solve the problem? Following the old maxim Prevention is better than Cure it is better to eliminate the problem than to cover up its effects. That is why I always start with the database design, then build my business/domain layer objects around this design with one class for each database table. Result - no mismatch, so no need for additional software to deal with a mismatch. I have automated the method by which changes in the database structure can be conveyed to the software, so it is easy to keep the two structures in sync.
That is because I write database applications whose only function is to manipulate data in a database. The data in that database can be spread across hundreds or even thousands of tables, yet the only operations which can be performed on each table are Create, Read, Update and Delete (CRUD). The objects in the Business layer support these methods, and the objects in the Presentation layer call these methods. There is a separate component in the Presentation layer for each Use Case or user transaction.
When designing a database application there are two parts - a logical database design and a list of use cases. Each use case is responsible for performing one or more of the CRUD operations on one or more tables. The list of operations is therefore fixed whereas the design of the database is totally flexible. This means that the design of the database is far more important and comes before the design of the software which can be considered as being nothing more than "an implementation detail". This can be summed in in the following quote:
Smart data structures and dumb code works a lot better than the other way around.
Eric S. Raymond, "The Cathedral and the Bazaar"
Get the database wrong and no amount of code will get you out of the mess that you have made yourself. Get the database right and the coding part will be much easier.
Where is this documented? This obviously is a mis-interpretation of the statement: "A properly written constructor leaves the resulting object in a valid state". In this context the term "valid state" does not mean the same thing as "data within the object must be valid". It actually means the following: "A valid object is one that can accept calls on any of its public methods".
This topic is discussed in more detail in Re: Objects should be constructed in one go.
Where is this documented? Just because it is used in some examples does not mean that it is a golden rule. People who work with hierarchical/network/relational databases know that they work with sets of data, not individual columns. Each dataset can contain any number of columns from any number of rows, which is why I prefer to stick to a single $fieldarray property which can hold that data. This means that I can make changes to the contents of that array, such as adding or removing columns, without having to change any method signatures, which is a good example of loose coupling.
This is only relevant if you have a separate class property for each table column (see previous point). As I use a single property for a complete dataset I can put the data into an object as a single input argument on a method call (as in
$dbobject->insertRecord($_POST)) and get it out again as a single result set.
Not according to Martin Fowler and his Table Module pattern. My single $fieldarray property allows me to deal with any number of columns from any number of rows in a single object, so why on earth should I change this to use a method which is less efficient and more cumbersome?
Where is that documented? Each domain object (model) is responsible for all its business rules, and as data validation is part of those business rules it means that the validation should be performed inside the model, not outside. If you take the processing of business rules out of the domain object you will end up with nothing but an anemic domain model which is considered to be a bad thing.
I don't use setters, so I can't. All data validation is performed by a standard validation object as part of the insertRecord() or updateRecord() operation. If the validation fails then the insert/update is abandoned and the method call returns an error message instead.
Where is this documented? Just because it is used in some examples does not mean that it is a golden rule. While most of my reusable page controllers do indeed work with no more than one model, I have some which work with 2, 3 or even 4. If this were truly "wrong" then it would cause problems, but it doesn't, so it isn't.
Where is this documented? Just because it is used in some examples does not mean that it is a golden rule. Each of my model classes inherits its public methods from my abstract table class, and as each controller speaks to its model(s) using these methods it means that any model can be accessed by any controller, and any controller can be used to access any model.
This is only relevant if you use an Object-Relational Mapper. Those of us who understand how databases work know that an SQL query does not use a variety of finder methods, it uses a single WHERE string on a SELECT statement which can handle a multitude of possibilities. I don't need to write special methods to manipulate this string as the language already contains a huge selection of functions. Once constructed I can use this string in a standard
$result = $dbobject->getData($where) command. I can even pass this string from one component to another with great ease.
Do you realise how much work this would create? In my ERP application I have 2,800+ tasks (use cases) and 350+ model classes. If I had a separate method in a Model for each of these tasks it would mean the following:
As the primary objective of using OOP in the first place is supposed to be to increase the amount of reusable code, the lack of reusability that following this principle would produce is a step in the wrong direction.
In my methodology I create an entry on the TASK table of my MENU database for each use case. This entry points to a component script on the file system which in turn points to a Controller and one or more Models where all communication between them is governed by the methods that were defined in the abstract table class. This means that the use case name is defined in the MENU database and not as a method name within a class. The user selects which task he wants to run by its name in the MENU database, and the Controller which is activated for that task uses generic methods to perform whatever action is required.
I do not have to create any special methods in a Model as all the public methods I need are inherited from a single abstract class. I do not have to put any special method calls into any Controller as they only use the same public methods which are defined in the abstract class. Each of my Controllers has been designed to be reusable with ANY Model, so is available as a pre-written component in my framework. So if I have 40 Controllers and 350 Models this equates to 40 x 350 = 14,000 (FOURTEEN THOUSAND!) opportunities for polymorphism. If I followed your rule I would not have this level of reusability, so I don't follow your rule.
A colleague once told me that all the big boys use a front controller, and if I wanted to be in their club then I should use one as well. He is now an ex-colleague. In my methodology each URL in the application points directly to a component script in the file system, and this script identifies IMMEDIATELY what parts of the application are being used to do what. This makes debugging far easier as you don't have trawl through multiple lines of code in various front controller and router objects to obtain what can be expressed in three lines.
There is no such thing as the "right" design patterns. Each programmer is allowed to use whatever design patterns he sees fit in whatever way he sees fit. To me design patterns are just like training wheels on a bicycle - they're OK when you are a novice, but after that they become more of a hindrance than a help. An experienced and competent programmer does not write software by first making a list of design patterns which it should use, he simply writes code and design patterns appear naturally of their own accord. This is what Erich Gamma said at an interview in May 2005:
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.
Another reason why I do not use design patterns with the same religious fervour as others is that they are not proper patterns at all. They do not provide pre-written code that can be used over and over again, they merely provide an outline of a design which you then have to implement yourself by writing your own code over and over again. I much prefer to use Transaction Patterns as they provide pre-written and reusable code which can be linked with any Model to produce a working transaction without the need to write any code whatsoever. That is why each use case has its own component script which does nothing but identify which Controller should be linked with which Model and which View.
Some people tell me that my abstract table class has so many methods that it surely must be breaking SRP and that it surely must be a God Object. They do not understand that the content of a class is not governed by the ability to count but by the ability to think. The description of encapsulation makes it quite clear that ALL the properties and ALL the methods for an entity should be put into the SAME class, and not spread across multiple classes. I am already obeying Robert C. Martin's definition of SRP by putting presentation logic and database logic into different objects, and I am also doing the right thing by following what he says in his article about Anemic Domain Models:
It's also worth emphasizing that putting behavior into the domain objects should not contradict the solid approach of using layering to separate domain logic from such things as persistence and presentation responsibilities. The logic that should be in a domain object is domain logic - validations, calculations, business rules - whatever you like to call it
He does not say that each of those areas of logic - validations, calculations, business rules, etc - should go into a separate object, he specifically says that ALL the business logic for a single entity should go into a SINGLE object while presentation logic and database logic should be handled separately. It is quite clear to me - there should be one object in the business/domain layer for each entity.
Other rules which I regularly break are identified in the following articles:
It is important to understand that the purpose of a software developer is to develop cost-effective software for the benefit of the paying customer, and not to impress other developers with the cleverness of his design or his ability to follow a set of arbitrary rules in a dogmatic and pedantic fashion. The dogmatist will follow a set of rules and assume that the results will be satisfactory. The pragmatist will aim to produce the best result possible and will follow those rules which support this endeavour and ignore those which do not.
When you work in a software house building applications for different clients you will quickly realise that the most important factor is the ability to deliver effective solutions as quickly as possible. Hitting the target quickly is more important than following rules blindly. Time is money, so the more time you spend in creating a solution the more expensive that solution will be. When you are competing against other software houses then he who finishes first takes the prize. A good set of development standards coupled with a good library of reusable software (or even better, a good framework) will always give you an edge over your competitors.
The idea that there is a single set of "standards", "rules" or "best practices" which every programmer should follow is a load of nonsense. Each group follows the standards which are best for them, and they will strongly resist having some outsider's standards imposed on them. Remember that programming is an Art and not a Science, which means that programming cannot made be made subject to scientific rules, it is subject to artistic interpretation.
Some of the rules which I am told I am breaking may actually be based on a genuine idea, but which have been seriously misinterpreted because the original description of the principle was inadequate, vague or wishy-washy. In other cases some people simply do not understand what they read or choose to read what isn't there. In some cases I have come across rules which are simply figments of someone's wild imagination and have never been published by any professional body.
As far as I am concerned I will not accept any rule unless that rule can be justified. I need to know under what circumstances it is supposed to produce benefits, and I need to know what problems will arise if I don't follow the rule. Rules which are a matter of opinion and not fact carry very little weight in my universe. If a rule cannot be justified then as far as I am concerned it has no right to exist and I should be able to ignore it with impunity.
When I write software I, like every other developer, am constrained by certain limitations:
I refuse to be constrained by the limitations of your intellect as it would be the equivalent of going back in time and living with neanderthals.
As I have said in a previous article:
Progress comes from innovation, not imitation. Innovation is not possible unless you do things differently, unless you rewrite the rules.
If were to do everything the same as you (which includes following the same interpretation of the rules as you and implementing them in the same way as you) then I would be no better than you, and I'm afraid that your best is simply not good enough.
In order to be better I have to start by being different, but all you can do is attack me for being different without noticing that my results are superior to yours.
You argument is that because I am breaking your precious rules then my code must be crap. What you fail to understand is that if I can produce superior results by ignoring your precious rules then it is your rules which are crap.
If the only bad thing that happens if I ignore one of your precious rules is that I offend your delicate sensibilities, then all I can say is Aw Diddums!
Those programmers who insist on following rules blindly without understanding the origin and purpose of those rules, the circumstances in which those rules are most appropriate, and how to implement them effectively, are in great danger of becoming nothing more than Cargo Cult Programmers whose level of competence needs to be seriously questioned. Follow the teachings of such people at your peril!
Here endeth the lesson. Don't applaud, just throw money.