SlideShare une entreprise Scribd logo
1  sur  52
Télécharger pour lire hors ligne
SOLID
In the heart of OO design
Who is on the scene



                     Eduards Sizovs
            linkedin.com/in/eduardsi
Agenda
•   Introduction
•   SRP
•   OCP
•   LSP
•   ISP
•   DIP
•   Q&A
SOLID

                •   SRP   The Single Responsibility
                •   OCP   Principle
                •   LSP   The Open Closed Principle
                •   ISP   The Liskov Substitution Principle
                •   DIP   The Interface Segregation
                          Principle
Robert Martin
                          The Dependency Inversion
                          Principle
SRP
The Single Responsibility
       Principle
Definition


Class   should    have    only   one
responsibility and only one reason to
change

                                                    Robert Martin
       http://www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfO
                                                               od
Rationale

          Just because you can,
          does not mean you
          should.




We want systems of many small, simple,
cohesive classes with clear purpose.
Milka cow violates SRP – it’s both
cow & advertisement.
In quest of responsibility
Ask yourself:
•   What concept does the class represent?
•   What does the class do?
•   What causes the class to change?
•   For existing classes: is class X responsible for doing
    Z?

Answer must be one-liner.
Violation symptoms
• Managers, Services, Facades…
• Long lists of variables, dependencies, methods,
  arguments
• Problematic unit-testing (e.g. when you need Spies)
• Different levels of abstractions inside a class
• A lot of details to tackle, implicitness
Overloaded responsibilities
interface JsonService {                     public class TaxCalculator {
   Json marshall(Object object);              @Autowired
   Object unmarshall(Json json);              private EmployeeRepository employeeRepository;
   void prettyPrint();
   void validate(Json json, Wadl wadl);        Tax calculate(Id employeeId) {
}                                                Employee employee =
                                            employeeRepository.findBy(employeeId);
                                                 return calculate(employee);
                                               }
                                            }
class FooValidator {                        class User {
   void validate(Foo foo) {                    public User(Registration registration) {
     if (foo.isSuitableForValidation()) {        this.email = registration.getEmail();
         // actual validation                    this.firstName = registration.getFirstName();
     }                                           this.lastName = registration.getLastName();
   }                                           }
}                                              public User(Invitation invitation) {
                                                 …
                                               }
                                            }
OCP
The Open Closed Principle
Definition


Software entities (classes, modules,
functions etc.) should be open for
extension, but closed for modification.



                                                  Robert Martin
           http://www.objectmentor.com/resources/articles/ocp.pdf
Rationale
Brain surgery is not
necessary when putting
on a hat.
Example – Interceptors [ 1 ]
com.ocp.mvc;                                             com.ocp.mvc.extensions;
class InterceptorRegistry {                              public class SecurityInterceptor {
   @Autowired                                              void intercept(WebRequest request) { ... }
                                                         }
   private WebApplication webapp;
                                                         public class CachingInterceptor {
    @Autowired                                             void intercept(WebRequest request) { ... }
    private SecurityInterceptor securityInterceptor;     }


    @Autowired
    private CachingInterceptor cachingInterceptor;

    @PostConstruct
    public void register() {
      webapp.registerInterceptor(securityInterceptor);
      webapp.registerInterceptor(cachingInterceptor);
    }
}

                                            • InterceptorRegistry disrespects
                                              OCP
                                            • Implementations cannot be hidden
Example – Interceptors [ 2 ]
com.ocp.mvc;                                        com.ocp.mvc.extensions;
class InterceptorRegistry {                         class SecurityInterceptor implements Interceptor {
   @Autowired                                          void intercept(WebRequest request) { ... }
                                                    }
   private WebApplication webapp;
                                                    class CachingInterceptor implements Interceptor {
    @Autowired                                         void intercept(WebRequest request) { ... }
    private Collection<Interceptor> interceptors;   }


    @PostConstruct
    public void register() {
      webapp.registerInterceptors(interceptors);
    }
}

interface Interceptor {
   void intercept(WebRequest request);
}
                                        • InterceptorRegistry respects
                                          OCP
                                        • Interceptors are hidden
                                        • Dependency direction has
Example – Interceptors [ 3 ]
 com.ocp.mvc;                                          com.ocp.mvc.extensions;
 public class InterceptorRegistry {                    class SecurityInterceptor implements Interceptor {
   @Autowired                                             @Autowired
                                                          private InterceptorRegistry interceptorRegistry;
   private WebApplication webapp;
                                                            @PostConstruct
     public void register(Interceptor interceptor) {        void register() {
       webapp.registerInterceptor(interceptor);               interceptorRegistry.register(this);
     }                                                     }
 }                                                         void intercept(WebRequest request) { ... }
                                                       }
 interface Interceptor {
    void intercept(WebRequest request);                class CachingInterceptor implements Interceptor {
 }                                                        @Autowired
                                                          private InterceptorRegistry interceptorRegistry;

                                                            @PostConstruct
                                                            void register() {
                                                              interceptorRegistry.register(this);
• Interceptors violate SRP?                                }


• InterceptorRegistry exposed
                                                           void intercept(WebRequest request) { ... }
                                                       }
Example – NotificationService [
                1]
class NotificationService {                                     class SmsNotifier {
   @Autowired                                                      void notify(Notification notification) { … }
   SmsNotifier smsNotifier;                                     }

    @Autowired                                                  class EmailNotifier {
    EmailNotifier emailNotifier;                                   notify(Notification notification) { … }
                                                                }
    void notify(Notification notification) {
      if (notification.getType() == NotificationType.Sms) {
           smsNotifier.notify(notification);
      }
      if (notification.getType() == NotificationType.Email) {
          emailNotifier.notify(notification);
      }
    }
}
Example – NotificationService [
              2]
