2. About us
Jarno Walgemoed Jan-Kees van Andel
–Architect @JPoint –Architect @JPoint
–Fa-Med
r –Rabobank
r
pe
pe
–Blinker –SNS Bank
lo
ve
–DJI
elo
D e –Apache MyFaces
v
–Devoxx Steering
De
SOLID Software Design 2
15. Code quality
Is this code quality?
/**
* This controller contains default Action and Render mappings,
* used as fallback for handling invalid URL's. This prevents DOS
* attacks, because a "no-handler-found“ Exception results in a
* corrupt application state in WAS and can only be restored by
* restarting the application. These handlers solve this problem.
*/
@Controller
@RequestMapping("VIEW")
public class DefaultController {
SOLID Software Design 15
16. Code quality
Is this code quality?
/**
* This controller contains default Action and Render mappings,
* used as fallback for handling invalid URL's. This prevents DOS
* attacks, because a "no-handler-found“ Exception results in a
* corrupt application state in WAS and can only be restored by
* restarting the application. These handlers solve this problem.
*/
@Controller
@RequestMapping("VIEW")
public class WebSphereASDefaultHandlerController {
SOLID Software Design 16
17. Code quality
Tonight, code quality means OO Design
– OOD is not free or easy, not even with Java/C#
– A lot of structured programming out there!
SOLID Software Design 17
18. Code quality
Tonight, code quality means SOLID principles
– Not about Object Oriented Modeling
• (Person, User, Plane is-a Vehicle, etc)
• Highlighting Nouns
– But about Dependency Management
SOLID Software Design 18
19. Code quality
Tonight, code quality means Dependency Mgt
– Because
• We DON’T want rigid code
• We DON’T want changes to cause ripple effects
• We DON’T want fragile code
• We DO want easily unit testable code
• We DO want reusable code
• We DO want readable code
SOLID Software Design 19
27. Single Responsibility Principle
“A class should have only one reason to change”
– Theory
– Simple example
– Real world example
– Considerations
– Conclusion
SOLID Software Design 27
28. Single Responsibility Principle
Theory
– A Class Should Only Have One Reason To Change
– Also referred to with the term Cohesion
(DeMarco, Page-Jones)
– Separation of Concerns
– Classes should have ONE well-defined
responsibility
SOLID Software Design 28
30. Single Responsibility Principle
Simple example
– Database application interface specification
public interface Database {
public void connect(String url);
public void disconnect();
public ResultSet executeQuery(String query);
}
SOLID Software Design 30
31. Single Responsibility Principle
Simple example
– What if the protocol changes?
– What if the connection management changes?
– What if we want to implement pooling or caching?
– We’ll need to change the database implementation
in both cases
SOLID Software Design 31
32. Single Responsibility Principle
Simple example
– How about this?
public interface DatabaseConnection {
public ResultSet executeQuery(String query);
}
public interface DatabaseConnectionManager {
public DatabaseConnection connect(String url);
public void disconnect(DatabaseConnection conn);
}
SOLID Software Design 32
33. Single Responsibility Principle
Simple example
– DatabaseConnection implementations handle
querying
– DatabaseConnectionManager implementations
handle connections
– We’ve managed to split two responsibilities
SOLID Software Design 33
35. Single Responsibility Principle
Considerations
– If the application doesn’t require changing either
of the coupled responsibilities at different times
DON’T USE SRP
– Don’t apply SRP if there are no symptoms
– Treat it as a guideline
– Be consistent in what you call a “Responsibility”
• Split on functionality, domain, architecture, layers and
do this in a consistent way
SOLID Software Design 35
36. Single Responsibility Principle
Conclusion
– Simplest SOLID principle, hardest to get right
– Be critical deciding whether or not an SRP
violation needs to be fixed
– Stay pragmatic!
– State management simplified by separating object
lifecycles
SOLID Software Design 36
38. Open-Closed Principle
“Software entities should be open for extension,
but closed for modification”
– Theory
– Simple example
– Real world example
– Considerations
– Conclusion
SOLID Software Design 38
39. Open-Closed Principle
Theory
– Helps preventing rigidity and cascading changes
– Open for extension
• Behaviour of a module can be extended
– Closed for modification
• Extending does not result in a source change for a
module
SOLID Software Design 39
41. Open-Closed Principle
Simple Example
– We are using this Rectangle object
public class Rectangle {
private int width; private int height;
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
SOLID Software Design 41
42. Open-Closed Principle
Simple Example
– With this function we calculate area totals
public class AreaCalculator {
public int calculateTotalArea(Rectangle [] rectangles) {
int totalArea = 0;
for(Rectangle rectangle : rectangles){
totalArea +=
rectangle.getWidth() * rectangle.getHeight();
}
return totalArea;
}
}
SOLID Software Design 42
43. Open-Closed Principle
Simple Example
– Now we want to add a circle to the equation
public class Circle {
private int radius;
public int getRadius() {
return radius;
}
}
SOLID Software Design 43
44. Open-Closed Principle
Simple Example
– What happens to the calculation?
public double calculateTotalArea(Object [] objects) {
double totalArea = 0;
for(Object object : objects){
if(object instanceof Rectangle){
Rectangle rectangle = (Rectangle)object;
totalArea += rectangle.getWidth() * rectangle.getHeight();
}
if(object instanceof Circle){
Circle circle = (Circle)object;
totalArea += circle.getRadius() * circle.getRadius() * Math.PI;
}
}
return totalArea;
}
SOLID Software Design 44
45. Open-Closed Principle
Simple Example
– This is poor design (of course)
– The calculate method is not closed for
modification and not open for extension
– Adding a Circle requires the developer to change
the calculation code!
SOLID Software Design 45
46. Open-Closed Principle
Simple Example
– Introducing Shape and extending it
public abstract class Shape {
public abstract double getArea();
}
public class Circle extends Shape {
public double getArea() {
return radius * radius * Math.pi;
}
…
}
SOLID Software Design 46
47. Open-Closed Principle
Simple Example
– Simplifies AreaCalculator substantially
– Allows future extension
public class AreaCalculator {
public double calculateTotalArea(Shape[] shapes) {
double totalArea = 0;
for (Shape shape : shapes) {
totalArea += shape.getArea();
}
return totalArea;
}
}
SOLID Software Design 47
48. Open-Closed Principle
Simple Example
– The calculation is now Open for extension and
closed for modification
– Adding another shape to the equation no longer
requires a change to the calculate implementation
SOLID Software Design 48
50. Open-Closed Principle
Considerations
– Abstraction is key
– So… should we just abstract everything? No.
– Abstract elements that require frequent change
– Overuse of abstractions can create clutter
– Avoid premature abstraction
SOLID Software Design 50
51. Open-Closed Principle
Conclusion
– At the heart of Object Oriented design
– Design using logical, useful abstractions
– Add abstractions only when required
– Expect having no changes in your code
– Stimulate change (test, iterate)
– Properly refactor code that’s affected by these changes
SOLID Software Design 51
52. Open-Closed Principle
Question: Real world usages of OCP?
– Examples in Java API
– Examples in GoF Design Patterns
– Big abusers
SOLID Software Design 52
53. Liskov Substitution Principle
“If for each object o1 of type S there is an object o2 of
type T such that for all programs P defined in terms of
T, the behavior of P is unchanged when o1 is
substituted for o2 then S is a subtype of T”
– Come again?
SOLID Software Design 53
54. Liskov Substitution Principle
“Subtypes must be substitutable for their base
types”
– Theory
– Simple example
– Real world example
– Considerations
– Conclusion
SOLID Software Design 54
55. Liskov Substitution Principle
Theory
– Polymorphism problem
– A extends B
• This means A IS-A B
• …but is this always true for A and B?
SOLID Software Design 55
57. Liskov Substitution Principle
Simple Example
– Square extends Rectangle
• Square IS-A Rectangle, right?
– Difference between Square and Rectangle
• Rectangle can have different height and width settings
• Square has equal values for both
SOLID Software Design 57
58. Liskov Substitution Principle
Simple Example
– So, this is correct then?
class Rectangle {
private int width; private int height;
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
} // Setters left out for brevity
}
class Square extends Rectangle {
// Initialize as a square
public Square(int size) {
super(size, size);
}
}
SOLID Software Design 58
59. Liskov Substitution Principle
Simple Example
– Suppose we test the Square like this
Square square = new Square(42);
assertEquals(42, square.getWidth()); // Ok
square.setHeight(50);
// Width should be the same as height, and we changed it!
assertEquals(50, square.getWidth()); // Whoops!
– Our square suddenly is a 42 by 50 Rectangle!
SOLID Software Design 59
60. Liskov Substitution Principle
Simple Example
– Fixing is easy, but is this really the way to go?
class Square extends Rectangle {
public void setWidth(int width) {
super.setWidth(width);
super.setHeight(width);
}
public void setHeight(int height) {
super.setHeight(height);
super.setWidth(height);
}
}
SOLID Software Design 60
61. Liskov Substitution Principle
Simple Example
– Maybe better to do this
class Square extends Shape { // Immutable
private final int size;
public Square(int size) {
this.size = size;
}
@Override
public int getHeight() {
return size;
}
@Override
public int getWidth() {
return size;
}
}
SOLID Software Design 61
62. Liskov Substitution Principle
Considerations
– The IS-A relationship not always applies in code
• A square is a rectangle in the real world
• A square is not a rectangle in code – contract breaks
when square doesn’t override rectangle behaviour
– Immutability can make a difference
• public Rectangle(int width, int height);
• public Square(int size);
• If both are immutable, Rectangle really IS-A Square!
SOLID Software Design 62
63. Liskov Substitution Principle
Conclusion
– Rule of thumb
• Instead of: A IS-A B, use: A is substitutable by B
– Inherit from a more abstract supertype if needed
• Rectangle and Square could both inherit from Shape
• Shape should enforce no rules for width and height
– Should you prevent LSP violations at all cost? No.
• What if you only have a method that draws Rectangles
• Will the LSP violation be a problem then?
SOLID Software Design 63
64. Liskov Substitution Principle
Question: Real world usages of LSP?
– Examples in Java API
– Examples in GoF Design Patterns
– Big abusers
SOLID Software Design 64
65. Interface Segregation Principle
“Clients should not be forced to depend on
methods that they do not use”
– Theory
– Simple example
– Real world example
– Considerations
– Conclusion
SOLID Software Design 65
67. Interface Segregation Principle
Simple Example
– Interface definition for a worker doing work
public interface Worker {
public void work();
public void eat();
}
– Implementation for a generic employee
public class Employee implements Worker {
public void work() { // do work stuff }
public void eat() { // eat lunch, keep up strength ;) }
}
SOLID Software Design 67
68. Interface Segregation Principle
Simple Example
– Robots are also part of the business
public class Robot implements Worker {
public void work() { // Work (without union breaks }
public void eat() { // Wait, what? }
}
– But they don’t eat lunch
– Still, eat() has to be implemented
SOLID Software Design 68
69. Interface Segregation Principle
Simple Example
– Split up the interfaces into sensible pieces
public interface NutritionConsumer {
public void eat();
}
public interface Worker {
public void work();
}
SOLID Software Design 69
70. Interface Segregation Principle
Simple Example
– Implement the interfaces as needed
public class Employee implements Worker, NutritionConsumer {
public void work() { }
public void eat() { }
}
public class Robot implements Worker {
public void work() {}
}
SOLID Software Design 70
71. Interface Segregation Principle
Simple Example
– Class dealing with Worker objects
public class WorkloadManager {
public void putWorkerToWork(Worker worker) {
worker.work();
}
}
– Can deal with both robots and employees
– Doesn’t need to be concerned with the nutritional
needs of the Employee type workers
SOLID Software Design 71
72. Interface Segregation Principle
Considerations
– Avoid coupling between interfaces and clients
– Clients should only depend on methods they use
– Separation reduces the risk of changes cascading
to implementing classes that do not have a need
for those methods
SOLID Software Design 72
73. Interface Segregation Principle
Conclusion
– Separate interfaces when it makes sense
– Don’t overdo it!
• Prevent classes having to implement many interfaces
• Prevent one-method interfaces
– Common sense is key (again)
• Split up interfaces as soon as clients show the need to
do so
SOLID Software Design 73
75. Dependency Inversion Principle
“High-level modules should not depend on low-
level modules directly, but through abstraction”
“Abstractions should not depend on details,
details should depend on abstractions”
– Theory
– Simple example
– Real world example
– Considerations
– Conclusion
SOLID Software Design 75
77. Dependency Inversion Principle
Simple Example
– Application that monitors system status
public class SystemStatus {
private HeatGauge gauge;
public void checkTemperature() throws OverheatingException {
if(gauge.actualTemperature() > 55) {
throw new OverheatingException();
}
}
}
SOLID Software Design 77
78. Dependency Inversion Principle
Simple Example
– HeatGauge implementation
public class HeatGauge {
public int actualTemperature() {
// Do some measuring and return the results
}
}
SOLID Software Design 78
79. Dependency Inversion Principle
Simple Example
– Systemstatus directly depends on HeatGauge
– Changes to HeatGauge can affect SystemStatus
public class SystemStatus {
private HeatGauge gauge = new HeatGauge();
public void checkTemperature() throws OverheatingException {
if(gauge.actualTemperature() > 55) {
throw new OverheatingException();
}
}
}
SOLID Software Design 79
80. Dependency Inversion Principle
Simple Example
– Abstract away the dependency
public interface HeatGauge {
public int actualTemperature();
}
public class HeatGaugeImpl implements HeatGauge {
public int actualTemperature() {
// Do some measuring
}
}
SOLID Software Design 80
81. Dependency Inversion Principle
Simple Example
– Use the new abstraction
public class SystemStatus {
// Less dependent by using the interface
private HeatGauge gauge = new GaugeImpl();
public void checkTemperature() throws OverheatingException {
if(gauge.actualTemperature() > 55) {
throw new OverheatingException();
}
}
}
– Better, but not perfect
SOLID Software Design 81
82. Dependency Inversion Principle
Simple Example
– Improving the example
public class SystemStatus {
private HeatGauge heatGauge;
public SystemStatus(HeatGauge heatGauge){
this.heatGauge = heatGauge;
}
public void checkTemperature() throws OverheatingException {
if(heatGauge.actualTemperature() > 55) {
throw new OverheatingException();
}
}
}
– Abstracts away the implementation used to gauge
the temperature
SOLID Software Design 82
83. Dependency Inversion Principle
Considerations
– Clients should ‘own’ the interfaces used to access
low-level modules
– Not the same as Dependency Injection (DI)
• Dependency Inversion
– Using abstractions to achieve loose coupling
– Ownership should be at client level
• Dependency Injection
– Design pattern to implement loose coupling
SOLID Software Design 83
84. Dependency Inversion Principle
Conclusion
– Maybe the most relevant of all SOLID principles
– Allows robust code to be written using
abstractions
– Dependency Inversion
• Relevant when designing functionality
– Dependency Injection
• Relevant when implementing functionality
– Do all classes need an interface? No.
SOLID Software Design 84
85. Dependency Inversion Principle
Question: Real world usages of DIP?
– Examples in Java API
– Examples in GoF Design Patterns
– Big abusers
SOLID Software Design 85
87. Other principles
Not SOLID, but just as important!
– REP: Release reuse Equivalency Principle
– CCD: Common Closure Principle
– CRP: Common Reuse Principle
– ADP: Acyclic Dependencies Principle
– SDP: Stable Dependencies Principle
– SAP: Stable Abstractions Principle
– From the same book as SOLID
SOLID Software Design 87
88. Other principles
Not SOLID, but just as important!
– REP: Release reuse Equivalency Principle
– CCD: Common Closure Principle
– CRP: Common Reuse Principle
– About package cohesion
SOLID Software Design 88
89. Other principles
Not SOLID, but just as important!
– ADP: Acyclic Dependencies Principle
– SDP: Stable Dependencies Principle
– SAP: Stable Abstractions Principle
– About package coupling
SOLID Software Design 89
93. Conclusion
Master the SOLID principles
– Use it in your communications
– Use it to challenge your design/yourself
– Applicable to modules, libraries, components...
– But don’t be dogmatic about it
– Don’t write SOLID, just because you can
– Try to see the disadvantages too!
– Don’t just believe the hype!
SOLID Software Design 93
94. Conclusion
SOLID principles are no hard rules
– Definitely no hard rules!
– Also no goals, just a means to an end
– There are more principles
– Principle of least Knowledge
– Premature optimization is the root of all evil
– Composition over Inheritance
– K.I.S.S. / Y.A.G.N.I.
SOLID Software Design 94
95. Conclusion
Don’t be dogmatic
– Even Uncle Bob said this
– http://blog.objectmentor.com/articles/2009/02/06/on
– In response to
– http://www.joelonsoftware.com/items/2009/01/31.ht
SOLID Software Design 95
Java API: -Examples: -Abusers: Almost every class with Context or Manager in it (javax.faces.FacesContext, javax.persistence.EntityManager, javax.servlet, HttpServletRequest, java.lang.Math, java.util.Collections) GoF Examples: Template Method, Chain of Responsibility, Decorator Abusers:
Java API: -Examples: javax.servlet.Filter, -Abusers: java.lang.String GoF -Examples: Template Method, Chain of Responsibility, Decorator, Abstract Factory, Command -Abusers: Singleton What about Aspect Oriented Programming? Open-Closed Principle on module level
Java API: -Examples: javax.servlet.HttpServlet (interfaces of HttpServletRequest/Response passed in, details are hidden) -Abusers: All static functions GoF -Examples: Strategy, State, Iterator, -Abusers: Spring Framework (Dependency Injection vs. Dependency Inversion)