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

Pop Quiz on OOP

Posted on 9th May 2020 by Tony Marston
Introduction
Questions
Answers
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 to insert or update a record in the database 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 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.

    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.

    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.

    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.

    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 50, one for each of my Transaction Patterns. If I have 50 Controllers and 400 table classes that means that I can deal with 50 x 400 = 20,000 (yes, TWENTY 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 truely pragmatic programmer should be "innovate, don't imitate".

    return to question

Other comments may be found on 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?

counter