interface Notifier {                                             class SmsNotifier implements Notifier {
   void notify(Notification notification) { … }                     void notify(Notification notification) { … }
   boolean isApplicableFor(NotificationType                         boolean isApplicableFor(NotificationType
notificaionType);                                                notificationType) {
}                                                                     return notification.getType() ==
                                                                 NotificationType.Sms;
class NotificationService {                                         }
   @Autowired                                                    }
   Collection<Notifier> notifiers;
                                                                 class EmailNotifier implements Notifier {
  void notify(Notification notification) {                          notify(Notification notification) { … }
    Notifier notifier = findApplicableNotifier(notification);       boolean isApplicableFor(NotificationType
    notifier.notify(notification);                               notificationType) {
  }                                                                   return notification.getType() ==
                                                                 NotificationType.Email;
                                                                    }
  private Notifier findApplicableNotifier(Notifier notifier) {
                                                                 }
     for (Notifier notifier : notifiers) {
         if (notifier.isApplicableFor(notification)) { return
notifier; }
      }
      …
  }
}
Example – Repository
interface EntityRepository {        interface EntityRepository {   interface By {
   Entity findByName(String);          Entity find(By);            }
   Entity findByPage(Page);         }
                                                                   class ByName implements By {
   Entity findById(Id);
                                                                      public ByName(String name) { … }
   Entity findByVersion(Version);                                  }
}
                                                                   class ByPage implements By {
                                                                      public ByPage(Page page) { … }
                                                                   }

                                                                   class ById implements By {
                                                                      public ById(Id id) { … }
                                                                   }

                                                                   class ByVersion implements By {
                                                                      public ByVersion(Version version) { … }
                                                                   }
LSP
The Liskov Substitution Principle
Definitions


The LSP specifies that functions that use
pointers of references to base classes
must be able to use objects of derived
classes without knowing it.



                                                   Robert Martin
            http://www.objectmentor.com/resources/articles/lsp.pdf
Syntactical conformance is not enough! It’s all
about semantics:

• Pre-conditions (can’t strengthen, can weaken)
• Post-conditions (can’t weaken, can strengthen)
• Preserved supertype’s invariants
Strengthening pre-conditions
interface FileReader {                  class OpenFileReader implements FileReader {
  @FileStateAgnostic                       public void read(File file) {
   void read(File file);
}                                       Preconditions.checkArgument(file.isOpen());
                                          }
class Client {                          }
   @Autowired
   void doIt(FileReader fileReader) {
     File file = getFile();
     fileReader.read(file);
   }
}
Weakening pre-conditions
class FileReader {                            class SmartFileReader extends FileReader {
  @CheckIsOpen                                   public void read(File file) {
   void read(File file) {                          …
                                                 }
Preconditions.checkArgument(file.isOpen());   }
  }
}

class Client {
   @Autowired
   void doIt(FileReader fileReader) {
     File file = getFileAndEnsureOpen();
     fileReader.read(file);
   }
}
Weakening post-conditions
interface Collection {                     class Queue implements Collection {
   @DecreasesSizeOfCollectionBy(1)            @RetainsItemIfQueueIsBusy
   void remove(Item item);                    public void remove(Item item) { … }
   boolean isEmpty();                         public boolean isEmpty() { … }
}                                          }

class Client {
   void cleanUp(Collection collection) {
     while(!collection.isEmpty()) {

collection.remove(collection.anyItem());
     }
  }
}
Strengthening post-conditions
interface Collection {                     class Queue implements Collection {
   @DecreasesSizeOfCollectionBy(1)            @RemovesHead
   void removeItem();                         public void removeItem() { … }
   boolean isEmpty();                         public boolean isEmpty() { … }
}                                          }

class Client {
   void cleanUp(Collection collection) {
     while(!collection.isEmpty()) {
        collection.removeItem();
     }
   }
}
Breaking class’ invariants
class Money {                          class Euro extends Money {
   protected BigDecimal amount;           // Does not defend invariants…
                                          public void setAmount(BigDecimal amount) {
     @NonNegative                            this.amount = amount;
     public BigDecimal getAmount() {      }
       return amount;                  }
    }
}
Communicating contract

• Self-descriptive names (e.g.
  doIfSomething());
• Meta-annotations
     • JSR 305 ( @Nullable @CheckForNull, @Immutable … )
     • Guava ( @VisibleForTesting )
     • Custom
• Executable specifications
     • Unit tests + Story Teller (storyteller.socosomi.com)
•   JavaDocs
•   Assertions
Violation indicators

• Modification of existing code on new
  subtype
• Unnatural class hierarchies
• Funny restrictions (do not use this class
  if…)
• instanceof, if, switch …
• InvalidOperationException() or similar
ISP
The Interface Segregation
         Principle
Definitions

No client should be forced to depend
on methods it does not use.


Many client specific interfaces are
better than one general purpose
interface.
                                        Robert Martin
                    Agile Software Development, 2002
Less FAT



FAT
interfaces
 • Are not cohesive
 • Violate SRP
 • Force implementations to violate SRP
 • Suffer from high afferent/efferent coupling
Flexible layering
                                                                            interface RegistrationSettings {
                                             com.4finance.cola.client           int getMaxAttempts();
                                                                            }
                                                                            interface BonusSettings {
com.4finance.cola.product                  com.4finance.cola.client.bonus        BonusAmount getBonusAmount();
                                                                            }
                                                                            interface SolvencySettings {
interface ProductSettings {              com.4finance.cola.client.solvency      Income getMinIncomeForSubmission();
   int getMaxRegistrationAttempts();
                                                                            }
   BonusAmount getBonusAmount();
   Income getMinIncomeForSubmission();
}



 Consider
    • Impact of change
    • Dependency management
Extensibility
                                                      interface JsonMarshaller {
                                                         Json marshall(Object object);
interface JsonService {                               }
   Json marshall(Object json);
   Object unmarshall(Json json);                      interface JsonUnmarshaller {
   ValidationResult validate(Json json, Wadl wadl);
                                                         Object unmarshall(Json json);
   void prettyPrint(Json json);
                                                      }
}

                                                      interface JsonValidator {
                                                         ValidationResult validate(Json json, Wadl wadl);
                                                      }
 Consider                                             interface JsonPrettyPrinter {

    •     Creating an adapter                         }
                                                         void prettyPrint(Json json);


    •     Creating a test double
    •     Creating an alternative implementation
    •     Creating Special Case (NoOp, Null Object)
Lower coupling
          interface JsonService {                           class JsonServiceImpl implements JsonService {
             Json marshall(Object json);                           …
             Object unmarshall(Json json);                  }
             ValidationResult validate(Json json, Wadl wadl);
             void prettyPrint(Json json);
          }
                                                    Pretty printing        Validation      (Un)marshalling




Consider
• High afferent coupling: all clients relying on
  particular Json functionality are coupled with
  Wadl.
• High efferent coupling: JsonService
  implementation will violate SRP as it relies on all
  dependencies required for fulfilling the contract.
Understandability
interface EventPublisher {               interface EventPublisher {
       void publish();                          void publish();
       void setJsonService(JsonService          void setJsonMarshaller(JsonMarshaller
jsonService);                            jsonMarshaller);
}                                        }




