The presentation consist of following:
- pimpl Idiom
- Introduction to ABC software firm – Rahul’s story.
- The SOLID Principles
- Outline of other principles : KISS , DRY , YAGNI.
- The story of a Paper- Boy : Law of Demeter
2. List of things to be covered :
1. Origin of objects : The short story
2. Pimpl Idiom
3. Introduction to ABC software firm – Rahul’s story.
4. The solid stuffs of programming.
5. Outline of other principles : KISS , DRY , YAGNI.
6. The story of a Paper- Boy : Law of Demeter
2
4. When was OO invented ??
4
Johan Dahl Kristen Nygard
1966 – By Two
Geeks
5. 5
They were working in the language called ALGOL
writing a simulator to simulate the ships .
They got sick of doing that and decided to hack the
language ALGOL
6. 6
ALGOL is a block structure language
Here is how block structure language works :
Lets take the example of c :
void function()
{
int a , b ;
}
Local variables are stored in stack (particularly in
Function Stack Frame )
7. 7
In block structured language you could have that , you
could have something else too :
void OuterFunction
{
int a = 10;
void innerFunction();
}
You could have function declared inside parent function
8. 8
If I have outer function ‘f’ , I could declare ‘g’ ( inner
function ) with in ‘f’ .
‘g’ would have access to ‘f’ variables
‘g’ could talk to variable on ‘f’ stack.
void f()
{
a= 20;
void g();
}
‘g’ could manipulate ‘f’ local variables.
9. 9
What would happen if we took function stack frame
and moved away from stack and put into heap ??
void f()
{
a= 20;
void g();
}
10. 10
If we do that , when f returns when outer function
returns , variables will still exist even though the f
returns .
void f()
{
a= 20;
void g();
}
Now ‘g’ could actually play with those variables even
though the f has returned
11. 11
And this was it :
‘f’ become a constructor
‘g’ become instance methods ,
local variables become instance variables
void f()
{
a= 20;
void g();
}
They had a long discussion , They go to mountains and
finally figure it out .. ! Yes “ The Objects”
12. 12
They developed Simula - The first object oreinted
language ( Simula 1 and simula 67 - objects ,classes ,
inheritance and subclasses.
The creator of C++, Bjarne Stroustrup, has
acknowledged that Simula 67 was the greatest
influence on him to develop C++
14. PIMPL idiom :
In C++ , when anything in a header file class definition
changes , all users of that class must be recompiled – even
if the only change was to the private class members that the
users of the class cannot even access.
To reduce these compilation dependencies , a common
technique is to use a pointer to hide some of the
implementation details - “the Pimpl idiom”
Here is the basic idea :
14
15. Pimpl: “Pointer to implementation”
class widget {
private:
struct impl; // things to be hidden go here
unique_ptr<impl> pimpl ; // pointer to forward-declared structure
}
15
16. 16
Pimpl idiom also know as the compilation firewall .
Its technique to hide the implementation of a class from the
user by defining all private members in the class definition
(.cpp)
17. How to do it : Pimpl idiom ??
1. Forward declare the struct into header file;
2. Declare a pointer to the struct into the header file class
definition;
3. Put the struct definition in the .cpp file.
4. Put all the private member variables into a struct
5. The constructors for the class need to create the struct
6. The destructors of the class needs to destroy the struct
7. The assignment operator and copy constructor need to copy
the struct appropriately (or else disabled)
17
18. Advantages : PIMPL
Changing private member variables of a class does not require
recompiling classes that depend on it (relinking of course is
required)
Re-compilation time is really decreased, since only the source
file needs to be rebuilt, but not the header, and every file that
includes it
Hide implementation
Minimize coupling and hide interfaces
18
21. ABC Software Systems :
Meeting # 1
THE Project Manager
“Client demands for
additional
functionality”
“You got 1 week to
finish the task:
“Yes ! I will
wrap it up by
next week “
RAHUL
Project Manager
21
29. Bugs did not fix , Code become more complex,
Twisted.
29
30. Meeting#3
“The bug is little
bit complex and it
will take more time
“
Rahul
“What’s the
status of
bugs??”
“Raj has
worked in
similar kind of
module last
year . Try out
his code “
Raj : “The backbone
of ABC corporation “ 30
31. Rahul in Trauma
after seeing the
Raj’s code.
Raj :
“hey Rahul ,
you look
stressed”
31
33. Rahul’s Code Design – “The Bad One”
Symptoms of Bad Design :
Rigidity
Fragility
Immobility
Needless Repetition
33
34. RIGIDITY:
What The code is hard to change
Every change causes a cascade of changes in
dependent modules
Why Tight coupling
Result Not changing the code becomes a policy
34
35. FRAGILITY:
What The code breaks in unexpected places every time there
is change
Why Tight coupling
Result Long list of bugs
35
36. IMMOBILITY:
What The code is hard to reuse
Why Tight coupling, many dependencies
Result Rewrite new code instead of reusing the existing one.
36
37. DUPLICATION:
What Same code appears in many places.
Why Lack of abstraction.
Result Fixing same bug or adding same change in many
places.
37
41. #1. SRP – Single Responsibility
Principle
“There should not be more than one reason for a class
to change”
Every class should define a single responsibility
41
43. Problems :
• We must include the GUI in the Computational Geometry application.
• If a change to the Graphical Application causes the Rectangle to change,
that change may force us to rebuild, retest, and redeploy the
Computational Geometry Application.
43
45. Modem Class :
Another SRP violation
Class Modem
{
public:
void Dial() = 0 {}
void Hangup() = 0 {}
void Send(char c) = 0 {}
void char Receive() = 0 {}
}
There are two responsibilities here :
connection management and communication management.
If the application changes in ways that affect the signature of the connection functions,
then the design will smell of Rigidity because the classes that call send
and receive will have to be recompiled and redeployed more often than we like
45
52. LSP
“Functions that use pointers or References to Base classes
must be able to use objects of Derived classes without
knowing it”
“Subtypes must be substitutable for their base types”
52
53. LSP Violation
Simple Example of Violation :Using RTTI (Run- Time Type
Information )
DrawShape is badly formed.
It must know about every possible derivative of the Shape Class
It must be changed whenever new derivatives of Shape are
created.
53
54. Square and Rectangle : A more suitable Violation
54
56. When someone sets the width of a square object ,its height
will change correspondingly and vice-versa.
56
57. But consider the following function :
If reference to a Square object is passed into this function , the
square object will be corrupted because height won’t change.
Violation of LSP : The f does not work for derivatives of its
arguments.
57
59. Consider g below :
The function works fine for Rectangle but throw assertion
error if passed a square.
Passing a square to functions whose programmers made
this assumption will result in problems
This function take pointers/references to Rectangle objects
,but cannot work on Square –violating LSP
59
60. #4. Interface Segregation Principle
Clients should not be forced to depend on interfaces
that they do not use
Do not pollute interfaces with lot of methods
Avoid fat interfaces.
Make fine grained interfaces that are client specific
60
61. //bad example (polluted interface)
Class Worker {
virtual void work()= 0;
virtual void eat() = 0;
}
Class ManWorker: Public Worker {
void work() {…};
void eat() {30 min break;};
}
Class RobotWorker : Public Worker {
void work() {…};
void eat() {//Not Appliciable for a RobotWorker};
}
61
62. Solution :
- split into two interfaces
Class Workable {
virtual void work() = 0;
}
Class Feedable{
virtual void eat() = 0;
}
62
63. 63
Class ManWorker : public Workable ,public Feedable{
public :
void work(){}
void eat(){}
};
Class RobotWorker : public Workable {
public :
void work(){}
};
64. #5 Dependency Inversion Principle
A. High-level modules should not depend on low-level
modules. Both should depend on abstractions.
B. Abstractions should not depend on details. Details
should depend on abstractions.
64
71. #KISS
Keep It Simple Stupid
The simpler your code is , the simpler it will be to
maintain it in the future
“Rahul’s code was complex and buggy”
71
72. #DRY
Don’t Repeat yourself
Divide a system into pieces
Reuse your code, do not duplicate it
Assign clear names
Choose right location
“Rahul loved CtrlC + CtrlV”
72
73. #YAGNI
“Always implement things when you actually need
them, never when you just foresee that you need
them”
You aren't gonna need it
“ Out of Rahul’s Zone – to be followed by the
Project Managers”
73
74. DRY : Divide a component into manageable
components !
KISS: Try to implement something as easy as possible !
YAGNI : Strives for simplicity by not implementing it
at all !
74
76. Law of Demeter (LoD) or principle of
least knowledge
design guideline for developing software, particularly
object-oriented programs.
proposed at Northeastern University towards the end of
1987
origin in the Demeter Project, an adaptive
programming and aspect-oriented programming effort
The project was named in honor of Demeter, “distribution-
mother” and the Greek goddess of agriculture, to signify a
bottom-up philosophy of programming
76
77. 77
The fundamental notion is that a given object should
assume as little as possible about the structure or
properties of anything else – Principle of information
hiding
summarized in each of the following ways:
Each unit should have only limited knowledge about
other units: only units "closely" related to the current
unit.
Each unit should only talk to its friends; don't talk to
strangers.
Only talk to your immediate friends.
78. 78
I deliver
newspapers “I read newspaper
daily and I pay
every month to
paper boy for his
service”
“Knock Knock
Payment time –
its month end”
79. Paper- Boy Story
The story has a customer and Paperboy
Every month he comes to customer and collects the
money from customer .
Lets say our paperboy stops by, rings the doorbell, and
demands his payment for a job well done.
79
83. Real World Problems : #1
“The paperboy is being exposed to more information than
he needs to be”
If our future Wallet object holds credit cards, the paperboy
has access to those too.
The 'Paperboy' class now 'knows' that the customer has a
wallet, and can manipulate it
83
84. Real World Problems : #2
“Tight Coupling”
When we compile the Paperboy class, it will need the
Customer class and the Wallet class.
These three classes are now 'tightly coupled'.
If we change the Wallet class, we may have to make
changes to both of the other classes.
84
85. Real World Problems : #3
What happens if the Customer's wallet has been stolen?
Perhaps last night a Thief picked the pocket of our
example, and someone else on our software development
team decided a good way to model this would be by setting
the wallet to null, like this: victim.setWallet(null);
Our paperboy will get a runtime exception for calling a
method on a null pointer.
85
86. We could fix this by checking for 'null' on the wallet before
we call any methods on it, but this makes our real-language
description even worse...
“If my customer has a wallet, then see how much he has...
if he can pay me, take it”. Obviously, we are getting
problems here.
86
89. Why its better now ??
The Paperboy code is now 'asking' the customer for a
payment.
The paperboy does not have direct access to the wallet.
The Wallet class can now change, and the paperboy is
completely isolated from that change
89
90. We are now free to change the implementation of
'getPayment()'.
90
91. 91
In the real world though, when the paper boy comes to the
door:
Our Customer may actually get the two bucks from a jar of
change, search between the cushions of his couch, or
borrow it from his roommate. All of this is 'Business Logic',
and is of no concern to the paper boy
This is the Law of Demeter in the sense that it is 'hiding'
the wrapped object, making the user use it through a
different interface.
92. Now Co-relate the paperboy
example with LOD
An object A can request a service (call a method) of an
object instance B, but object A should not "reach
through" object B to access yet another object C, to
request its services. Doing so would mean that
object A implicitly requires greater knowledge of
object B's internal structure. Instead, B's interface
should be modified if necessary so it can directly serve
object A's request, propagating it to any relevant
subcomponents.
92