Tony Marston's Blog About software development, PHP and OOP

Pop Quiz on OOP

Posted on 9th May 2020 by Tony Marston

Amended on 4th February 2023

Introduction
Questions
Answers
Amendment History
Comments
Comments on reddit comments

Introduction

In the world of computer programming in general, and object-oriented programming in particular, there are numerous concepts, terms and principles being banded around which can mean different things to different people, which may be implemented in numerous different ways, and where each different implementation has its own set of pros and cons. Some programmers follow these concepts, terms and principles in a purely dogmatic fashion while others have a more pragmatic approach. I have put this little impromptu quiz together so that you may identify whether you are a dogmatist or a pragmatist.


Questions

  1. Is computer programming:
    1. A science that anyone can do if they follow a predefined formula?
    2. An art in which they can only excel if they have the necessary talent to begin with?
    answer
  2. What should be the aim of a computer programmer? Is it:
    1. To impress other developers with the purity and complexity of their solution?
    2. To provide cost-effective solutions to the person who pays their wages?
    answer
  3. What is the best way to write a program? Is it:
    1. To achieve simple tasks using complex code?
    2. To achieve complex tasks using simple code?
    answer
  4. What is the best way to use Design Patterns? Is it:
    1. Make a list of the "correct", "popular" or "fashionable" patterns, then write the code to implement as many as possible?
    2. Write code that works, then refactor it to see what patterns emerge of their own accord?
    answer
  5. What are the features that a language is supposed to support before it can call itself "Object Oriented"?
    1. The use of value objects, immutable objects, namespaces, strong typing, annotations, interfaces, lambdas, generators, traits, mixins, et cetera?
    2. Is it encapsulation, inheritance and polymorphism?
    answer
  6. What is the difference between Procedural and Object Oriented programming?
    1. Code is procedural when it is all about how the goal should be achieved instead of what the goal is. A method is procedural if the name is centered around a verb, but OO if it is centered around a noun.
    2. They are both the same except that one supports encapsulation, inheritance and polymorphism while the other does not.
    answer
  7. What is OOP?
    1. Object-oriented programming involves the creation of a community of objects which model the interactions and responsibilities we see in agents of purpose in the real world. Objects should be designed to solve problems like we solve them in every day life.
    2. 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.
    answer
  8. What is the meaning of "Encapsulation"?
    1. Encapsulation is a technique for minimizing interdependencies among separately-written modules by defining strict external interfaces. The external interface of a module serves as a contract between the module and its clients, and thus between the designer of the module and other designers. ... A module is encapsulated if clients are restricted by the definition of the programming language to access the module only via its defined external interface. ("Encapsulation and Inheritance in Object-Oriented Programming Languages" : OOPSLA 86 proceedings)
    2. 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.
    answer
  9. What "things" should be turned into classes?
    1. Each "real world" object should have its own class even if that object is comprised of multiple entities.
    2. Each class should represent a single entity in the business domain with its data defined as class properties and operations defined as class methods. An "entity" is something which is of interest to your application.
    answer
  10. Does encapsulation mean data hiding?
    1. Yes.
    2. No.
    answer
  11. What is the meaning of "Inheritance"?
    1. It is the mechanism of basing an object or class upon another class, retaining similar implementation. Also defined as deriving new classes (sub classes) from existing ones such as super class or base class and then forming them into a hierarchy of classes..
    2. It is a mechanism where you can to derive a class from another class for a hierarchy of classes that share a set of attributes and methods.
    3. The mechanism by which an existing class, the superclass, can be extended to form a new subclass. All the properties and methods in the superclass are automatically inherited (shared) by the subclass, but these may be overridden in the subclass. The subclass may even define new properties and new methods of its own.
    answer
  12. What is the best way to use inheritance?
    1. To inherit from one concrete class to create a different concrete class.
    2. To inherit from one class after another to form deep inheritance hierarchies.
    3. To only ever inherit from an abstract class.
    answer
  13. How much inheritance should you aim to achieve?
    1. Have a large number of small classes from which you inherit a small number of times.
    2. Have a small number of large classes from which you inherit a large number of times.
    answer
  14. What is the meaning of "Polymorphism"?
    1. Polymorphism is the ability of an object to take on many forms. The most common use of polymorphism in OOP occurs when a parent class reference is used to refer to a child class object.
    2. Identical (identically-named) operations can behave differently in different contexts. The operations that can be performed on an object make up its interface. They enable you to address operations with the same name in different objects.
    3. Same interface, different implementation. Polymorphism requires that the same method signature be available in more than one class, usually, but not necessarily, through inheritance. This allows each of those classes to have a different implementation for that method, thus allowing the caller of that method to substitute one class for another at runtime. The method call will work, but produce a different result because of the different implementation.
    answer
  15. What is the best way to use polymorphism?
    1. The calling object should have code to identify which class is to be instantiated into an object before calling that method on that object.
    2. Use dependency injection so that the choice of which class to use is made by the preceding object, thus reducing the decision making in the calling object as all it need to is call the method on whatever object was injected into it for that purpose.
    answer
  16. When should you use Dependency Injection?
    1. For every possible dependency even if there is only one object which can be injected.
    2. Only when there is a choice of several dependent objects made possible by polymorphism.
    answer
  17. When designing a database application where should you start?
    1. Design your software first and leave the database design till last.
    2. Design your database first, then design your software to match this design.
    answer
  18. When should you use an Object-Relational Mapper?
    1. Always
    2. Never
    answer
  19. How do you satisfy the requirements of a user transaction (use case)?:
    1. Create new methods which are specific to that use case?
    2. Re-use generic methods which can be defined in an abstract class?
    answer
  20. In the MVC design pattern -
    1. Can a Controller communicate with only one Model?
    2. Can a Controller communicate with more than one Model?
    answer
  21. In the MVC design pattern -
    1. Can a Model be accessed by only one Controller?
    2. Can a Model be accessed by more than one Controller?
    answer
  22. How do you create Controllers for each Model? Do you:
    1. Manually create a new Controller which is specific to that Model?
    2. Re-use an existing Controller which can perform its actions on any Model?
    answer
  23. If you have separate tasks to List/Browse, Create, Read, Update and Delete do you:
    1. Put all these tasks into a single Controller?
    2. Have a separate Controller for each task?
    answer
  24. What is the best way of inserting data into an object, such as from the $_POST array?
    1. Each item of data should have its own argument in the method call, as in:
      $result = $dbobject->update($_POST['userID'],
                                  $_POST['email'],
                                  $_POST['firstname'],
                                  $_POST['lastname'],
                                  $_POST['address1'],
                                  $_POST['address2'],
                                  $_POST['city'],
                                  $_POST['province'],
                                  $_POST['country'],
                                  );
      
    2. Each item of data should have its own setter method, as in:
      <?php 
      $dbobject = new Person(); 
      $dbobject->setUserID    ( $_POST['userID'   ); 
      $dbobject->setEmail     ( $_POST['email'    ); 
      $dbobject->setFirstname ( $_POST['firstname'); 
      $dbobject->setLastname  ( $_POST['lastname' ); 
      $dbobject->setAddress1  ( $_POST['address1' ); 
      $dbobject->setAddress2  ( $_POST['address2' ); 
      $dbobject->setCity      ( $_POST['city'     ); 
      $dbobject->setProvince  ( $_POST['province' ); 
      $dbobject->setCountry   ( $_POST['country'  ); 
      
      if ($dbobject->updatePerson($db) !== true) { 
          // do error handling 
      } 
      ?> 
      
    3. Pass the entire $_POST array as a single argument in the method call, as in:
      <?php 
      $table_id = 'whatever';
      .....
      require_once 'classes/$table_id.class.inc';  // $table_id is provided by the previous script
      $dbobject = new $table_id;
      $result = $dbobject->updateRecord($_POST);
      if ($dbobject->errors) {
          // do error handling 
      }
      ?> 
      
    answer
  25. What is the best way of getting data out of an object?
    1. Each item of data should have its own getter method, as in:
      $User_d    = $dbobject->getUserID(); 
      $Email     = $dbobject->getEmail(); 
      $Firstname = $dbobject->getFirstname(); 
      $Lastname  = $dbobject->getLastname(); 
      $Address1  = $dbobject->getAddress1(); 
      $Address2  = $dbobject->getAddress2(); 
      $City      = $dbobject->getCity(); 
      $Province  = $dbobject->getProvince(); 
      $Country   = $dbobject->getCountry(); 
      
      if ($dbobject->updatePerson($db) !== true) { 
          // do error handling 
      } 
      ?> 
      
    2. Extract all the data in a single array, as in:
      $fieldarray = $dbobject->getFieldArray(); 
      
    answer
  26. When and where should data be validated?
    1. Before it is inserted into the Model?
    2. Within the Model itself
    answer
  27. How many rows of data should an object be allowed to deal with?
    1. Only a single row.
    2. As many rows as is necessary.
    answer
  28. In a framework what is the best pattern or principle for implementing Inversion of Control (IoC)?
    1. The Dependency Inversion Principle
    2. The Template Method Pattern
    answer
  29. In order to insert or update a record in the database using data submitted from an web page what methods do you have?
    1. A separate method for each step, as in:
      $object->load($_POST);
      $object->validate();
      $object->store();
      
    2. A single method which carries out all the steps, as in:
      $object->insertRecord($_POST);
      OR
      $object->updateRecord($_POST);
      
    answer
  30. What type of programmer are you?
    1. A dogmatist who will blindly and without question follow whatever rules you have been given and assume that the results will be correct.
    2. A pragmatist who will use your skill to achieve the most cost-effective result, and will only follow those rules which make sense or provide a measurable benefit.
    answer

Answers

  1. (b) is the correct answer.

    Computer programming is an art, not a science, for which you need talent to be any good. A person without talent cannot read a book on playing a musical instrument and become a musician, or read a book of recipes and become a chef, or read a book on how to use a hammer and chisel and become a sculptor. If you don't have the necessary talent to begin with you will never be anything more than a "dabbler" instead of being a "master".

    return to question
  2. (b) is the correct answer.

    A programmer who cannot produce cost-effective software and justify his salary will be a liability and not an asset, and will eventually be found out and fired.

    return to question
  3. (b) is the correct answer.

    You should always follow the KISS principle and not the KICK principle.

    return to question
  4. (b) is the correct answer.

    Erich Gamma himself, one of the Gang of Four, said the following in an interview:

    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.

    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.

    A lot of the patterns are about extensibility and reusability. When you really need extensibility, then patterns provide you with a way to achieve it and this is cool. But when you don't need it, you should keep your design simple and not add unnecessary levels of indirection.

    If he says that you should use patterns sparingly, then who are you to argue?

    return to question
  5. (b) is the correct answer.

    Alan Kay, the man who invented the term, said that any language which did not support these three concepts had no right to call itself "object oriented". In his paper called Why C++ is not just an Object Oriented Programming Language the author Bjarne Stroustrup said the following:

    A language or technique is object-oriented if and only if it directly supports:
    1. Abstraction - providing some form of classes and objects.
    2. Inheritance - providing the ability to build new abstractions out of existing ones.
    3. Runtime polymorphism - providing some form of runtime binding.

    So if those two say that then who are you to argue?

    return to question
  6. (b) is the correct answer.

    Both paradigms are designed around the idea of writing imperative statements which are executed in a linear fashion, but OOP also supports the concepts of encapsulation, inheritance and polymorphism. The commands are the same, it is only the way in which they are packaged which is different.

    return to question
  7. (b) is the correct answer.

    I have seen far too many descriptions of OOP which fail to identify what OOP has which other paradigms do not, and what advantages these differences have to offer. Any description which fails to identify encapsulation, inheritance and polymorphism which can be used to increase the amount of reusable code is therefore not painting a clear picture. Explanations should be simple and concise, and should not use 10 dollar words to explain 10 cent concepts.

    return to question
  8. (b) is the correct answer.

    Explanations which are not simple, concise and precise are confusing to the novice developer. The use of clever words which can be interpreted in several different ways often leads to different and sometimes conflicting descriptions. If an error creeps in then that error can grow in subsequent descriptions.

    Before you can encapsulate something you first have to identify that "thing". It should be an entity which will be of interest to your application, something which has data and operations which can manipulate that data. You then create a class for that entity, define all its data as properties (also known as attributes) and its operations as methods. Note that ALL the data and ALL the operations for an entity SHOULD be placed in the same class. If you split the class into numerous smaller classes then you will be reducing cohesion and increasing coupling.

    return to question
  9. (b) is the correct answer.

    Modelling the "real world" is not a clever idea unless you are writing software which communicates directly with objects in the real world. When writing a database application which deals with entities such as "Customer" and "Product" you will not be communicating with real customers or real products, just with the data about those entities which is held in a database. A database is a collection of things called "tables", so there will be a "Customer" table and a "Product" table. Designing code which communicates directly with the relevant objects would always be my first choice.

    The answer to question 8 stated that you first need to identify all the entities which will be of interest to your application and then create a separate class for each entity. It is possible that you may recognise an entity in the real world which, after the process of data normalisation, results in more than one table in the database, such as the concept of an ORDER as shown in the following diagram:

    A compound "order" object

    order-object (2K)

    It would be a great mistake to create a single class to encapsulate the concept of an order for the simple reason that this is a compound entity which results in multiple tables in the database. As each table in the database can be regarded as being a separate entity in its own right then creating a compound/composite class which is responsible for multiple tables would break the Single Responsibility Principle. It would also create the following problems:

    Note that there is no communication between the database entity and the "real world" entity, so designing software which appears to communicate with an object with which there is no actual communication, then being forced to write additional code (such as an Object-Relational Mapper) to deal with the translation from a theoretical entity to an actual entity (or entities), strikes me as being totally illogical.

    return to question
  10. (b) is the correct answer.

    The biggest error with most descriptions of encapsulation is that far too many people seem to think that it must enforce visibility restrictions on the data. This is wrong! ENCAPSULATION WAS NEVER MEANT TO MEAN DATA HIDING! If you don't believe me take a look at:

    return to question
  11. While (a) and (b) are technically correct, option (c) is a more complete answer.

    If you extend ClassA into ClassB then ClassB ends up as a combination of everything in ClassA plus whatever is defined in ClassB. ClassB can be used to either override properties and methods in ClassA or to define new properties and methods of its own.

    When you inherit from a class (abstract or concrete) which contains one or more non-abstract methods you use the extends keyword. This is called implementation inheritance.

    When you inherit from an interface (an abstract class which contains nothing but abstract methods) you use the implements keyword. This is called interface inheritance.

    Note that the creators of these two concepts got their knickers in a twist as the implements keyword does NOT give you implementation inheritance. Go figure!

    return to question
  12. (c) is the correct answer.

    Options (a) and (b) are often overused which can cause problems for which the solution is the Composite Reuse Principle which is commonly referred to as favour composition over inheritance. Refusing to use inheritance altogether just because some usages may cause problems strikes me as being an over-reaction, like amputating a leg just because the toenails are too long.

    I never inherit from one concrete class to form another concrete class, and I never create deep inheritance hierarchies, so I automatically avoid the problems which other people encounter.

    In his article Object Composition vs. Inheritance the author Paul John Rajlich wrote 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.
    ....
    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.

    The same idea was also mentioned in the Gang of Four book where, in the section titled Inheritance versus Composition, it says the following:

    Implementation dependencies can cause problems when you are trying to reuse a subclass. Should any aspect of the inherited implementation not be appropriate for new problem domains, the parent class must be rewritten or replaced by something more appropriate. This dependency limits flexibility and ultimately reusability. One cure for this is to inherit only from abstract classes, since they usually provide little or no implementation.

    That last statement inherit only from abstract classes since they usually provide little or no implementation is contradicted later on in the book when it describes the Template Method Pattern which uses a mixture of unvarying methods (with implementations) and variable methods (without implementations) in an abstract class. That chapter specifically states that Template methods are a fundamental technique for code reuse, which means that the more template methods you have the more implementations you have. In my own framework every method called by a Controller on a Model is defined within the same abstract class, so that adds up to a lot of methods.

    return to question
  13. While (a) is achieved by most programmers (b) is more desirable.

    Having large amounts of code which are reused in large numbers of places provides much more reusability than small amounts of code which are reused in small numbers of places.

    In my framework every method which is called by a Controller on a Model is an instance of a Template Method, which explains why my abstract table class is so large. That single abstract class is inherited by every one of my Model classes (I currently have over 400) so that produces a HUGE amount of reusability. That's much better than having 100 abstract classes that are only inherited 4 times each.

    return to question
  14. (c) is the more complete and accurate answer.

    Some people assume that polymorphism can only exist through inheritance, but this is not the case. It is perfectly possible for method signatures and their implementations to be hard-coded into a class without any sort of inheritance. For polymorphism to exist all you need is the same method signature to be defined in more than one concrete class. This is usually achieved through inheritance, but need not be.

    You must have polymorphism before you can use dependency injection, so it helps to produce reusable code which is the major objective of OOP.

    return to question
  15. (b) is the correct answer.

    The fact that polymorphism provides identically-named operations which behave differently in different contexts does not really identify how you can take advantage of this situation. This is where Dependency Injection comes into play as it describes a mechanism whereby objects which have the same method signature can be swapped around at runtime to produce different results.

    For example, in my framework every concrete table class has an insertRecord() method which is inherited from the abstract table class. This allows data to be inserted into that table provided that it passes all the validation rules. I have a Controller which calls this method, but instead of having the table name hard-coded into each Controller (which would require multiple Controllers) I inject it from above. This means that instead of:

    $dbobject = new Customer;
    $fieldarray = $dbobject->insertRecord($_POST);
    

    I can have:

    $table_id = 'whatever';
    .....
    $dbobject = new $table_id;
    $fieldarray = $dbobject->insertRecord($_POST);
    

    Where the value of $table_id can be set to any one of my 400 concrete table classes.

    Let me emphasis this point. This technique means that instead of having a separate Controller to handle the inserts for each of my 400 table classes I have a single Controller which can handle the inserts for ANY of those 400 table classes. Is that a good example of reusability or what?

    return to question
  16. (b) is the correct answer.

    Option (a) would be a waste of time if you did not have a choice of different objects to inject as without that choice you would be providing a mechanism that would never be used, thus violating YAGNI.

    If you read what Robert C. Martin wrote in his article The Dependency Inversion Principle (PDF) you will see where he gives an example of a "Copy" program to show how this principle can be used. This program is used to copy data from one device to another, but where the actual implementation of the "read" and "write" methods can vary for each device. This means that the "Copy" program itself would need to be changed should any implementation change for any device, or even to add a completely new device.

    The solution proposed by Uncle Bob was to create a separate class/object for each device, each with its own implementations for the "read" and "write" methods, and to inject the relevant device objects into the "Copy" program so that all it need to is call the $deviceIN->read() and $deviceOUT->write() methods to complete its assigned task. This means that you could create objects for devices and inject them into the "Copy" program without ever having to change that program.

    This technique is called Dependency Injection because the "Copy" program is dependent on the device objects to complete its assigned task, and these objects are instantiated externally and then injected instead of being instantiated internally.

    Note here that there are several different device objects having the "read" and "write" methods (thus producing polymorphism) which means that there is a choice of different objects which can be injected at runtime. If you do not have a choice of objects to inject then implementing this technique which deals with a choice of objects would be a waste of time.

    For a more detailed discussion on this topic I invite you to read Dependency Injection is EVIL.

    return to question
  17. (b) is the correct answer.

    Designing software to deal with theoretical entities only to discover later that in reality these entities are totally different has always seemed like a stupid idea to me. When I first started to write database applications using poorly structured code I encountered problem after problem. The solution, as taught to me in Jackson Structured Programming, was to design a program structure which was built around the database structure, thus eliminating the problems instead of writing code to work around them. This is a philosophy which I have followed ever since, and I will not change it for anyone. This is why I always start by designing a properly normalised database, then use each table's structure to create a class for that table. This is a standard process that I use for each table, so I have managed to automate it by building a Data Dictionary into which I can import each table's structure at the press of a button, then export that structure into a class file at the press of another button.

    Being able to create fully-functioning table classes by pressing a few buttons instead of writing reams of code seems like a good idea to me, especially when you create large applications with hundreds of table classes.

    return to question
  18. (b) is the correct answer.

    Option (a) is used only by retards who don't understand SQL. Someone writing a database application who doesn't understand SQL is just as useless as someone writing a web application who doesn't understand HTML. If you don't understand how the objects with which your software is communicating actually work then how can you possibly believe that you can write cost-effective software?

    For a more detailed discussion on this topic I invite you to read Object-Relational Mappers are EVIL.

    return to question
  19. (b) is the correct answer.

    Option (a) is used only by those who don't know any better.

    Each use case (user transaction or task) is designed to perform a function for the user, such as "Create Product", "Create Customer", "Create Invoice" and "Pay Invoice". Programmers who have been badly taught create a separate method for each use case and end up with a list of methods such as the following:

    This method has so-o-o many disadvantages:

    Option (b) only becomes apparent when you realise that every use case, regardless of what function it carries out for the user, always follows the same pattern: it performs one or more CRUD operations on one or more tables, and may process business rules during either or both of the input and output phases. In my framework each concrete table class inherits standard methods to perform those CRUD operations from a single abstract table class. I add the functions "Create Product", "Create Customer", "Create Invoice" and "Pay Invoice" to my menu database as a TASK which identifies which component script in the file system will perform that task, and I add each task to a MENU which is used to show the user which functions he is allowed to perform. When the user selects one of those menu options it runs the nominated component script which then calls the necessary CRUD operations on the specified table.

    Each method that the Controller calls on a Model is available in every Model by virtue of the fact that it is defined in the abstract table class which is inherited by every concrete table class. Each method is an instance of the Template Method Pattern which contains a mixture of invariant and variable methods. Standard boilerplate code is defined in the invariant methods in the superclass while the variable hook methods can have their implementations defined within each individual subclass.

    It is a feature of my framework that each Controller script performs its operations on an unspecified Model and can therefore be used with ANY Model. At runtime the identity of the Model to be used is specified in the component script before it hands over control to a particular Controller. This is my form of dependency injection which is only possible because I have so much polymorphism available due to the fact that every concrete table class inherits from the same abstract table class. Below is an example of the "traditional" way compared with the heretical "Tony Marston" way.

    traditional effect on the database the Tony Marston way
    createProduct() insert a record into the PRODUCT table
    $table_id = 'product';
    ....
    require "classes/$table_id.class.inc";
    $dbobject = new $table_id;
    $result = $dbobject->insertRecord($_POST);
    
    createCustomer() insert a record into the CUSTOMER table
    $table_id = 'customer';
    ....
    require "classes/$table_id.class.inc";
    $dbobject = new $table_id;
    $result = $dbobject->insertRecord($_POST);
    
    createInvoice() insert a record into the INVOICE table
    $table_id = 'invoice';
    ....
    require "classes/$table_id.class.inc";
    $dbobject = new $table_id;
    $result = $dbobject->insertRecord($_POST);
    
    payInvoice() insert a record into the PAYMENT table
    $table_id = 'payment';
    ....
    require "classes/$table_id.class.inc";
    $dbobject = new $table_id;
    $result = $dbobject->insertRecord($_POST);
    

    My version of the payInvoice() method does away with those stupid arguments I have seen on the interweb where some people say it should be $invoice->pay() while others say it should be $pay->invoice(). In my simplified world the paying of an invoice results in the INSERT of a record into the PAYMENT table which means that I can use the generic insertRecord() method on the PAYMENT object. It's not rocket science!

    As you should be able to see the "traditional" way uses large amounts of unique and therefore unsharable code whereas my "heretical" way uses non-unique sharable code in each Controller that can be used with any Model. This is only possible because of the way I have implemented inheritance to provide maximum polymorphism which then enables the most efficient use of dependency injection. My use of the Template Method Pattern gives each Model instant access to large amounts of standard boilerplate code which can be easily augmented using the numerous hook methods.

    return to question
  20. (b) is the correct answer.

    Too many people think that (a) is the rule because they have not seen any examples which show otherwise.

    When you have built as many user transactions with screens that I have (and I have built thousands) you should notice that each screen can be broken down into different zones or areas. Some of these zones can be filled in by the framework while others are supplied by the application. While some screens deal only with a single application component there may be others which deal with a hierarchy of components where each component has a separate object in the Controller and a separate zone on the screen. This is what I was used to in the last language which I used before switching to PHP, so I saw no reason why I should not continue with that practice.

    This means, for example, that if you have two tables in a parent-child relationship, such as CUSTOMER and ORDER, you may wish to have a screen which shows a single CUSTOMER in the top/parent zone and a list of ORDERS for that particular CUSTOMER in the bottom/child zone. I have found it much easier to deal with those two zones by having a separate Model for each zone instead of having a single Model for multiple zones.

    In my library of Transaction Patterns I have expanded this idea to allow some screens to have three or even four application zones.

    return to question
  21. (b) is the correct answer.

    Too many people think that (a) is the rule because they have not seen any examples which show otherwise.

    I have seen too many code samples on the interweb which follow the practice of creating just one Controller for each Model to handle all the possible use cases which are available for that Model. This is a practice which was common in my COBOL days, but after constructing my first framework I began to notice its weaknesses, so I switched to the practice of creating a separate Controller for each use case. This is documented in Component Design - Large and Complex vs. Small and Simple. By having a separate Controller for each use case I avoid the problem of having large and complex Controllers which handle multiple use cases. I can also add new use cases to an existing Model without having to change any existing Controllers. This means that a Model can be accessed by any number of Controllers.

    By use case I mean a single unit of work, sometimes called a user transaction or task, which can be selected from a menu button or navigation button. The most common set of forms that a database table may require is known as a Forms Family and while some people seem to think that the whole family is a single use case I have found benefits in treating each member of that family as a separate use case in its own right. Each task has a different structure, behaviour and content, and trying to deal with a single Controller which handles all possible combinations of those three characteristics can be quite challenging. That is why as long ago as the mid-1980s I decided to split a large program with multiple responsibilities into a series of smaller programs each with a single responsibility. Each of these programs has its own entry in the MENU database and its own component script, and as the behaviour of each program is centered around which combination of the CRUD operations it perform on its database table I have been able to code each Controller so that it performs its operations on a table whose identity is supplied at run-time through my implementation of Dependency Injection. This means that I can have a single Model accessed by as many Controllers as I see fit, and I can add new use cases for a Model, each with its own Controller, without having to amend any existing Controller.

    return to question
  22. (b) is the correct answer.

    Option (a) is chosen by those who do not know how to create reusable Controllers that can work with any Model.

    My decades of prior experience with designing and building database applications in non-OO languages taught me several important points:

    The very first Controller that I created had the table name hard-coded into it. When I copied that Controller to do exactly the same thing on another table I discovered that the only thing which I had to change was the table name, so I asked myself the question If the only difference between these two Controllers is the table name, is there a mechanism which allows me to pass that name in as a variable instead of a literal? The answer is YES. Instead of being forced to write the following code:

    require_once "classes/product.class.inc";
    $dbobject = new product;
    $fieldarray = $dbobject->insertRecord($_POST);
    
    I discovered that I could write the following instead.
    $table_id = 'product';
    .....
    require_once "classes/$table_id.class.inc";
    $dbobject = new $table_id;
    $fieldarray = $dbobject->insertRecord($_POST);
    

    The value for $table_id is now defined in a separate component script which resembles the following:

    <?php
    $table_id = "product";                      // identify the Model
    $screen   = 'product.detail.screen.inc';    // identify the View
    require 'std.add1.inc';                     // activate the Controller
    ?>
    

    Note here that none of my Controllers contains any hard-coded table or column names. This means that each Controller can call its methods on any Model regardless of what columns it contains, and each Model can be accessed by any Controller. While I started with just a small set of reusable Controllers this list has expanded into a library of 40, one for each of my Transaction Patterns. If I have 40 Controllers and 450 table classes that means that I can deal with 40 x 450 = 18,000 (yes, EIGHTEEN THOUSAND) combinations.

    Many years later I discovered that what I was doing was a form of Dependency Injection. I found it very strange that no-one else had used DI in this manner and was capable of having hundreds of alternatives for use as a dependent object.

    return to question
  23. (b) is the correct answer.

    I was taught to use option (a) when I was a junior programmer, but I quickly learned its limitations and its weaknesses. Having a Controller which can perform many tasks means that it may have method calls which are relevant to only one particular task, so ensuring that the right method calls are made in the correct sequence requires tricky code, and the need for tricky code can lead to mistakes. Been there, done that, got the t-shirt. Things get more complicated when different tasks within the same controller need different screens. Then add into the mix the requirement for each task to be the subject of role-based access control so that certain tasks can only be accessed by certain users and what started as a can of worms is now a bucket of worms.

    Instead of having a large, complex program that can do lots of things it may be better to split it into a series of smaller and simpler programs which do one thing each. This idea is explored in greater detail in Component Design - Large and Complex vs. Small and Simple. It was years later that I discovered that my approach was following the Single Responsibility Principle in that I had created smaller components which were responsible for only a single task each instead of having a large component which was responsible for several tasks.

    return to question
  24. (c) is the correct answer.

    Options (a) and (b) are examples of tight coupling because changes to the number of columns in that table will cause the method signature to change, thus causing a ripple effect which necessitates corresponding changes to other modules. You should also notice that in each of these two samples both the table and column names are hard-coded, which means that this code is so tightly coupled it can only be used with one particular Model.

    Option (c) avoids these issues completely so is therefore an example of loose coupling. No column names are specified, which means that the number of columns can be altered at will without having to change any method signatures. You should also notice that because the name of the database table is not hard-coded in the Controller it can be used with any table in the database as every method that the Controller calls is always available in every Model by virtue of the fact that every one of those methods is defined in the abstract table class which is inherited by every concrete table class.

    Note that the contents of fieldarray will be validated by standard code in the abstract table class in order to ensure that the SQL query which will be generated will not fail. If the validation fails the insert will be skipped and all error messages will be passed back to the user. Any columns which are not part of the table's structure will be ignored, which means that they can be used on a call to insertRecord() on another table.

    return to question
  25. (b) is the correct answer

    Option (a) produces tight coupling which should be avoided. Using individual getters to extract column values one by one is just the same as using setters to insert column values one by one.

    By having all an object's data made available in a single $fieldarray variable it makes life so much easier. The Controller does not need to know the names of the columns whose data is being inserted into or extracted from the Model. Neither does the View which does nothing but iterate through the array and insert every element into an XML document before it is transformed into HTML output using an XSL stylesheet.

    As the contents of $fieldarray is totally dynamic it may contain only a subset of the columns which are part of that table's structure, or it may even contain columns from other sources such as from JOINs to other tables in the sql SELECT statement.

    return to question
  26. (b) is the correct answer.

    Option (a) is chosen by novices as they are under the impression that a Model should never contain invalid data. This is bunkum. The only golden rule, which I learned in the 20 years of programming before I switched to an OO language, is that the data MUST be validated BEFORE the SQL query is constructed and executed otherwise invalid data will cause the query to fail, and this will cause the program to terminate immediately.

    This means that it is perfectly acceptable to insert data into an object and have that object validate the data internally, and only when that data passes all its validation checks should it update the database. Any validation failures should result in the database update being skipped and any error messages being sent back to the user so that he/she can correct his/her mistakes.

    Data validation is performed in two separate phases. The first is called primary validation which checks that the input data does not violate any of the rules contained in the $fieldspec array. The second phase is called secondary validation which has to be handled by custom code in any of the relevant hook methods.

    The rules of both the 3-Tier Architecture and Model-View-Controller dictate that ALL business rules (which includes data validation) be performed within the Business/Domain/Model layer, which then prohibits having business rules in any of the other layers.

    return to question
  27. (b) is the correct answer.

    Option (a) is chosen by novices whose use of getters and setters automatically ties them to one set of fields at a time. Option (b) has been allowed in Robert C. Martin's Table Module pattern, so if he says it's OK then who are you to argue.

    By using a single $fieldarray variable to hold all the data for an object I can allow this to be an associative array to contain the data for a single row, or allow it to be an indexed array where each index number contains an associative array for that row's data.

    return to question
  28. (b) is the correct answer

    The definition found in wikipedia states that it inverts the flow of control in a manner described as the "Hollywood Principle" (don't call us, we'll call you). This is the difference between using a library and a framework - you have to write code to call a library routine, whereas a framework has the means to call the code which you write. The best design pattern to achieve this is the Template Method Pattern which is a fundamental feature of my framework.

    Option (a) is wrong because the Dependency Inversion Principle has nothing to do with inverting the flow of control, it merely changes the place where a dependent object is instantiated.

    return to question
  29. (b) is the correct answer.

    Option (a) provides the opportunity to call these methods out of sequence which could then cause the generated SQL query to be rejected.

    If those three methods have to be called in that sequence then instead of calling them one at a time you can create a single super-method which will call them for you. This will guarantee that the sub-methods will always be called in the correct sequence. If there is any condition checking between one step and another then this can be performed in the super-method. Any changes to these conditions can then be made in the super-method so that they are instantly available to all users of that method.

    Those of you who are still awake and on the ball should instantly recognise that this type of super-method is an ideal candidate for conversion into a Template Method which defines the skeleton of an operation in terms of a number of high-level steps.

    return to question
  30. If you have answered with mostly (a)s then I'm afraid you are a dogmatist who only knows what he has been taught. You obviously have not had enough experience to learn anything useful, such as what you have been taught is not the only way and therefore may not be the best way. You are blind to alternative solutions because, when faced with a choice, you don't have the mental capacity to weigh one choice against another in order to determine which one is best for your circumstances. You are unable to evaluate when the words use when appropriate apply to your current circumstances or not, so you take the path of least resistance and substitute use always instead. By following the rules without question even in those circumstances where they may not be appropriate you are nothing more than a cargo cult programmer. You will always be a code monkey and never a code meister.

    If you have answered with mostly (b)s, or (c)s when available, then you are a pragmatist. You know which solutions produce the best results and which alternatives to avoid. Instead of following rules blindly you question them, and if you don't like the answer you ignore them as you know that they will be adding to your problems instead of reducing them. Dogmatists will dislike your free spirit, they will call you a maverick, a non-conformist or, even worse, a heretic for failing to follow the accepted path. However, you will have one vital characteristic that your dogmatist colleagues will lack - your ability to produce cost-effective solutions will make you an asset in the eyes of your employer whereas their dogged determination to follow the rules regardless of the results will make them a liability.

    If your answers are split half-and-half then you have to decide whether you are a "glass half full" or "glass half empty" type of person. You have reached a crossroads in your career, so you need to decide whether you follow the path of righteousness with the rest of us pragmatists, or follow the path of wickedness, the path of darkness and despair, so favoured by the dogmatists.

    While it may seem easy to do as you are told and follow the rules, the same styles and the same practices as everyone else around you, especially when you are a junior member of a team of so-called "experts", all you will end up doing is copying their mistakes. As you gain more experience you should be exposed to more ideas, different ideas, some of which may challenge or even contradict what you have been taught so far. You should try to experiment with some of these new ideas and learn for yourself whether they have merit or not.

    Remember that progress is never made by doing things in the same old way, by copying what has been done before. You have to break the mould, throw out the old rules and start afresh. The mantra for a truly pragmatic programmer should be "innovate, don't imitate".

    return to question

Comments on reddit comments

A reference to this article appeared in this reddit post. You will notice that none of the people who commented actually provided any answers, they just followed their normal practice of insulting me left, right and center. Is there anyone out there who is capable of intelligent debate?

If you regard this article as a series of interview questions then I'm afraid that all the respondents so far have failed miserably.

Instead of forcing you to read the whole thread I will summarise some of the comments and my responses below.

  1. The first respondent named OdBx wrote Sorry but your first question has two subjective "answers" and then presents one as correct and the other as wrong. Didn't get any further than that. That person clearly hasn't grasped the fact that every article ever written is oriented around the experiences of the author and is therefore subjective. It can only be classed as "objective" if it based on real facts and not influenced by personal beliefs or feelings. This article was meant to sort out the pragmatists from the dogmatists. Answer (a) is what I have seen consistently promoted as the "right" way, the "only" way, but my experience has taught me that there is always more than one way and each alternative has its own set of pros and cons. Where I have offered pragmatic answers which are alternatives to the traditional ones which are favoured by dogmatists I have tried to explain why my answers have more pros and fewer cons. If you dismiss my answers as pure heresy simply because they challenge the accepted dogma then you are heading down the road of becoming nothing more than a Cargo Cult Programmer who follows rules blindly without understanding them. In my book the dogmatic answer is always wrong and the pragmatic answer is always right.
  2. He followed this up by writing Indeed, so why are you saying one answer is correct and the other is wrong? Answer (a) is "wrong" because it does not provide as much reusable code as my alternative, and as the whole objective of OOP is supposed to be the creation of as much reusable code as possible then answer (a) has clearly failed. It may satisfy a dogmatist, but it is clearly the wrong answer for a pragmatist.
  3. He then wrote Subjective answers cannot be "right" or "wrong". which is incorrect. Those answers are subject to my own personal experience, and in my personal experience answer (a) is "wrong" simply because it is NOT the answer that, as a pragmatist, I would choose.
  4. He then wrote The question is about what computer science is. It has absolutely no bearing on reusability of anything. which indicates that he did not read the question. I did not ask "What is computer science" I asked "Is computer programming a science or an art?" I personally consider it to be an art as without talent you will never become proficient, just as a person without any musical talent will never become a musician regardless of how many books he reads.
  5. He then began to question my use of the word "talent". He first wrote Are you implying that somebody born with the right talent can pop out their mum's vagina and start programming flawlessly from birth? followed by So, people have to learn programming regardless of any pre-existing "talent" then, yes? Glad you agree. Now can you quantify what "talent" is? If I have to explain the meaning of the word "talent" to someone then it is quite obvious, to me at least, that they don't have any.
  6. He then wrote You're not challenging anything. You're asserting subjectivity as fact. followed by You made an assertive statement about a subjective opinion. This person clearly does not understand what assertive actually means. A simple lookup on google came up with the following definition:
    Being assertive is a core communication skill. Being assertive means that you express yourself effectively and stand up for your point of view, while also respecting the rights and beliefs of others.
    Here is a definition for subjectivity:
    the quality of being based on or influenced by personal feelings, tastes, or opinions.
    Here is a definition for fact:
    something that is known to have happened or to exist, especially something for which proof exists, or about which there is information.
    Yes, I am being assertive, but why shouldn't I be? Yes, my preferred answers are subjective, but that is because they are the product of decades of personal experience. Yes, I express these opinions as facts simply because I have employed them for over 15 years and they have proven to be more effective than their dogmatic counterparts. They are not wild theories which have not yet been put into practice, they have been practiced for over 15 years and have proven to produce results which are more cost-effective than anything else I have seen on the internet.
  7. His next statement was The question wasn't about OOP. And didn't present it as an opinion. You stated it as an objective fact. Which it is not. It may not have been about OOP in particular, but it is an important question nevertheless. If you believe that computer programming is a science which can be broken down into a set of rules which can be followed by absolutely anybody in a dogmatic fashion regardless of talent then in my personal experience you are barking up the wrong tree. Ever since I started programming in the 1970s every single piece of source code ever written contained the name if its programmer as the author. This means that each computer program is a work of authorship which is defined as:
    The state or fact of being the writer of a book, article, or document, or the creator of a work of art.
    A work of authorship is a work of art which can be protected under the laws of copyright. That is a fact. When writing a book an author must use words that are available in the dictionary and string them together using the rules of grammar before he can produce something which his intended audience will be willing to read. However, the use of dictionary and grammar on their own will not guarantee a best seller, the author must have a talent for writing before that can happen. The job of a computer programmer is to take an instruction manual that a human can read and convert it into instructions that a computer can read. In this case the "dictionary" is the list of statements, instructions or constructs which the programming language provides, and the "grammar" is how you can group certain instructions together in order to achieve certain tasks, such as sending data to or receiving data from a web browser, or sending data to or receiving data from a database.

    Just as the author of a book requires more than following a dictionary and the rules of grammar to write a best seller, the author of a computer program requires more than following a dictionary and the rules of grammar to write a successful program. In this case "successful" is judged to be a cost-effective solution in the eyes of the person who pays the programmer's wages. As well as providing a reliable and effective solution which the computer can execute it is much more important to provide source code which can be easily read, understood and maintained by others. There are many different thoughts on how source code can be structured in order to make it readable, but every programmer and his dog has a totally different opinion on what this structure should be. Dogmatists think that it is possible to provide a single set of rules which, if followed by the letter and without question, will always result in perfection. Pragmatists know otherwise. That is not just my opinion, it is shared by Jeff Atwood in his article Level 5 means never having to say you're sorry.

  8. His next statement was There are differences in opinion which cannot be stated as fact. I disagree. The internet is full of articles which state the author's opinion as fact. Take a look at the following examples: In neither of these articles does the author state "this is just my opinion" therefore their viewpoints come across as a statement of fact, new "rules" which should be followed by the masses. If you read these articles you will see that they totally contradict each other - one says the constructor should be empty while the other says it should be used to fill the object with valid data. So which one is right? Neither, in my opinion. The only genuine rule regarding a constructor is that it should leave the object in a condition in which it can respond to subsequent calls on any of its public methods. This means that you can put whatever code you like into a constructor provided that it leaves the object in a callable condition. All other "rules" are pure fabrications or personal preferences and can therefore be safely dismissed as being not worth the toilet paper on which they are written.
  9. Another respondent called equilni wrote this is response to my question #29: your question states nothing on using a controller or loading data or validating it It should be obvious that the object being called is the Model which is being called from a Controller. It should also be obvious that when the user presses the SUBMIT button an an HTML form the data from that form is presented to the Controller in the $_POST array. The object of the exercise is to get the data from the HTML form and insert it into the database. It should also be obvious that this procedure has to be done in stages: Those points should be obvious to every PHP programmer, so I did not think it necessary to have to go into so much detail.

    The point I tried to make was that I have seen many code samples on the internet where those three steps are performed in three separate calls from the Controller on the Model. This leads to the complaint that it is possible to insert some calls between the validate() and store() methods which have the effect of sending unvalidated data to the database. If those three methods always have to be called in that sequence then it is far better to create a new method which calls those methods in that sequence. This is not just a new idea that I dreamed up, it is an example of the Template Method Pattern which was discussed in the following books:

    This is a powerful design pattern that I use extensively in my framework. If you do not understand what it is and how to use it then that is your loss.
  10. Another statement of his was I have no idea what load(), validate() and store() does. OMG! If you cannot understand such basic operations then why are you criticising someone who does? Let me spell it out for you in terms that even a clueless newbie should understand: Is that simple enough for you? Or do I have to explain what code is required in the validate() method and the store() method.
  11. Another respondent called amazingmikeyc asked the following question: It depends on how important it is to have reusable code doesn't it? This means that he does not understand the main purpose of OOP in the first place. The only reason to replace one programming paradigm with another is to invent one which is better. But what is the definition of "better"? The only no-nonsense definition of OOP which I encountered at the start of my journey into this alien world after two decades of working with non-OO languages (COBOL and UNIFACE) went as follows:
    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.
    I read this as saying that this new paradigm had three things - encapsulation, inheritance and polymorphism - which the older paradigms did not, and these could be used to help the programmer write more pieces of code which were reusable. In case you do not understand what "reusable" means let me explain it for you. If you write a piece of code once then reuse it multiple times, possibly hundreds or even thousands of times, it means that when you want to repeat that logic you don't have to spend time in re-writing, re-testing and debugging the same piece of code multiple times. By using code that you don't have to write you automatically make yourself more productive. My entire framework has been geared around this idea, and I have at my disposal much more reusable code than I have ever seen in any rival framework. It has now reached the point where, at the touch of a few buttons, I can create the tasks to maintain the contents of a new database table and run them immediately without having to write a single line of code - no PHP, no HTML, no SQL. All the basic functionality is there, and all the programmer has to do to handle the non-standard business rules is to put the relevant code into the relevant hook methods. Unless you can achieve the same levels of productivity then any criticisms of my methods will have the same effect as a lead balloon. The fact that I have managed to achieve such high levels of productivity by breaking so many of those rules which are favoured by the traditionalists and the dogmatists (those labelled (a) in my pop quiz) just convinces me that those rules are not worth the toilet paper on which they were written. In case you don't understand what that means, it is just a polite way of saying "your rules are crap". Put THAT into your IDE and compile it!
  12. Another respondent called Hall_of_Famer made this statement: your alternative to DI was proven to be ineffective but when I asked him to provide such proof he could not. Besides, I never suggested an alternative to DI, I simply suggested NOT using DI in those circumstances where it was not appropriate - where there is no alternative implementation available for injection - as this would be a violation of YAGNI. I explained where I use DI in my framework to achieve actual benefits as demonstrated by the fact that I have 40 reusable Controllers into which I can inject any of my 450 table classes. This produces 40 x 450 = 18,000 (yes, EIGHTEEN THOUSAND) opportunities for polymorphism, and every competent programmer should be able to tell you that you cannot use DI without polymorphism.

    He then tried to claim that other frameworks could achieve the same thing, but could not offer any proof. He certainly could not point to the existence of any reusable controllers in any framework, such as those which are documented in Transaction Patterns for Web Applications.

  13. The same person later said: I am a better and more productive programmer because almost everyone on this reddit will agree with me but when asked to prove it by taking this challenge he bottled out, as usual.
  14. This is an addition to My Comment #9

    In another reddit post someone (who shall remain nameless) complained that my answer to Question #9 was unacceptable as it did nothing but promote my personal style. Excuse me! I did not invent the DRY Principle as my personal style, it was devised by others as one of those practices which every good programmer should follow. It simply means that where you see the same block of code appearing in multiple places it would be good practice to put that block of code in some sort of reusable subroutine so that you can replace each copy of that block of code with a subroutine call. Apart from reducing the amount of code which you have to write, which is a good idea in its own right, it also means that if you ever need to change the contents of this block of code you only need to change the one subroutine instead of every copy of that code.

    Take the following block of code which I used in Question #29:

    $object->load($_POST);
    $object->validate();
    $object->store();
    

    It may not look like much, but that is because it does include any code required for error checking.

    In this scenario the above code is contained in the Controller and $object identifies the Model. If you don't know about the MVC design pattern you should go away and study it NOW! You should then realise that this code will be duplicated in every script where a Controller calls a Model, and that could be a large number of scripts.

    The problem with this block of code is that it is technically possible, after loading a validating some data, to "accidentally" load in some unvalidated data before storing it, which could potentially create a problem. The only way to ensure that this cannot happen is to wrap that block of code in a subroutine (or in this case a new method in the Model) so that it is physically impossible to insert unvalidated data before the $object->store(). This is achieved in the following code which I put forward as my answer:

    $object->insertRecord($_POST);
    OR
    $object->updateRecord($_POST);
    

    You should notice that instead of one subroutine I have created two. Why is this? Because the logic required for an INSERT operation is different from that required for an UPDATE. Apart from the fact the validation rules are different, the SQL query which is generated is also different. You can see the differences when you compare the internal workings of these methods:

    Note that these methods appear in every concrete table class (Model), but they are inherited from an abstract table class and therefore shared and not duplicated. The use of an abstract class then enables the use of the Template Method Pattern, which explains those methods with a "_cm_" prefix. The use of an abstract class and the Template Method Pattern are both described in the Gang of Four book as fundamental techniques for code reuse. In case you did not get the memo the ability to create higher volumes of reusable code is supposed to be the primary objective behind OOP.

    If you are wondering why I pass the contents of the $_POST array as a single argument instead of loading each element individually then take a look at question #24 and its answer where it explains the benefits of loose coupling over tight coupling.

    You should be able to see that none of the characteristics in my answer was a personal invention, I am simply utilising ideas that were formulated by other people:

    The only thing that I "invented" was how to incorporate these ideas into my code. Surely that is supposed to be what every programmer should be capable of doing.


Amendment History

04 Feb 2023 Added My Comment #14.
31 May 2020 Added Comments on reddit comments.

counter