Consider
 • When JsonService is set, you need to dive into
   EventPublisher implementor’s details in order to
   understand what parts of it are in use.
Example – PageRouter
interface PageRouter {                            interface PageRouter{
       Route getRouteToProfile();                        Route getRoute();
       Route getRouteToRegistration();            }
}
                                                  interface ProfilePageRouter extends PageRouter {
class DefaultPageRouter implements PageRouter {   }
       …
}                                                 interface RegistrationPageRouter extends PageRounter {
                                                  }
class RuPageRouter {
       // RU overrides both routes                class DefaultProfilePageRouter implements ProfilePageRounter
}                                                 {
                                                  }
                                                  …

Consider
 • What if alternative implementation appeared that
   overrides only one route?
DIP
The Dependency Inversion
       Principle
Definition

High-level modules should not depend
on low-level modules. Both should
depend on abstractions.

                                                 Robert Martin
          http://www.objectmentor.com/resources/articles/dip.pdf
<< interface >>
                                             AS ervice

    Component A                  Component A


                                          << interface >>
                                             BS vice
                                                er


    Component B                  Component B




    Component C                  Component C



A directly depends on B in order to realize its
potential.
A defines external needs with interfaces it owns.
B indirectly satisfies needs of A by implementing
them.
Increasing reuse

      1                    2               3

  Widgets              Widgets         Widgets
  DatePicker           DatePicker      DatePicker


                                     DateFormatter

Loans System         Loans System
DateTimeUtils        DateFormatter
                                     Loans System

                     DateTimeUtils   DateTimeUtils
DwA != DI


In true Dependency Inversion, high-level
      module owns the abstraction.
Tangle elimination
Tangle elimination


                                           com.isp.client

         com.isp.client
                                              Client

            Client
                                       com.isp.client.salary

     com.isp.client.salary        Salary            Experience
Salary         SalaryCalculator

                                                 SalaryCalculator
Some code
package com.system;                                 package com.system;
@Configuration                                      interface ScanPackages {
@ComponentScan(“com.system”)                           String[] get();
class HibernateConfiguration {                      }
   @Autowired
   private Collection<ScanPackages> scanPackages;   package com.system;
                                                    @Component
    @Bean                                           class DefaultScanPackages implements ScanPackages {
    public SessionFactory createInstance() {           public String[] get() {
      return new LocalSessionFactoryBean()               return new String[] { “com.system.model” };
         .setPackagesToScan(scanPackages())            }
         .newSessionFactory();                      }
    }

    private String[] scanPackages() {
                                                    package com.system.subsystem
       // iterate over “scanPackages”               @Component
       // and aggregate String[] array              class SubsystemScanPackages implements ScanPackages {
    }                                                  public String[] get() {
}                                                        return new String[] { “com.system.sub.model };
                                                       }
                                                    }
You did it.
But… Why care?


SOLID contribute to clean code. Writing clean
code is what you must do in order to call
yourself a professional. There is no
reasonable excuse for doing anything less
than your best.
SOLID
cv@4finance.l
     v
More
Q&A

Contenu connexe

Tendances

Java Deserialization Vulnerabilities - The Forgotten Bug Class
Java Deserialization Vulnerabilities - The Forgotten Bug ClassJava Deserialization Vulnerabilities - The Forgotten Bug Class
Java Deserialization Vulnerabilities - The Forgotten Bug ClassCODE WHITE GmbH
 
Making Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVMMaking Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVMRafael Winterhalter
 
Bytecode manipulation with Javassist and ASM
Bytecode manipulation with Javassist and ASMBytecode manipulation with Javassist and ASM
Bytecode manipulation with Javassist and ASMashleypuls
 
Ow2 Utilities - The Swiss Army Knife Of Ow2 Projects
Ow2 Utilities - The Swiss Army Knife Of Ow2 ProjectsOw2 Utilities - The Swiss Army Knife Of Ow2 Projects
Ow2 Utilities - The Swiss Army Knife Of Ow2 ProjectsGuillaume Sauthier
 
Java Concurrency Gotchas
Java Concurrency GotchasJava Concurrency Gotchas
Java Concurrency GotchasAlex Miller
 
UNICORN: A Unified Approach for Localizing Non-deadlock Concurrency Bugs
UNICORN: A Unified Approach for Localizing Non-deadlock Concurrency BugsUNICORN: A Unified Approach for Localizing Non-deadlock Concurrency Bugs
UNICORN: A Unified Approach for Localizing Non-deadlock Concurrency BugsSangmin Park
 
10 Typical Enterprise Java Problems
10 Typical Enterprise Java Problems10 Typical Enterprise Java Problems
10 Typical Enterprise Java ProblemsEberhard Wolff
 
A Brief History of UniRx/UniTask, IUniTaskSource in Depth
A Brief History of UniRx/UniTask, IUniTaskSource in DepthA Brief History of UniRx/UniTask, IUniTaskSource in Depth
A Brief History of UniRx/UniTask, IUniTaskSource in DepthYoshifumi Kawai
 
Java Concurrency Gotchas
Java Concurrency GotchasJava Concurrency Gotchas
Java Concurrency GotchasAlex Miller
 
Java Deserialization Vulnerabilities - The Forgotten Bug Class (RuhrSec Edition)
Java Deserialization Vulnerabilities - The Forgotten Bug Class (RuhrSec Edition)Java Deserialization Vulnerabilities - The Forgotten Bug Class (RuhrSec Edition)
Java Deserialization Vulnerabilities - The Forgotten Bug Class (RuhrSec Edition)CODE WHITE GmbH
 
Black Hat EU 2010 - Attacking Java Serialized Communication
Black Hat EU 2010 - Attacking Java Serialized CommunicationBlack Hat EU 2010 - Attacking Java Serialized Communication
Black Hat EU 2010 - Attacking Java Serialized Communicationmsaindane
 
Dalvik Source Code Reading
Dalvik Source Code ReadingDalvik Source Code Reading
Dalvik Source Code Readingkishima7
 
Java and OpenJDK: disecting the ecosystem
Java and OpenJDK: disecting the ecosystemJava and OpenJDK: disecting the ecosystem
Java and OpenJDK: disecting the ecosystemRafael Winterhalter
 
Common mistakes in android development
Common mistakes in android developmentCommon mistakes in android development
Common mistakes in android developmentHoang Nguyen Huu
 
The definitive guide to java agents
The definitive guide to java agentsThe definitive guide to java agents
The definitive guide to java agentsRafael Winterhalter
 
