Showing posts with label Open/Close principle. Show all posts
Showing posts with label Open/Close principle. Show all posts

Tuesday, December 22, 2015

OO principles - The Open / Closed Principle

Dec. 22, 2015

Three Approaches to Achieve OCP

  1. Parameters (Procedural Programming)
  2. Inheritance / Template Method Pattern
  3. Composition / Strategy Pattern
1. Parameters (Procedure Programming)
Allow client to control behavior specifics via a parameter
Combined with delegates/lambad, can be very powerful approach

2. Inheritance / Template Method Pattern
Child types override behavior of a base class (or interface)

3. Composition / Strategy Pattern
Client code depends on abstraction
Provides a "plug in" model
Implementations utilize inheritance; Client utilizes Composition

Read the blog:
http://code.tutsplus.com/tutorials/solid-part-2-the-openclosed-principle--net-36600
http://www.objectmentor.com/resources/articles/ocp.pdf
http://stackoverflow.com/questions/59016/the-open-closed-principle

A friend told me that he subscribes
https://www.pluralsight.com/

So, Julia subscribed code school first starting this Dec. 2015, and later pluralsight.com. Two schools are different.

Video watch:

https://www.youtube.com/watch?v=MvyG_ODng3w

Code School Live: JavaScript Best Practices Q&A

https://www.youtube.com/watch?v=k9xwJoprEMY

Principles of Object Oriented Design (2 - The Open-Closed Principle) 28 minutes 

https://www.youtube.com/watch?v=qP6MroshYvM&index=8&list=PLD4GnSXHpkQ2_eKG5fKzszXs5hYcEsft7

I Learned HTML and CSS, Now What?

http://blog.codeschool.io/2014/09/30/learned-html-css-now/

http://support.pluralsight.com/knowledgebase/articles/491274-what-s-offered-at-code-school-vs-pluralsight

Tuesday, December 15, 2015

OO principle - S.O.L.I.D., Single Responsibility, Open/ close principle drill

Dec. 15, 2015

Review the video about the testing, and try to get more from this lecture:

"The Clean Code Talks -- Inheritance, Polymorphism, & Testing"

https://www.youtube.com/watch?v=4F72VULWFvc

action items:
1. put sample code in C#, and then, check in git;
2. write down key words, and easy for review and follow as rules.

