Code Solid 2014
Code Solid 2014
Mireille Blay-Fornarino, Université Nice Sophia Antipolis, Département Info IUT, Octobre 2014
1
dimanche 5 octobre 14
Conclusion
dimanche 5 octobre 14
S.O.L.I.D : l’essentiel !
dimanche 5 octobre 14
SOLID: Single Responsibility
principle(SRP)
http://williamdurand.fr/from-stupid-to-solid-code-slides/#/4/4 4
dimanche 5 octobre 14
The single-responsibility principle
✤ Example:
➡ Often we need to sort students by their name, or ssn. So one may make Class Student
implement the Java Comparable interface.
5
www.cs.uofs.edu/~bi/2013f-html/se510/design-principles.ppt
dimanche 5 octobre 14
The single-responsibility principle
Register Student
Add(Course d, Student s); SSN Comparable
Name int compareTo()
getSSN()
getName()
major
When a new requirement getMajor()
int compareTo()
needs to sort students in a
different order, Student,
Register, and AClient all
need to be recompiled, even AClient
Register has nothing to do op() { ;}
dimanche 5 octobre 14
The single-responsibility principle
Register
Add(Course d, Student s); Comparator
int compare(Object o1, Object o2)
Student
SSN
Name
getSSN() StudentByName
getName()
int compare(Object o1, Object o2) ClientA
major op() { ;}
getMajor()
StudentBySSN
int compare(Object o1, Object o2)
The solution is to separate
the two responsibilities into
two separate classes and use ClientB
another version of op() { ;}
It invokes
Collections.sort(). Collections.sort(aListofStudents,
new StudentByName()); 7
www.cs.uofs.edu/~bi/2013f-html/se510/design-principles.ppt
dimanche 5 octobre 14
Les codes : Classe Student
public class Student {
// constructor
public Student(String name, int section) {
this.name = name;
this.section = section;
}
....}
dimanche 5 octobre 14
Les codes : Comparateurs
Interface Comparator<T>
Type Parameters:
T - the type of objects that may be compared by this comparator
dimanche 5 octobre 14
Les codes :
Comparer des étudiants
Student[] students = {
larry, kevin, jen, isaac, grant, helia,
frank, eve, dave, carol, bob, alice
};
http://ima.udg.edu/~sellares/EINF-ES2/OOBasicsPrinciples.pdf 10
dimanche 5 octobre 14
SOLID: Open/Closed Principle
(OCP)
A class should have one, and only
one, reason to change.
Robert C. Martin.
http://deviq.com/single-responsibility-principle11
dimanche 5 octobre 14
Principe ouvert / fermé
Open/Closed Principle (OCP)
You should be able to extend a classes behavior, without modifying it.
Robert C. Martin.
✤ Comment faire en sorte que la voiture aille plus vite à l’aide d’un
turbo?
➡ Il faut changer la voiture
‣ avec la conception actuelle…
13
dimanche 5 octobre 14
... But Keep It Closed!
dimanche 5 octobre 14
The Open/Closed Principle (OCP)
Example
An Example of
What not to do!
What is wrong
with this code?
15
www2.cs.uh.edu/~svenkat/ooad/slides/PPT/session07.ppt
dimanche 5 octobre 14
The Open/Closed Principle (OCP)
Example
16
dimanche 5 octobre 14
Heuristiques pour OCP
dimanche 5 octobre 14
The Open-Closed Principle(OCP) :
allons plus loin (1)
✤ Le travail de cette méthode est de calculer le prix total d’un ensemble de «parties»
public double totalPrice(Part[] parts) {
total += parts[i].getPrice();
return total;
18
CSSE501 Object-Oriented Development
dimanche 5 octobre 14
The Open-Closed Principle(OCP) :
allons plus loin (2)
✤ «But the Accounting Department decrees that motherboard parts and memory parts should have a premium applied
when figuring the total price.»
else
total += parts[i].getPrice();
return total;
}
19
CSSE501 Object-Oriented Development
dimanche 5 octobre 14
The Open-Closed Principle(OCP) :
allons plus loin (3)
✤ Here are example Part and ConcretePart classes:
21
CSSE501 Object-Oriented Development
dimanche 5 octobre 14
The Open-Closed Principle(OCP) :
allons plus loin (5)
/**
* Class PricePolicy implements a given price policy.
*/
public class PricePolicy {
private double factor;
22
CSSE501 Object-Oriented Development
dimanche 5 octobre 14
The Open-Closed Principle(OCP) :
allons plus loin (6)
23
CSSE501 Object-Oriented Development
dimanche 5 octobre 14
The Open-Closed Principle (OCP)
24
CSSE501 Object-Oriented Development
dimanche 5 octobre 14
SOLID: Liskov Substitution
Principle (LSP)
Derived classes must be
substitutable for their base classes.
Robert C. Martin.
http://williamdurand.fr/from-stupid-to-solid-code-slides/#/
25
dimanche 5 octobre 14
Principe de substitution de Liskov
Liskov Substitution Principle (LSP)
26
dimanche 5 octobre 14
Principe de substitution de Liskov
✤ « Si une propriété P est vraie pour une instance x d'un type T, alors
cette propriété P doit rester vraie pour tout instance y d'un sous-type
de T »
✤ Implications :
➡ Le «contrat» défini par la classe de base (pour chacune de ses méthodes)
doit être respecté par les classe dérivées
➡ L'appelant n'a pas à connaître le type exact de la classe qu'il manipule :
n'importe quelle classe dérivée peut être substituée à la classe qu'il utilise
✤ → Principe de base du polymorphisme :
➡ Si on substitue une classe par une autre dérivée de la même hiérarchie:
comportement (bien sûr) différent mais conforme.
27
dimanche 5 octobre 14
Inheritance Appears Simple
// ...
Parrot mypet;
mypet.mimic(); // my pet being a parrot can Mimic()
mypet.fly(); // my pet “is-a” bird, can fly
dimanche 5 octobre 14
Penguins Fail to Fly!
class Penguin : public Bird {
public: void fly() {
error (“Penguins don’t fly!”); }
};
§ Does not model: “Penguins can’t fly”
§ It models “Penguins may fly, but if they try it is error”
§ Run-time error if attempt to fly → not desirable
§ Think about Substitutability - Fails LSP
void PlayWithBird (Bird& abird) {
abird.fly(); // OK if Parrot.
// if bird happens to be Penguin...OOOPS!!
}
dimanche 5 octobre 14
Liskov Substitution Principe :
contre-exemple
class Rectangle
{
int m_width;
int m_height;
public void setWidth(int width)
{
m_width = width;
}
public void setHeight(int h){
m_height = ht;
} class Square extends Rectangle
public int getWidth(){ {
return m_width;
public void setWidth(int width){
}
public int getHeight(){
super.setWidth(width);
return m_height; super.setHeight(width);
} }
public int getArea(){
return m_width * m_height; public void setHeight(int height){
} super.setWidth(width);
} super.setHeight(width);
}
}
dimanche 5 octobre 14
Liskov Substitution Principle
class LspTest
{
private static Rectangle getNewRectangle(){
// it can be an object returned by some factory ...
return new Square();
}
public static void main (String args[]){
Rectangle r = LspTest.getNewRectangle();
r.setWidth(5);
r.setHeight(10);
// user knows that r it's a rectangle. It assumes that he's
able to set the width and height as for the base class
System.out.println(r.getArea());
// now he's surprised to see that the area is 100 instead of 50.
}
dimanche 5 octobre 14
LSP Related Heuristic
It is illegal for a derived class, to override
a base-class method with a NOP method
n NOP = a method that does nothing
dimanche 5 octobre 14
Program To An Interface, Not An
Implementation
✤ An interface is the set of methods one object knows it can invoke on
another object
✤ A class can implement many interfaces. (Essentially, an interface is a subset
of all the methods that a class implements)
✤ A type is a specific interface of an object
✤ Different objects can have the same type and the same object can have
many different types.
✤ An object is known by other objects only through its interface.
✤ Interfaces are the key to pluggability
34
CSSE501 Object-Oriented Development
dimanche 5 octobre 14
Interface Example
/**
* Interface IManeuverable provides the specification
* for a maneuverable vehicle.
*/
35
CSSE501 Object-Oriented Development
dimanche 5 octobre 14
Interface Example (Continued)
36
CSSE501 Object-Oriented Development
dimanche 5 octobre 14
Interface Example (Continued)
✤ This method in some other class can maneuver the vehicle without being
concerned about what the actual class is (car, boat, submarine) or what
inheritance hierarchy it is in
37
CSSE501 Object-Oriented Development
dimanche 5 octobre 14
Interface segregation principle
✤ Many client-specific interfaces are better than one general-purpose
interface.
➡ Incite à avoir des interfaces petites pour ne pas forcer des classes à
implémenter les méthodes qu’elles ne veulent pas.
dimanche 5 octobre 14
public interface Animal {
void fly();
void run();
void bark();
}
public class Bird implements Animal {
public void bark() { /* do nothing */ }
public void run() {
// write code about running of the bird
}
public void fly() {
// write code about flying of the bird
}
}
public class Cat implements Animal {
public void fly() { throw new Exception("Undefined cat
property"); }
public void bark() { throw new Exception("Undefined cat
property"); }
public void run() {
// write code about running of the cat
}
}
public class Dog implements Animal {
public void fly() { }
public void bark() {
// write code about barking of the dog
}
public void run() {
// write code about running of the dog
}
}
39
http://codebalance.blogspot.fr/2010/09/oop-solid-rules-interface-segregation.html
dimanche 5 octobre 14
public interface Flyable {
void fly();
}
public interface Runnable {
void run();
}
public interface Barkable {
void bark();
}
public class Bird implements Flyable, Runnable {
public void run() {
// write code about running of the bird
}
public void fly() {
// write code about flying of the bird
}
}
public class Cat implements Runnable{
public void run() {
// write code about running of the cat
}
}
public class Dog implements Runnable, Barkable {
public void bark() {
// write code about barking of the dog
}
public void run() {
// write code about running of the dog
}
} http://codebalance.blogspot.fr/2010/09/oop-solid-rules-interface-segregation.html 40
dimanche 5 octobre 14
Principe inversion de dépendance
Dependency Inversion Principle (DIP)
Depend on abstractions,
not on concretions.
Robert C. Martin.
A LIRE !! http://cyrilgandon.blogspot.fr/2013/07/inversion-des-dependances-solid-55.html
41
dimanche 5 octobre 14
Inversion de dépendance
✤ Réduire les dépendances sur les classes concrètes
dimanche 5 octobre 14
Inversion de dépendance
43
dimanche 5 octobre 14
Design to an Interface
n Abstract classes/interfaces:
q tend to change much less frequently
n Exceptions
q Some classes are very unlikely to change;
n as in Java or C++
dimanche 5 octobre 14
Software design principles-
summary
✤ The single-responsibility principle
✤ There is only one source that may the class to change
✤ The open-closed principle
✤ Open to extension, closed for modification
✤ The Liskov substitution principle
✤ A subclass must substitutable for its base class
✤ The dependency inversion principle
✤ Low-level (implementation, utility) classes should be dependent on high-
level (conceptual, policy) classes
✤ The interface segregation principle
✤ A client should not be forced to depend on methods it does not use.
www.cs.uofs.edu/~bi/2013f-html/se510/design-principles.ppt
dimanche 5 octobre 14
Autres éléments de bibliographie
✤ Coupling and Cohesion, Pfleeger, S., Software Engineering Theory and Practice.
Prentice Hall, 2001.
✤ http://igm.univ-mlv.fr/ens/Master/M1/2013-2014/POO-DP/cours/1c-POO-x4.pdf
46
dimanche 5 octobre 14
L’art du «Codage»
«Conventional wisdom says that once a project is in the coding phase, the work is mostly
mechanical, transcribing the design into executable statements. We think that this attitude
is the single biggest reason that many programs are ugly, inefficient, poorly structured,
unmaintainable, and just plain wrong.
Coding is not mechanical. If it were, all the CASE tools that people pinned their hopes on
in the early 1980s would have replaced programmers long ago. There are decisions to be
made every minute—decisions that require careful thought and judgment if the resulting
program is to enjoy a long, accurate, and productive life.»
Hunt, Thomas «The pragmatic Programmer»
47
dimanche 5 octobre 14
Premature Optimization
if (isset($frm['title_german'][strcspn($frm['title_german'], '<>')]))
{
// ...
}
http://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html 48
dimanche 5 octobre 14
Eviter la programmation par
coïncidence
«Developers who don't actively think about their code are programming by
coincidence—the code might work, but there's no particular reason why »
Hunt, Thomas «The pragmatic Programmer»
validate(); !
public void setup() {
frameRate(4);
! reinit();
revalidate(); ! memoriseCarts() ;....
! // on veut garder la main sur le jeu c'est mousePressed qui stimule des redraw
repaint(); ! noLoop();
! }
paintImmediately(r); !
! public void draw() {
! ! afficherJoueurs();
! ! //afficherCartes();
! } 49
dimanche 5 octobre 14
Eviter la programmation par
coïncidence
«Developers who don't actively think about their code are programming by
coincidence—the code might work, but there's no particular reason why »
Hunt, Thomas «The pragmatic Programmer»
➡ «A oui! ça ne peut pas marcher parce que tu n’as pas mis le code sous
bazarland»
50
dimanche 5 octobre 14
Penser à «Estimer» vos algorithmes
➡ Comment le programme se comportera s’il y a 1000 enregistrements? 1 000
000? Quelle partie optimiser?
‣ S’il faut 1s pour traiter 100 éléments, pour en traiter 1000, en faut-il :
1, (O(1)) : temps constant
‣
100 (O(n2))
‣
51
dimanche 5 octobre 14
Penser à «Estimer» vos algorithmes
52
dimanche 5 octobre 14
«Refactoring» ou
l’art du «jardinage logiciel»
« Rather than construction, software is more like gardening—it is more
organic than concrete. You plant many things in a garden according to an
initial plan and conditions. Some thrive, others are destined to end up as
compost. You may move plantings relative to each other to take advantage
of the interplay of light and shadow, wind and rain. Overgrown plants get
split or pruned, and colors that clash may get moved to more aesthetically
pleasing locations. You pull weeds, and you fertilize plantings that are in
need of some extra help. You constantly monitor the health of the garden,
and make adjustments (to the soil, the plants, the layout) as needed»
53
dimanche 5 octobre 14
«Refactoring» : quand ?
✤ Pour éliminer les «fenêtres cassées»
✤ Pour améliorer le design : duplication
(DRY), couplage, performance, ...
✤ Pour ajuster en fonction des besoins et des
demandes de changements
-
dimanche 5 octobre 14
«Refactoring» : comment ?
✤ Utilisez des outils pour identifier les
changements (cf. cours Métriques)
✤ Utilisez des outils pour factoriser (Par
exemple, Eclipse et les outils d’extractions
de méthodes, ...)
-
๏ Organiser le refactoring
๏ Planifiez, Mettez des priorités, Mémorisez les
changements à faire
๏ Soyez sûr de vos tests avant de refactoriser
๏ Progressez pas à pas
http://www.jhackens.com/2006/10/jardinier/ 55
dimanche 5 octobre 14
«Refactoring» : exemple (2)
This Java code is part of a framework that will be used throughout your project. Refactor it to
be more general and easier to extend in the future.
public class Window {
public Window(int width, int height) { ... }
public void setSize(int width, int height) { ... }
public boolean overlaps(Window w) { ... }
public int getArea() { ... -}
}
56
dimanche 5 octobre 14
«Refactoring» : exemple (2)
57
dimanche 5 octobre 14
«Refactoring» : exemple (2)
public abstract class Shape { public class Window {
// ... private Shape shape;
public abstract boolean public Window(Shape shape) {
overlaps(Shape s); this.shape = shape;
public abstract int getArea(); ... }
} public void setShape(Shape shape) {
this.shape = shape;
- ...
} public boolean overlaps(Window w) {
return shape.overlaps(w.shape);
} public int getArea() {
return shape.getArea();
}
}
58
dimanche 5 octobre 14
«Refactoring» : exemple (2)
Note that in this approach functions. This is a good idea.
we've used delegation rather It means that when you extend
than subclassing: a window is the concept of a shape, the
not a "kind-of'' shape—a compiler will warn you about
window "has-a" shape. It uses classes that you have affected.
- You'll
a shape to do its job. We recommend using
often find delegation useful interfaces this way when you
when refactoring. delegate all the functions of
We could also have extended some other class.
this example by introducing a
Java interface that specified
the methods a class must
59
support to support the shape
dimanche 5 octobre 14
Et si nous parlions du
moustique...
Selon ce développeur Microsoft, bon nombre de codes sources vérifient une version de Windows 95 ou 98 en testant "en dur" une chaîne de caractère qui commenc
par "Windows 9".
Effectivement, si l'on utilise par exemple le moteur de recherche searchcode la chaîne "if(version,startswith("windows 9")" qui correspond en Java à la recher
de "Windows 9"dans le début de la chaîne de caractères de la version, on obtient un certain nombre de résultats dans les codes open source qui n'augurent rien de
bon pour l'ensemble des codes de la planète :
https://searchcode.com/?q=if%28version%2Cstartswith%28%22windows+9%22%29
60
http://www.zdnet.fr/actualites/pourquoi-windows-10-et-pas-windows-9-39807217.htm
dimanche 5 octobre 14