From C++ to Objective-C
From C++ to Objective-CFrom C++ to Objective-C
From C++ to Objective-Ccorehard_by
 
Java Concurrency Idioms
Java Concurrency IdiomsJava Concurrency Idioms
Java Concurrency IdiomsAlex Miller
 

Tendances (20)

Java Deserialization Vulnerabilities - The Forgotten Bug Class
Java Deserialization Vulnerabilities - The Forgotten Bug ClassJava Deserialization Vulnerabilities - The Forgotten Bug Class
Java Deserialization Vulnerabilities - The Forgotten Bug Class
 
Making Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVMMaking Java more dynamic: runtime code generation for the JVM
Making Java more dynamic: runtime code generation for the JVM
 
Bytecode manipulation with Javassist and ASM
Bytecode manipulation with Javassist and ASMBytecode manipulation with Javassist and ASM
Bytecode manipulation with Javassist and ASM
 
Ow2 Utilities - The Swiss Army Knife Of Ow2 Projects
Ow2 Utilities - The Swiss Army Knife Of Ow2 ProjectsOw2 Utilities - The Swiss Army Knife Of Ow2 Projects
Ow2 Utilities - The Swiss Army Knife Of Ow2 Projects
 
Java Concurrency Gotchas
Java Concurrency GotchasJava Concurrency Gotchas
Java Concurrency Gotchas
 
UNICORN: A Unified Approach for Localizing Non-deadlock Concurrency Bugs
UNICORN: A Unified Approach for Localizing Non-deadlock Concurrency BugsUNICORN: A Unified Approach for Localizing Non-deadlock Concurrency Bugs
UNICORN: A Unified Approach for Localizing Non-deadlock Concurrency Bugs
 
Java 10, Java 11 and beyond
Java 10, Java 11 and beyondJava 10, Java 11 and beyond
Java 10, Java 11 and beyond
 
Java exception handling
Java exception handlingJava exception handling
Java exception handling
 
10 Typical Enterprise Java Problems
10 Typical Enterprise Java Problems10 Typical Enterprise Java Problems
10 Typical Enterprise Java Problems
 
A Brief History of UniRx/UniTask, IUniTaskSource in Depth
A Brief History of UniRx/UniTask, IUniTaskSource in DepthA Brief History of UniRx/UniTask, IUniTaskSource in Depth
A Brief History of UniRx/UniTask, IUniTaskSource in Depth
 
Java Concurrency Gotchas
Java Concurrency GotchasJava Concurrency Gotchas
Java Concurrency Gotchas
 
Java Deserialization Vulnerabilities - The Forgotten Bug Class (RuhrSec Edition)
Java Deserialization Vulnerabilities - The Forgotten Bug Class (RuhrSec Edition)Java Deserialization Vulnerabilities - The Forgotten Bug Class (RuhrSec Edition)
Java Deserialization Vulnerabilities - The Forgotten Bug Class (RuhrSec Edition)
 
Black Hat EU 2010 - Attacking Java Serialized Communication
Black Hat EU 2010 - Attacking Java Serialized CommunicationBlack Hat EU 2010 - Attacking Java Serialized Communication
Black Hat EU 2010 - Attacking Java Serialized Communication
 
Dalvik Source Code Reading
Dalvik Source Code ReadingDalvik Source Code Reading
Dalvik Source Code Reading
 
Java and OpenJDK: disecting the ecosystem
Java and OpenJDK: disecting the ecosystemJava and OpenJDK: disecting the ecosystem
Java and OpenJDK: disecting the ecosystem
 
Common mistakes in android development
Common mistakes in android developmentCommon mistakes in android development
Common mistakes in android development
 
The definitive guide to java agents
The definitive guide to java agentsThe definitive guide to java agents
The definitive guide to java agents
 
From C++ to Objective-C
From C++ to Objective-CFrom C++ to Objective-C
From C++ to Objective-C
 
Java Concurrency
Java ConcurrencyJava Concurrency
Java Concurrency
 
Java Concurrency Idioms
Java Concurrency IdiomsJava Concurrency Idioms
Java Concurrency Idioms
 

En vedette

Domain Driven Design - DDDSydney 2011
Domain Driven Design - DDDSydney 2011Domain Driven Design - DDDSydney 2011
Domain Driven Design - DDDSydney 2011thinkddd
 
Introducción a DDD
Introducción a DDDIntroducción a DDD
Introducción a DDDsergiopolo
 
A Practical Guide to Domain Driven Design: Presentation Slides
A Practical Guide to Domain Driven Design: Presentation SlidesA Practical Guide to Domain Driven Design: Presentation Slides
A Practical Guide to Domain Driven Design: Presentation Slidesthinkddd
 
Domain Driven Design using Laravel
Domain Driven Design using LaravelDomain Driven Design using Laravel
Domain Driven Design using Laravelwajrcs
 

En vedette (6)

Introduction to DDD
Introduction to DDDIntroduction to DDD
Introduction to DDD
 
Domain Driven Design - DDDSydney 2011
Domain Driven Design - DDDSydney 2011Domain Driven Design - DDDSydney 2011
Domain Driven Design - DDDSydney 2011
 
Introducción a DDD
Introducción a DDDIntroducción a DDD
Introducción a DDD
 
A Practical Guide to Domain Driven Design: Presentation Slides
A Practical Guide to Domain Driven Design: Presentation SlidesA Practical Guide to Domain Driven Design: Presentation Slides
A Practical Guide to Domain Driven Design: Presentation Slides
 
Domain Driven Design 101
Domain Driven Design 101Domain Driven Design 101
Domain Driven Design 101
 
Domain Driven Design using Laravel
Domain Driven Design using LaravelDomain Driven Design using Laravel
Domain Driven Design using Laravel
 

Similaire à SOLID

Testable JavaScript: Application Architecture
Testable JavaScript:  Application ArchitectureTestable JavaScript:  Application Architecture
Testable JavaScript: Application ArchitectureMark Trostler
 
Spring training
Spring trainingSpring training
Spring trainingTechFerry
 
Implement Service Broker with Spring Boot #cf_tokyo
Implement Service Broker with Spring Boot #cf_tokyoImplement Service Broker with Spring Boot #cf_tokyo
Implement Service Broker with Spring Boot #cf_tokyoToshiaki Maki
 
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to MissJava Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to MissAndres Almiray
 
Paradigmas de linguagens de programacao - aula#9
Paradigmas de linguagens de programacao - aula#9Paradigmas de linguagens de programacao - aula#9
Paradigmas de linguagens de programacao - aula#9Ismar Silveira
 