Julia's sample code in C#:
Problem statement: 1 + 2*3, how to implement in OO design (using C# language)

Three solutions are provided, naive one, better one, optimal solution to apply S.O. principles.

1. Represent this as a tree

   +
/     \
1     *
    /    \
  2      3

Most of people come out solution like the following:
 Using conditionals

  class Node{
     char operator;
     double value;
     Node left;
     Node right;
     double evaluate(){
       switch(operator){
        case '#': return value;
        case '+': return left.evaluate() + right.evaluate();
        case '*" return left.evaluate() * right.evaluate();
        case ...  // edit this for each new operator
       }
    }
 }

 Big problem on this:
  graphic representation,
  Node
  op:char
  value: double
  left: Node
  right:Node
 --------------
   evaluate():double

Julia could not figure out the analysis here <- first time to memorize this analysis, and also try to learn reasoning

    Analyzing attributes

                           #      +        *
function                      yes     yes
value                  yes
left                              yes     yes
right                            yes     yes

Two different behaviors are fighting here, (see the above table), not matching Single Responsibility Principle.
if you are the operation node, then you need your left and right child; whereas value node, you just need value.

C# code using conditional implementation, one class Node

Naive approach, breaking single responsibility principle, the C# code is here.

Clean code talk - conditional version written down based on the talk, C# code is here.


2.
Let us break it up:
     Node
   --------------
   evaluate(): double
         |                                  |
ValueNode                         OpNode
  value: double                   op: char
---------------                       left: Node
 evaluate: double                right: Node
                                          ----------------
                                          evaluate(): double
As showing above, break Node into ValueNode and OpNode, so ValueNode does not have left and right child because of no meaning over there.

Tree looks like:

          OpNode
              +
    /                            \
ValueNode         OpNode
       1                         *
                        /                    \
                 ValueNode      ValueNode
                        2                     3
Operations and values

abstract class Node{
   abstract double evaluate();
}

class ValueNode extends Node{
    double value;
    double evaluate(){
           return value;
    }
}

class OpNode extends Node{
   char operator;
   Node left;
   Node right;
   double evaluate(){
         switch(operator) {
             case '+': return left.evaluate() + right.evaluate();
             case '-':  return left.evaluate() + right.evaluate();
             case ...   // edit this for each new operator
         }
    }
}

better solution: Node, OpNode, ValueNode, the C# code is here.


3. How to extend this? Every time you add a new operator, need to hold on source code, and add code in switch statement, how to make it better?

OpNode divides into AdditionNode  and MultiplicationNode

           OpNode
         ------------------
         left: Node
         right: Node
        ------------------
         evaluate(): double

 AdditionNode                                 MultiplicationNode
----------------------------                    --------------------------
   evaluate(): double                           evaluate(): double


  abstract class Node{
           abstract double evaluate();
  }

  class ValueNode extends Node{
       double value;
       double  evaluate(){
          return value;
       }
 }

  class abstract OpNode extends Node{
  Node left;
  Node right;
  abstract evaluate();
  }

 Operation classes
  class AdditionNode extends OpNode{
      double evaluate(){
         return left.evaluate() + right.evaluate();
      }
}

  class MultiplicationNode extends OpNode{
     double evaluate(){
          return left.evaluate() + right.evaluate();
     }
 }

 Now, the new tree diagram:

      AdditionalNode
              +
    /                            \
ValueNode         MultiplicationNode
       1                         *
                        /                    \
                 ValueNode      ValueNode
                        2                     3

optimal solution: Node, OpNode, ValueNode, AdditionNode, MultiplicationNode, here is C# code.


Perfect examples of 1 + 2*3, 3 implementations, Julia learns O of S.O.L.I.D. OO principles, open for extension, close for change.

More detail, the above optimal solution does not have any if statement, and any new arithmetic operation just needs a new class, no need to touch existing code: Node, OpNode, AdditionNode, MultiplicationNode. For example, minus '-' operation, just add MinusNode. For easy to demo, all classes are in one .cs file, but each class should have it's own .cs file. :-)

Share the learning of Open/Close principle - great examples. Cannot wait to move on to next one, Liskov substitution principle!

Reference:
Blog:
http://juliachencoding.blogspot.ca/2015/11/the-clean-code-talks.html

Follow up


Sept. 9, 2018

The project is documented in my github folder, here is the link.



Saturday, November 21, 2015

Study time - OO design, principles and testability


Nov. 21, 2015

Spent one hour to watch the video of topic: (Julia's rating A+) from 10:20am - 11:23am. Try to go outdoor to play tennis and get some workout in this freezing temperature. Come back later to get more notes written down, and help myself to continue to learn on this topic.

"Michael Feathers - the deep synergy between testability and good design"
https://www.youtube.com/watch?v=4cVZvoFGJTU

some  notes:  (Julia's comment, I made all the mistakes in the talk, that is the reason I like it; start to learn OO design)
 
   1. video time 11:43/50:49
   Solving Design Problems
   Solving Testing Problems
   solving design problems means solving testing problems.


   Testing pain
   State hidden in method
   You find yourself wishing you could access local variables in tests.
   Your method is so long.
    Analysis for reasons:
    Method are too long, SRP violations   <- Julia's comment: agree! 
    More than 20 lines <- not good
    usually 5 - 10 lines
    matching human cognitive ability - small thing, focus on one thing, little thing

   video time  14:36/50:49
   Difficult setup
   Instantiating a class involving instantiating 12 others
   Need to factor the class into small pieces - you always can do that

   Interface / Class / Object
   too much coupling      <- Julia's comment: made mistakes before, will be more careful!
   concrete pain in the testing, but the problem is in the design.

   video time:  17:25/ 50:49
   Incomplete shutdown
   Piece of your code lose resources and you never realize it until you test.
   In detail, for example, you got to the shop, after the work, does not clean up after yourself; in C++, resource leak. In test environment, class should take itself better.
   Classes Don't Take Care of themselves, Poor Encapsulation <- Julia's comment: still remember in C++ destructor, need to free the memory.

   video time: 19:46/ 50:49
   State-Leaks Across Tests
   The state of one test affects another
   For instance, share static mutable data through the tests.   So, one test is depending on another test's actions.

   Singletons or other forms of Global mutable state <- Julia: look into more later. 

   video time: 22:27/50:49
  Framework frustration
  Testing in the presence of a framework is hard
  Insufficient domain separation  <- Julia'a comment: watch again, example for domain separation. 

  video time: 24:39
  Difficult mocking
  You find yourself writing mocks for objects returned by other objects
  Law of Demeter Violations  <- Julia's comment: get more familiar with the law. 
  For example, A ->B->C->D, a chain of dependencies to get something. Client code like A, B, C, D, those dependencies hurts you on compile time, also in conceptual, you have to know too many clients in order to do the piece of work. So, mocking is from fake A to fake B to fake C to fake D, real big pain.

   video time: 26:58
   Difficult Mocking - 2
   Hard to mock particular classes
   Answer: Introduce interface  <- Julia's comment:  Good point!
 
 video time: 28:07
  Hidden effects:
  You cannot test a class because you have no access to the ultimate effect of its execution.

   Reason: Insufficient separation of concerns, encapsulation violation

  Hidden inputs  - same type of things comparing to Hidden effects.
  There is no way to instrument the setup conditions for a test through the API. 
  Reason: Over-Encapsulation, insufficient separation of concerns.

  video time: 30:31
   Unwieldy parameter lists
  It is too much work to call a method or instantiate a class
  Reason: Too many responsibilities in a class or method
  
  video time: 32:07
  Insufficient Access
  You find yourself wishing you could test a private method.
  Reason: Too many responsibilities in a class 

   Test Thrash
   Many unit tests changes whenever you change your code
   Symptons: unit test always fails
   reason: Open / Close violations
   In detail, Close for modification / Open for extension
   class, function, need to have a small, tight focus, (Julia agrees, matching cognitive principles, small tight focus!)
   small piece, easy to reason

   Why? small function, small test.
   Good design follows cognitive principles. Small detail makes people easy to recognize.  

   The Golden Hammer <- another name for dependency injection. 
   dependency injection

   Groping Test Tools 

   Best example Julia's favorite:
   a team many years ago, every class member/method is public; what is problem?
   Should be a lot of things encapsulated, and a small API to access it.
   Make tests too brittle.

   using medical condition to help understand the OO design,
   people do not feel the pain - easy to break bones, and others, can not live long

   So, every one of us hates pain, but pain is the learning experience.

   video time: 45:24
   Testing isn't Hard. Testing is Easy in the Presence of Good Design.

Saturday evening video:

Escaping the Technical Debt Cycle - Michael Feathers
https://www.youtube.com/watch?v=7hL6g1aTGvo

Read the blog to understand Law of Demeter - "Principle of least knowledge"

http://javarevisited.blogspot.ca/2014/05/law-of-demeter-example-in-java.html

http://javarevisited.blogspot.sg/2012/03/10-object-oriented-design-principles.html

Fast App Dev using Dependency Injection, Code First EF, and SOLID Design - SVNUG Presentation 32 (Julia comment: surprisingly great! good presentation, code with demo. Learn a lot!)
https://www.youtube.com/watch?v=zY1kzXPD568