Design for testabilityStanislav Tyurikov
Design for testability«One reasonable definition of good design is testability. It is hard to imaginea software system tha...
Symptoms of poor design• Rigidity – System is hard to change.• Fragility – Changes causes system to break easily and requi...
Symptoms of good design• Minimal complexity – Avoid making “clever“ designs. Clever designs are usually hard tounderstand....
SOLID design principles• SRP: Single Responsibility Principle – There should never be more than one reasonfor a class to c...
Single Responsibility Principle (SRP)There should never be more than one reason for a class to change.Violation example:pu...
Single Responsibility Principle (SRP)There should never be more than one reason for a class to change.Violation example:Af...
Open/Closed Principle (OCP)Software entities (classes, modules, functions, etc.) should be open forextension, but closed f...
Open/Closed Principle (OCP)Software entities (classes, modules, functions, etc.) should be open forextension, but closed f...
Liskov Substitution Principle (LSP)Functions that use pointers or references to base classes must be able to useobjects of...
Interface Segregation Principle (ISP)Clients should not be forced to depend on methods that they do not use.Violation exam...
Interface Segregation Principle (ISP)Clients should not be forced to depend on methods that they do not use.Violation exam...
Dependency Inversion Principle (DIP)High-level modules should not depend on low-level modules. Both should dependon abstra...
ADKEHFGCBAny OOP designed software is a set of interacting objects.A class instance can have own lifecycle (scope, lifetim...
1) Create it by yourself.2) Ask someone to find/create it:• Locator (for instance)• Factory (for new instance)3) Someone p...
CS1I1 S2TestStubuseimplI2S3TestStubCS1I1 S2TestStubuseimplI2S3TestStubRuntime configuration: Test configuration:Some IoC f...
<?xml version="1.0" encoding="windows-1251"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://w...
Law of Demeter principle (LoD)• Each unit should only use a limited set of other units: only units“closely” related to the...
Law of Demeter violation code exampleclass A{public String getMessage(){return "Message";}}public class Main{public static...
Law of Demeter violation code exampleclass A{public String getMessage(){return "Message";}}public class Main{public static...
Package design principlesCohesion• RREP: Release Reuse Equivalency Principle – The granule of reuse is the granule of rele...
TUF & TUCTUF – Test Unfriendly Features• Database access• File system access• Network access• Access to side effecting API...
GRASP design patterns• Information Expert – A general principal of object design and responsibilityassignment?• Creator – ...
GoF design patternsBehavioralChain of responsibilityCommandInterpreterIteratorMediatorMementoObserverStateStrategyTemplate...
• http://www.oodesign.com/ - Design principles, GoF patterns• http://en.wikipedia.org/wiki/GRASP_%28Object_Oriented_Design...
Upcoming SlideShare
Loading in...5
×

Design for Testability

911

Published on

Some common principles of good OOP design are described in this presentation.

Published in: Technology, Design
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
911
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Design for Testability

  1. 1. Design for testabilityStanislav Tyurikov
  2. 2. Design for testability«One reasonable definition of good design is testability. It is hard to imaginea software system that is both testable and poorly designed. It is also hardto imagine a software system that is well designed but also untestable»Robert C. Martin.Design for testability – is improving quality of software design as wellas possibility to write tests for the code.
  3. 3. Symptoms of poor design• Rigidity – System is hard to change.• Fragility – Changes causes system to break easily and require otherchanges.• Immobility – Difficult to entangle components that can be reused inother systems.• Viscosity – Doing things right is harder than doing things wrong.• Needless Complexity – System contains infrastructure that has nodirect benefit.• Needless Repetition – Repeated structures that should have asingle abstraction.• Opacity – Code is hard to understand.
  4. 4. Symptoms of good design• Minimal complexity – Avoid making “clever“ designs. Clever designs are usually hard tounderstand. Keep it simple.• Ease of maintenance – it is easy to understand and make changes.• Loose coupling – Loose coupling means designing so that you hold connections among differentparts of a program to a minimum.• Extensibility – You should be able to change a piece of the system without causing a huge impact toother pieces of the system.• Reusability – less of code duplication, it can be reused in other systems.• High fan-in – Refers to having a high number of classes that use a given class. High fan-in impliesthat a system has been designed to make good use of utility classes at the lower levels in the system.• Low-to-medium fan-out – a given class should use a low-to-medium number of other classes. Highfan-out (more than about seven) indicates a class uses a large number of other classes and may beoverly complex.• Portability – program can be run on lot of computers without complex configuration.• Leanness – no redundant modules/classes/functionalities.• Stratification – try to keep the levels of decomposition stratified so you can view the system at anysingle level without dipping into other levels.• Standard techniques – Give the whole system a familiar feeling by using standardized, commonapproaches.
  5. 5. SOLID design principles• SRP: Single Responsibility Principle – There should never be more than one reasonfor a class to change.• OCP: Open/Closed Principle – Software entities (classes, modules, functions, etc.)should be open for extension, but closed for modification.• LSP: Liskov Substitution Principle – Functions that use pointers or references tobase classes must be able to use objects of derived classes without knowing it.• ISP: Interface Segregation Principle – Clients should not be forced to depend onmethods that they do not use.• DIP: Dependency Inversion Principle – High-level modules should not depend onlow-level modules. Both should depend on abstractions. Abstractions should notdepend on details. Details should depend on abstractions.
  6. 6. Single Responsibility Principle (SRP)There should never be more than one reason for a class to change.Violation example:public class EntityFactory implements IEntityFactory{private Map<String, String> loadPropertiesFromFile(String fileName){...}@Overridepublic Entity createEntity(){final Map<String, String> properties = loadPropertiesFromFile("entity.properties");return new Entity(properties.get("name"));}}
  7. 7. Single Responsibility Principle (SRP)There should never be more than one reason for a class to change.Violation example:After refactoring:public class EntityFactory implements IEntityFactory{private Map<String, String> loadPropertiesFromFile(String fileName){...}@Overridepublic Entity createEntity(){final Map<String, String> properties = loadPropertiesFromFile("entity.properties");return new Entity(properties.get("name"));}}public class EntityFactory implements IEntityFactory{@Overridepublic Entity createEntity(final Map<String, String> properties){if (properties == null) {throw new IllegalArgumentException("Properties must not be null");}return new Entity(properties.get("name"));}}
  8. 8. Open/Closed Principle (OCP)Software entities (classes, modules, functions, etc.) should be open forextension, but closed for modification.Violation example:public interface BeanSearcher {public Bean findById(Long id);}public interface BeanSearcher {public Bean findById(Long id);public Bean findByName(String name);}extension
  9. 9. Open/Closed Principle (OCP)Software entities (classes, modules, functions, etc.) should be open forextension, but closed for modification.Violation example:After refactoring:public interface BeanSearcher {public Bean findById(Long id);}public interface BeanSearcher {public Bean findByQuery(SearchQuery query);}public class IdSearchQuery extends SearchQuery {}public class NameSearchQuery extends SearchQuery {}public interface BeanSearcher {public Bean findById(Long id);public Bean findByName(String name);}extension
  10. 10. Liskov Substitution Principle (LSP)Functions that use pointers or references to base classes must be able to useobjects of derived classes without knowing it.Violation example:class Rectangle{protected int width;protected int height;public void setWidth(int w){this.width = w;}public void setHeight(int h){this.height = h;}public int calculateRectangleArea(){return width * height;}}class Square extends Rectangle{@Overridepublic void setWidth(int w){this.width = w;this.height = w;}@Overridepublic void setHeight(int h){this.width = h;this.height = h;}}private Rectangle rectangle = new Square();@Testpublic void rectangle(){rectangle.setHeight(2);rectangle.setWidth(3);Assert.assertEquals(rectangle.calculateRectangleArea(), 6);}
  11. 11. Interface Segregation Principle (ISP)Clients should not be forced to depend on methods that they do not use.Violation example:interface ProcessListener{public void onProcessStart(Process p);public void onProcessEnd(Process p);}class NewProcessRegistrator implements ProcessListener{public void onProcessStart(Process p){registerProcess(p);}public void onProcessEnd(Process p){// nothing to do.}…}
  12. 12. Interface Segregation Principle (ISP)Clients should not be forced to depend on methods that they do not use.Violation example:interface ProcessListener{public void onProcessStart(Process p);public void onProcessEnd(Process p);}class NewProcessRegistrator implements ProcessListener{public void onProcessStart(Process p){registerProcess(p);}public void onProcessEnd(Process p){// nothing to do.}…}interface ProcessStartupListener{public void onProcessStart(Process p);}interface ProcessShutdownListener{public void onProcessEnd(Process p);}interface ProcessListener extendsProcessStartupListener, ProcessShutdownListener{}class NewProcessRegistrator implements ProcessStartupListener{public void onProcessStart(Process p){registerProcess(p);}…}refactoring
  13. 13. Dependency Inversion Principle (DIP)High-level modules should not depend on low-level modules. Both should dependon abstractions. Abstractions should not depend on details. Details should dependon abstractions.Violation example:• Direct instantiation: new SomeObject();• Static methods: ServiceLocator.getObject();• Interface contains field on a class: interface A { final Service SERVICE = new Service(); }CICCIIICdepends dependsdepends depends
  14. 14. ADKEHFGCBAny OOP designed software is a set of interacting objects.A class instance can have own lifecycle (scope, lifetime).The problems are:• Who should take care about instance creation and lifecycle?• How to share one service instance between many others?• How to reuse classes in deferent environment ?useuseuseuseuseInversion Of Control and Dependency Injection
  15. 15. 1) Create it by yourself.2) Ask someone to find/create it:• Locator (for instance)• Factory (for new instance)3) Someone puts it to you. («Don’t call us. We’ll call you.»)A Buse// direct instantiation.class A {private B b = new B();public void doSomething() {b.someCall();}}// Ask locator for componentclass A {private B b = Locator.getB();public void doSomething() {b.someCall();}}// Create component with// factoryclass A {private B b =Factory.createB();public void doSomething() {b.someCall();}}// Someone puts componentclass A {private B b;public A(B b) {this.b = b;}public void doSomething() {b.someCall();}}Inversion Of Control and Dependency Injection
  16. 16. CS1I1 S2TestStubuseimplI2S3TestStubCS1I1 S2TestStubuseimplI2S3TestStubRuntime configuration: Test configuration:Some IoC frameworks (for example Spring) make possible to change dependencyconfiguration without any code modification.Inversion Of Control and Dependency Injection
  17. 17. <?xml version="1.0" encoding="windows-1251"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><bean id="service1" class="com.mycompany.springexample.services.ServiceImpl1" /><bean id="service2" class="com.mycompany.springexample.services.ServiceImpl2" /><bean id="client1" class="com.mycompany.springexample.client.Client" ><property name="service1" ref="service1" /><property name="service2" ref="service2" /></bean></beans><?xml version="1.0" encoding="windows-1251"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><bean id="service1" class="com.mycompany.springexample.services.stub.ServiceStub1" /><bean id="service2" class="com.mycompany.springexample.services.stub.ServiceStub2" /><bean id="client1" class="com.mycompany.springexample.client.Client" ><property name="service1" ref=“service1" /><property name="service2" ref=“service2" /></bean></beans>Runtime ConfigurationTest ConfigurationBeans linkage definition
  18. 18. Law of Demeter principle (LoD)• Each unit should only use a limited set of other units: only units“closely” related to the current unit.• “Each unit should only talk to its friends. Don’t talk to strangers.”Main Motivation: Control information overload. We can only keep alimited set of items in short-term memory.Benefits: Loosely coupled classes.LoD violation example:A B C A MB CDA knows B’s dependencies A knowsM’s inner structure
  19. 19. Law of Demeter violation code exampleclass A{public String getMessage(){return "Message";}}public class Main{public static void main(String[] args){new B().printMessage(new A());}}class B{public void printMessage(A a){System.out.println(a.getMessage());}}
  20. 20. Law of Demeter violation code exampleclass A{public String getMessage(){return "Message";}}public class Main{public static void main(String[] args){new B().printMessage(new A());}}refactoringclass B{public void printMessage(A a){System.out.println(a.getMessage());}}public class Main{public static void main(String[] args){A a = new A();String message = a.getMessage();new B().printMessage(message);}}class B{public void printMessage(String message){System.out.println(message);}}
  21. 21. Package design principlesCohesion• RREP: Release Reuse Equivalency Principle – The granule of reuse is the granule of release.Only components that are released through a tracking system can be effectively reused. Thisgranule is the package.• CCP: Common Closure Principle – The classes in a package should be closed together againstthe same kinds of changes. A change that affects a package affects all the classes in thatpackage.• CRP: Common Reuse Principle – The classes in a package are reused together. If you reuseone of the classes in a package, you reuse them all.Coupling• ADP: Acyclic Dependencies Principle – The dependency structure between packages must bea directed acyclic graph (DAG). That is, there must be no cycles in the dependency structure.• SDP: Stable Dependencies Principle – The dependencies between packages in a design shouldbe in the direction of the stability of the packages. A package should only depend uponpackages that are more stable that it is.• SAP: Stable Abstractions Principle – Packages that are maximally stable should be maximallyabstract. Instable packages should be concrete. The abstraction of a package should be inproportion to its stability.
  22. 22. TUF & TUCTUF – Test Unfriendly Features• Database access• File system access• Network access• Access to side effecting APIs (GUI, etc)• Lengthy computations• Inscrutable computations(computations which are hard to testbecause they are difficult to understand)• Static variable usageNever hide a TUF within a TUCTUC – Test Unfriendly Constructs• Final Methods• Final Classes• Static Methods• Private Methods• Static Initialization Expressions• Static Initialization Blocks• Constructors• Object Initialization Blocks• New‐Expressions
  23. 23. GRASP design patterns• Information Expert – A general principal of object design and responsibilityassignment?• Creator – Who creates?• Controller – What first object beyond the UI layer receives and coordinates asystem operation?• Low Coupling – How to reduce the impact of change?• High Cohesion – How to keep objects focused, understandable, and manageable?• Polymorphism – Who is responsible when behavior varies by type?• Pure Fabrication – Who is responsible when you are desperate, and do not want toviolate high cohesion and low coupling?• Indirection – How to assign responsibilities to avoid direct coupling?• Protected Variations – How to assign responsibilities so that the variations orinstability in the elements do not have an undesirable impact on other elements?
  24. 24. GoF design patternsBehavioralChain of responsibilityCommandInterpreterIteratorMediatorMementoObserverStateStrategyTemplate methodVisitorCreationalAbstract factoryBuilderFactory methodPrototypeSingletonStructuralAdapterBridgeCompositeDecoratorFacadeFlyweightProxy
  25. 25. • http://www.oodesign.com/ - Design principles, GoF patterns• http://en.wikipedia.org/wiki/GRASP_%28Object_Oriented_Design%29 – GRASP patterns.• http://www.c2.com/cgi/wiki?LawOfDemeter – Law Of Demeter description.• Working Effectively with Legacy Code; Michael Feathers, 2006.• Clean Code: A Handbook of Agile Software Craftsmanship; Robert C. Martin, 2008• Agile Software Development, Principles, Patterns, and Practices; Robert C. MartinAdditional Information

×