Servletand sessiontracking
Servletand sessiontrackingServletand sessiontracking
Servletand sessiontrackingvamsi krishna
 
OpenWebBeans and DeltaSpike at ApacheCon
OpenWebBeans and DeltaSpike at ApacheConOpenWebBeans and DeltaSpike at ApacheCon
OpenWebBeans and DeltaSpike at ApacheConos890
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotationjavatwo2011
 
Testing in android
Testing in androidTesting in android
Testing in androidjtrindade
 
CSW2017 Henry li how to find the vulnerability to bypass the control flow gua...
CSW2017 Henry li how to find the vulnerability to bypass the control flow gua...CSW2017 Henry li how to find the vulnerability to bypass the control flow gua...
CSW2017 Henry li how to find the vulnerability to bypass the control flow gua...CanSecWest
 
Context and Dependency Injection
Context and Dependency InjectionContext and Dependency Injection
Context and Dependency InjectionWerner Keil
 
CDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptorCDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptorCaelum
 
Daggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processorDaggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processorBartosz Kosarzycki
 
Cut your Dependencies with Dependency Injection for East Bay.NET User Group
Cut your Dependencies with Dependency Injection for East Bay.NET User Group Cut your Dependencies with Dependency Injection for East Bay.NET User Group
Cut your Dependencies with Dependency Injection for East Bay.NET User Group Theo Jungeblut
 
Spring vs. Java EE QConSP 2012
Spring vs. Java EE QConSP 2012Spring vs. Java EE QConSP 2012
Spring vs. Java EE QConSP 2012Guilherme Moreira
 

Similaire à SOLID (20)

Testable JavaScript: Application Architecture
Testable JavaScript:  Application ArchitectureTestable JavaScript:  Application Architecture
Testable JavaScript: Application Architecture
 
Spring training
Spring trainingSpring training
Spring training
 
Implement Service Broker with Spring Boot #cf_tokyo
Implement Service Broker with Spring Boot #cf_tokyoImplement Service Broker with Spring Boot #cf_tokyo
Implement Service Broker with Spring Boot #cf_tokyo
 
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to MissJava Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss
 
E:\Plp 2009 2\Plp 9
E:\Plp 2009 2\Plp 9E:\Plp 2009 2\Plp 9
E:\Plp 2009 2\Plp 9
 
Paradigmas de linguagens de programacao - aula#9
Paradigmas de linguagens de programacao - aula#9Paradigmas de linguagens de programacao - aula#9
Paradigmas de linguagens de programacao - aula#9
 
Devoxx 2012 (v2)
Devoxx 2012 (v2)Devoxx 2012 (v2)
Devoxx 2012 (v2)
 
Servletand sessiontracking
Servletand sessiontrackingServletand sessiontracking
Servletand sessiontracking
 
OpenWebBeans and DeltaSpike at ApacheCon
OpenWebBeans and DeltaSpike at ApacheConOpenWebBeans and DeltaSpike at ApacheCon
OpenWebBeans and DeltaSpike at ApacheCon
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
 
Exploring lambdas and invokedynamic for embedded systems
Exploring lambdas and invokedynamic for embedded systemsExploring lambdas and invokedynamic for embedded systems
Exploring lambdas and invokedynamic for embedded systems
 
Testing in android
Testing in androidTesting in android
Testing in android
 
CSW2017 Henry li how to find the vulnerability to bypass the control flow gua...
CSW2017 Henry li how to find the vulnerability to bypass the control flow gua...CSW2017 Henry li how to find the vulnerability to bypass the control flow gua...
CSW2017 Henry li how to find the vulnerability to bypass the control flow gua...
 
Using the Windows 8 Runtime from C++
Using the Windows 8 Runtime from C++Using the Windows 8 Runtime from C++
Using the Windows 8 Runtime from C++
 
Context and Dependency Injection
Context and Dependency InjectionContext and Dependency Injection
Context and Dependency Injection
 
JDK Power Tools
JDK Power ToolsJDK Power Tools
JDK Power Tools
 
CDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptorCDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptor
 
Daggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processorDaggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processor
 
Cut your Dependencies with Dependency Injection for East Bay.NET User Group
Cut your Dependencies with Dependency Injection for East Bay.NET User Group Cut your Dependencies with Dependency Injection for East Bay.NET User Group
Cut your Dependencies with Dependency Injection for East Bay.NET User Group
 
Spring vs. Java EE QConSP 2012
Spring vs. Java EE QConSP 2012Spring vs. Java EE QConSP 2012
Spring vs. Java EE QConSP 2012
 

Plus de Eduards Sizovs

Beyond Software Craftsmanship - Johnny's Road to Remarkable Career
Beyond Software Craftsmanship - Johnny's Road to Remarkable CareerBeyond Software Craftsmanship - Johnny's Road to Remarkable Career
Beyond Software Craftsmanship - Johnny's Road to Remarkable CareerEduards Sizovs
 
8 Things That Make Continuous Delivery Go Nuts
8 Things That Make Continuous Delivery Go Nuts8 Things That Make Continuous Delivery Go Nuts
8 Things That Make Continuous Delivery Go NutsEduards Sizovs
 
Architecting well-structured Java applications
Architecting well-structured Java applicationsArchitecting well-structured Java applications
Architecting well-structured Java applicationsEduards Sizovs
 
Software Architecture Anti-Patterns
Software Architecture Anti-PatternsSoftware Architecture Anti-Patterns
Software Architecture Anti-PatternsEduards Sizovs
 
Continuous Delivery (The newest)
Continuous Delivery (The newest)Continuous Delivery (The newest)
Continuous Delivery (The newest)Eduards Sizovs
 
Software Craftsmanship Essentials
Software Craftsmanship EssentialsSoftware Craftsmanship Essentials
Software Craftsmanship EssentialsEduards Sizovs
 
Micro Service Architecture
Micro Service ArchitectureMicro Service Architecture
Micro Service ArchitectureEduards Sizovs
 
Code Structural Analysis
Code Structural AnalysisCode Structural Analysis
Code Structural AnalysisEduards Sizovs
 
Code Structural Analysis
Code Structural AnalysisCode Structural Analysis
Code Structural AnalysisEduards Sizovs
 

Plus de Eduards Sizovs (10)

Beyond Software Craftsmanship - Johnny's Road to Remarkable Career
Beyond Software Craftsmanship - Johnny's Road to Remarkable CareerBeyond Software Craftsmanship - Johnny's Road to Remarkable Career
Beyond Software Craftsmanship - Johnny's Road to Remarkable Career
 
8 Things That Make Continuous Delivery Go Nuts
8 Things That Make Continuous Delivery Go Nuts8 Things That Make Continuous Delivery Go Nuts
8 Things That Make Continuous Delivery Go Nuts
 
Architecting well-structured Java applications
Architecting well-structured Java applicationsArchitecting well-structured Java applications
Architecting well-structured Java applications
 
Software Architecture Anti-Patterns
Software Architecture Anti-PatternsSoftware Architecture Anti-Patterns
Software Architecture Anti-Patterns
 
Continuous Delivery (The newest)
Continuous Delivery (The newest)Continuous Delivery (The newest)
Continuous Delivery (The newest)
 
Software Craftsmanship Essentials
Software Craftsmanship EssentialsSoftware Craftsmanship Essentials
Software Craftsmanship Essentials
 
Micro Service Architecture
Micro Service ArchitectureMicro Service Architecture
Micro Service Architecture
 
Code Structural Analysis
Code Structural AnalysisCode Structural Analysis
Code Structural Analysis
 
Continuous Delivery
Continuous DeliveryContinuous Delivery
Continuous Delivery
 
Code Structural Analysis
Code Structural AnalysisCode Structural Analysis
Code Structural Analysis
 

Dernier

UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UbiTrack UK
 
UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7DianaGray10
 
Computer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsComputer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsSeth Reyes
 
Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.YounusS2
 
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Will Schroeder
 
Spring24-Release Overview - Wellingtion User Group-1.pdf
Spring24-Release Overview - Wellingtion User Group-1.pdfSpring24-Release Overview - Wellingtion User Group-1.pdf
Spring24-Release Overview - Wellingtion User Group-1.pdfAnna Loughnan Colquhoun
 
Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024SkyPlanner
 
Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1DianaGray10
 
RAG Patterns and Vector Search in Generative AI
RAG Patterns and Vector Search in Generative AIRAG Patterns and Vector Search in Generative AI
RAG Patterns and Vector Search in Generative AIUdaiappa Ramachandran
 
Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024D Cloud Solutions
 
Linked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesLinked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesDavid Newbury
 
PicPay - GenAI Finance Assistant - ChatGPT for Customer Service
PicPay - GenAI Finance Assistant - ChatGPT for Customer ServicePicPay - GenAI Finance Assistant - ChatGPT for Customer Service
PicPay - GenAI Finance Assistant - ChatGPT for Customer ServiceRenan Moreira de Oliveira
 
UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8DianaGray10
 
Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™Adtran
 
Empowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintEmpowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintMahmoud Rabie
 
Machine Learning Model Validation (Aijun Zhang 2024).pdf
Machine Learning Model Validation (Aijun Zhang 2024).pdfMachine Learning Model Validation (Aijun Zhang 2024).pdf
Machine Learning Model Validation (Aijun Zhang 2024).pdfAijun Zhang
 
Cloud Revolution: Exploring the New Wave of Serverless Spatial Data
Cloud Revolution: Exploring the New Wave of Serverless Spatial DataCloud Revolution: Exploring the New Wave of Serverless Spatial Data
Cloud Revolution: Exploring the New Wave of Serverless Spatial DataSafe Software
 
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...Aggregage
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6DianaGray10
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Commit University
 

Dernier (20)

UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
 
UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7UiPath Studio Web workshop series - Day 7
UiPath Studio Web workshop series - Day 7
 
Computer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and HazardsComputer 10: Lesson 10 - Online Crimes and Hazards
Computer 10: Lesson 10 - Online Crimes and Hazards
 
Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.
 
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
 
Spring24-Release Overview - Wellingtion User Group-1.pdf
Spring24-Release Overview - Wellingtion User Group-1.pdfSpring24-Release Overview - Wellingtion User Group-1.pdf
Spring24-Release Overview - Wellingtion User Group-1.pdf
 
Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024
 
Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1
 
RAG Patterns and Vector Search in Generative AI
RAG Patterns and Vector Search in Generative AIRAG Patterns and Vector Search in Generative AI
RAG Patterns and Vector Search in Generative AI
 
Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024Artificial Intelligence & SEO Trends for 2024
Artificial Intelligence & SEO Trends for 2024
 
Linked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesLinked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond Ontologies
 
PicPay - GenAI Finance Assistant - ChatGPT for Customer Service
PicPay - GenAI Finance Assistant - ChatGPT for Customer ServicePicPay - GenAI Finance Assistant - ChatGPT for Customer Service
PicPay - GenAI Finance Assistant - ChatGPT for Customer Service
 
UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8
 
Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™Meet the new FSP 3000 M-Flex800™
Meet the new FSP 3000 M-Flex800™
 
Empowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintEmpowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership Blueprint
 
Machine Learning Model Validation (Aijun Zhang 2024).pdf
Machine Learning Model Validation (Aijun Zhang 2024).pdfMachine Learning Model Validation (Aijun Zhang 2024).pdf
Machine Learning Model Validation (Aijun Zhang 2024).pdf
 
Cloud Revolution: Exploring the New Wave of Serverless Spatial Data
Cloud Revolution: Exploring the New Wave of Serverless Spatial DataCloud Revolution: Exploring the New Wave of Serverless Spatial Data
Cloud Revolution: Exploring the New Wave of Serverless Spatial Data
 
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)
 

SOLID

  • 1. SOLID In the heart of OO design
  • 2. Who is on the scene Eduards Sizovs linkedin.com/in/eduardsi
  • 3. Agenda • Introduction • SRP • OCP • LSP • ISP • DIP • Q&A
  • 4. SOLID • SRP The Single Responsibility • OCP Principle • LSP The Open Closed Principle • ISP The Liskov Substitution Principle • DIP The Interface Segregation Principle Robert Martin The Dependency Inversion Principle
  • 6. Definition Class should have only one responsibility and only one reason to change Robert Martin http://www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfO od
  • 7. Rationale Just because you can, does not mean you should. We want systems of many small, simple, cohesive classes with clear purpose.
  • 8. Milka cow violates SRP – it’s both cow & advertisement.
  • 9. In quest of responsibility Ask yourself: • What concept does the class represent? • What does the class do? • What causes the class to change? • For existing classes: is class X responsible for doing Z? Answer must be one-liner.
  • 10. Violation symptoms • Managers, Services, Facades… • Long lists of variables, dependencies, methods, arguments • Problematic unit-testing (e.g. when you need Spies) • Different levels of abstractions inside a class • A lot of details to tackle, implicitness
  • 11. Overloaded responsibilities interface JsonService { public class TaxCalculator { Json marshall(Object object); @Autowired Object unmarshall(Json json); private EmployeeRepository employeeRepository; void prettyPrint(); void validate(Json json, Wadl wadl); Tax calculate(Id employeeId) { } Employee employee = employeeRepository.findBy(employeeId); return calculate(employee); } } class FooValidator { class User { void validate(Foo foo) { public User(Registration registration) { if (foo.isSuitableForValidation()) { this.email = registration.getEmail(); // actual validation this.firstName = registration.getFirstName(); } this.lastName = registration.getLastName(); } } } public User(Invitation invitation) { … } }
  • 12. OCP The Open Closed Principle
  • 13. Definition Software entities (classes, modules, functions etc.) should be open for extension, but closed for modification. Robert Martin http://www.objectmentor.com/resources/articles/ocp.pdf
  • 14. Rationale Brain surgery is not necessary when putting on a hat.
  • 15. Example – Interceptors [ 1 ] com.ocp.mvc; com.ocp.mvc.extensions; class InterceptorRegistry { public class SecurityInterceptor { @Autowired void intercept(WebRequest request) { ... } } private WebApplication webapp; public class CachingInterceptor { @Autowired void intercept(WebRequest request) { ... } private SecurityInterceptor securityInterceptor; } @Autowired private CachingInterceptor cachingInterceptor; @PostConstruct public void register() { webapp.registerInterceptor(securityInterceptor); webapp.registerInterceptor(cachingInterceptor); } } • InterceptorRegistry disrespects OCP • Implementations cannot be hidden
  • 16. Example – Interceptors [ 2 ] com.ocp.mvc; com.ocp.mvc.extensions; class InterceptorRegistry { class SecurityInterceptor implements Interceptor { @Autowired void intercept(WebRequest request) { ... } } private WebApplication webapp; class CachingInterceptor implements Interceptor { @Autowired void intercept(WebRequest request) { ... } private Collection<Interceptor> interceptors; } @PostConstruct public void register() { webapp.registerInterceptors(interceptors); } } interface Interceptor { void intercept(WebRequest request); } • InterceptorRegistry respects OCP • Interceptors are hidden • Dependency direction has
  • 17. Example – Interceptors [ 3 ] com.ocp.mvc; com.ocp.mvc.extensions; public class InterceptorRegistry { class SecurityInterceptor implements Interceptor { @Autowired @Autowired private InterceptorRegistry interceptorRegistry; private WebApplication webapp; @PostConstruct public void register(Interceptor interceptor) { void register() { webapp.registerInterceptor(interceptor); interceptorRegistry.register(this); } } } void intercept(WebRequest request) { ... } } interface Interceptor { void intercept(WebRequest request); class CachingInterceptor implements Interceptor { } @Autowired private InterceptorRegistry interceptorRegistry; @PostConstruct void register() { interceptorRegistry.register(this); • Interceptors violate SRP? } • InterceptorRegistry exposed void intercept(WebRequest request) { ... } }
  • 18. Example – NotificationService [ 1] class NotificationService { class SmsNotifier { @Autowired void notify(Notification notification) { … } SmsNotifier smsNotifier; } @Autowired class EmailNotifier { EmailNotifier emailNotifier; notify(Notification notification) { … } } void notify(Notification notification) { if (notification.getType() == NotificationType.Sms) { smsNotifier.notify(notification); } if (notification.getType() == NotificationType.Email) { emailNotifier.notify(notification); } } }
  • 19. Example – NotificationService [ 2] interface Notifier { class SmsNotifier implements Notifier { void notify(Notification notification) { … } void notify(Notification notification) { … } boolean isApplicableFor(NotificationType boolean isApplicableFor(NotificationType notificaionType); notificationType) { } return notification.getType() == NotificationType.Sms; class NotificationService { } @Autowired } Collection<Notifier> notifiers; class EmailNotifier implements Notifier { void notify(Notification notification) { notify(Notification notification) { … } Notifier notifier = findApplicableNotifier(notification); boolean isApplicableFor(NotificationType notifier.notify(notification); notificationType) { } return notification.getType() == NotificationType.Email; } private Notifier findApplicableNotifier(Notifier notifier) { } for (Notifier notifier : notifiers) { if (notifier.isApplicableFor(notification)) { return notifier; } } … } }
  • 20. Example – Repository interface EntityRepository { interface EntityRepository { interface By { Entity findByName(String); Entity find(By); } Entity findByPage(Page); } class ByName implements By { Entity findById(Id); public ByName(String name) { … } Entity findByVersion(Version); } } class ByPage implements By { public ByPage(Page page) { … } } class ById implements By { public ById(Id id) { … } } class ByVersion implements By { public ByVersion(Version version) { … } }
  • 22. Definitions The LSP specifies that functions that use pointers of references to base classes must be able to use objects of derived classes without knowing it. Robert Martin http://www.objectmentor.com/resources/articles/lsp.pdf
  • 23. Syntactical conformance is not enough! It’s all about semantics: • Pre-conditions (can’t strengthen, can weaken) • Post-conditions (can’t weaken, can strengthen) • Preserved supertype’s invariants
  • 24. Strengthening pre-conditions interface FileReader { class OpenFileReader implements FileReader { @FileStateAgnostic public void read(File file) { void read(File file); } Preconditions.checkArgument(file.isOpen()); } class Client { } @Autowired void doIt(FileReader fileReader) { File file = getFile(); fileReader.read(file); } }
  • 25. Weakening pre-conditions class FileReader { class SmartFileReader extends FileReader { @CheckIsOpen public void read(File file) { void read(File file) { … } Preconditions.checkArgument(file.isOpen()); } } } class Client { @Autowired void doIt(FileReader fileReader) { File file = getFileAndEnsureOpen(); fileReader.read(file); } }
  • 26. Weakening post-conditions interface Collection { class Queue implements Collection { @DecreasesSizeOfCollectionBy(1) @RetainsItemIfQueueIsBusy void remove(Item item); public void remove(Item item) { … } boolean isEmpty(); public boolean isEmpty() { … } } } class Client { void cleanUp(Collection collection) { while(!collection.isEmpty()) { collection.remove(collection.anyItem()); } } }
  • 27. Strengthening post-conditions interface Collection { class Queue implements Collection { @DecreasesSizeOfCollectionBy(1) @RemovesHead void removeItem(); public void removeItem() { … } boolean isEmpty(); public boolean isEmpty() { … } } } class Client { void cleanUp(Collection collection) { while(!collection.isEmpty()) { collection.removeItem(); } } }
  • 28. Breaking class’ invariants class Money { class Euro extends Money { protected BigDecimal amount; // Does not defend invariants… public void setAmount(BigDecimal amount) { @NonNegative this.amount = amount; public BigDecimal getAmount() { } return amount; } } }
  • 29. Communicating contract • Self-descriptive names (e.g. doIfSomething()); • Meta-annotations • JSR 305 ( @Nullable @CheckForNull, @Immutable … ) • Guava ( @VisibleForTesting ) • Custom • Executable specifications • Unit tests + Story Teller (storyteller.socosomi.com) • JavaDocs • Assertions
  • 30. Violation indicators • Modification of existing code on new subtype • Unnatural class hierarchies • Funny restrictions (do not use this class if…) • instanceof, if, switch … • InvalidOperationException() or similar
  • 32. Definitions No client should be forced to depend on methods it does not use. Many client specific interfaces are better than one general purpose interface. Robert Martin Agile Software Development, 2002
  • 33. Less FAT FAT interfaces • Are not cohesive • Violate SRP • Force implementations to violate SRP • Suffer from high afferent/efferent coupling
  • 34. Flexible layering interface RegistrationSettings { com.4finance.cola.client int getMaxAttempts(); } interface BonusSettings { com.4finance.cola.product com.4finance.cola.client.bonus BonusAmount getBonusAmount(); } interface SolvencySettings { interface ProductSettings { com.4finance.cola.client.solvency Income getMinIncomeForSubmission(); int getMaxRegistrationAttempts(); } BonusAmount getBonusAmount(); Income getMinIncomeForSubmission(); } Consider • Impact of change • Dependency management
  • 35. Extensibility interface JsonMarshaller { Json marshall(Object object); interface JsonService { } Json marshall(Object json); Object unmarshall(Json json); interface JsonUnmarshaller { ValidationResult validate(Json json, Wadl wadl); Object unmarshall(Json json); void prettyPrint(Json json); } } interface JsonValidator { ValidationResult validate(Json json, Wadl wadl); } Consider interface JsonPrettyPrinter { • Creating an adapter } void prettyPrint(Json json); • Creating a test double • Creating an alternative implementation • Creating Special Case (NoOp, Null Object)
  • 36. Lower coupling interface JsonService { class JsonServiceImpl implements JsonService { Json marshall(Object json); … Object unmarshall(Json json); } ValidationResult validate(Json json, Wadl wadl); void prettyPrint(Json json); } Pretty printing Validation (Un)marshalling Consider • High afferent coupling: all clients relying on particular Json functionality are coupled with Wadl. • High efferent coupling: JsonService implementation will violate SRP as it relies on all dependencies required for fulfilling the contract.
  • 37. Understandability interface EventPublisher { interface EventPublisher { void publish(); void publish(); void setJsonService(JsonService void setJsonMarshaller(JsonMarshaller jsonService); jsonMarshaller); } } Consider • When JsonService is set, you need to dive into EventPublisher implementor’s details in order to understand what parts of it are in use.
  • 38. Example – PageRouter interface PageRouter { interface PageRouter{ Route getRouteToProfile(); Route getRoute(); Route getRouteToRegistration(); } } interface ProfilePageRouter extends PageRouter { class DefaultPageRouter implements PageRouter { } … } interface RegistrationPageRouter extends PageRounter { } class RuPageRouter { // RU overrides both routes class DefaultProfilePageRouter implements ProfilePageRounter } { } … Consider • What if alternative implementation appeared that overrides only one route?
  • 40. Definition High-level modules should not depend on low-level modules. Both should depend on abstractions. Robert Martin http://www.objectmentor.com/resources/articles/dip.pdf
  • 41. << interface >> AS ervice Component A Component A << interface >> BS vice er Component B Component B Component C Component C A directly depends on B in order to realize its potential. A defines external needs with interfaces it owns. B indirectly satisfies needs of A by implementing them.
  • 42. Increasing reuse 1 2 3 Widgets Widgets Widgets DatePicker DatePicker DatePicker DateFormatter Loans System Loans System DateTimeUtils DateFormatter Loans System DateTimeUtils DateTimeUtils
  • 43. DwA != DI In true Dependency Inversion, high-level module owns the abstraction.
  • 45. Tangle elimination com.isp.client com.isp.client Client Client com.isp.client.salary com.isp.client.salary Salary Experience Salary SalaryCalculator SalaryCalculator
  • 46. Some code package com.system; package com.system; @Configuration interface ScanPackages { @ComponentScan(“com.system”) String[] get(); class HibernateConfiguration { } @Autowired private Collection<ScanPackages> scanPackages; package com.system; @Component @Bean class DefaultScanPackages implements ScanPackages { public SessionFactory createInstance() { public String[] get() { return new LocalSessionFactoryBean() return new String[] { “com.system.model” }; .setPackagesToScan(scanPackages()) } .newSessionFactory(); } } private String[] scanPackages() { package com.system.subsystem // iterate over “scanPackages” @Component // and aggregate String[] array class SubsystemScanPackages implements ScanPackages { } public String[] get() { } return new String[] { “com.system.sub.model }; } }
  • 48. But… Why care? SOLID contribute to clean code. Writing clean code is what you must do in order to call yourself a professional. There is no reasonable excuse for doing anything less than your best.
  • 51. More
  • 52. Q&A

Notes de l'éditeur

  1. It’s not only about classes. Size matters, but it has supporting functions – signals of bloated responsibility.
  2. Better insights of the system – many clear concepts. Divide &amp; conqueror – mini problems.No one likes systems of GOD objects, GOD methodsLess things in mindTestabilityComposability
  3. Spend time. Every line – ask yourself about responsibilityConscious design &amp; better micro-architectures
  4. Side-effects require JavaDocs! JavaDocs are evil.
  5. - How important it is to define contract at the early stages
  6. EmptyAbstractClass – pig with a lipstick
  7. Goal: increasing reuse &amp; decoupling.Indirection can be solved by DI or Service Locator (Service Registry a-la OSGi)
  8. High-level module: “reusable” or “decoupled from details”!= Separate interface
  9. You have to be careful about dependency direction as it is part of your design.
  10. Similar to OCP example!
  11. Be conscious about design you make.