I am brushing up my fundamentals on SOLID principles, by going through the pluralsight course named: SOLID Principles of Object Oriented Design
The author of the course Steven Smith has done an amazing job here kudos to him.
Tell don't Ask:
Don't interrotgate objects for their internals -- move behavior to the object.
Tell the object what you want it to do.
Consider Refactoring to a new Base Class
- Given 2 classes share a lot of behavior refactor them to a base class
Interface segragation principle:
- Clients should not be forced to depend on methids they do not user.
- Prefer small, cohesive interfaces to fat interfaces
- Interface Segragation principle violations result in classses that depend on things they do not need,
increasing coupling and reducing flexibility and maintainability.
Smells:
- Unimplemented Interface methods
- Client references a class but only uses a portion of it.
- If you find yourself depending on a fat interface you own
- if you find fat interfaces are problematic but you don't own them
- Create a smaller interface with what you need
- Implement this interface using an adapter that implements the full interface.
Tips
Dependency Inversion Principle PART I:
- Highlevel modules should not depent on lowlevel modules. both should depend on abstractions.
- Abstractions should not depend on details rather details should depend on abstractions.
- What are the depdendencies ?
- Framework is a dependency, ohter dependencies are third party libraries, Database, File system, Email, Webservices, System Resources, configuration, the new keyword (this means direct dependency), Static methods, thread.sleep, Random(difficult to test if the code uses Random instead use a inteface to generate random so that during testing its possible to make sure that random returns the expected value by mocking and faking the objects)
- Classes dependencies should be honest
- Classes whose constructors make this clear are called as explicit dependencies
- Classes that do not have impplicit or hidden dependencies
- Classes should declare on what they need.
Dependency Injection : is a technique that is used to allow calling code to inject the dependencies a class needs when it is instantiated.
The hollywood principle: Don't call us; we'll call you.
The techniques:
1. Constructor Injection : Strategy Pattern
Pros:
- Classes self document on what they need to perform ofr their work
- Works well without a container
- Classes are always in a valid state once constructed
Cons:
- Constructors can have many parameters/dependencies
- Some features may require default constructor.(Serialization)
- Some methods in the calls may not require things other methods require but the constructor injection.
makes all the dependencies available for all the methods which is a design smell.
2. Property Injection: Setter Injection
Pros:
- Dependencies can be changed at any time during the lifetime of the object
- Very flexible
Cons:
- Objects may be in invalid state between the construction and seetion of dependencies via setters
- Less intuitive
3. Parameter Injection: dependencies are passed in via a method parameter
Pros:
- Most Granular
- very flexible
- Requires no change to the rest of the class
Cons:
- Breaks method signature
- Can result in many parameters
Consider if only one method has the dependency otherwise prefer constructor injection.
How to refactor to achieve dependency inversion principle;
- Extract dependencies to Interfaces
- Inject Implementaytion of interfaces into order
- Reduce Orders responsibility (apply SRP)
Design Smells which can be addressed via Dependency Inversion principle
- Use of new Keyword
- Use of Static method and properties
- Good way of using static method is the place where there is no dependency in the method apart from the parameters which are being passed
- static methods should not instantiate other classes which might have dependencies of their own then it becomes a problem.
Where do we instantiate the objects:
- Default Constructor
- Startup of the application or the main method of the application.
- Use an IOC container.
IOC Containers:
- Responsible for object graph instantiation
- Inititated at application startup via code or configuration
- Managed interfaces and the implementation to be used are Registered with the container
- Dependencies on interfaces are Resolved at application startup or runtime.
Dependency Inversion Principle PART II:
- Traditional application architecture follows the model where in we have UI --> BLL --> DAL
- The problem with such a design is that the dependencies flow towards the Infrastructure
- Core/Business/Domain classes depend on the Implementation details.
- This results in tight coupling
- No way to change implementation details without recompile(OCP violation)
- Difficult to test
- Dependencies is transitive
- If UI depends on BLL depends on DAL depends on DB. Then everything depends on database.
- Depend on abstraction
Don't Repeat Yourself :
- Every piece of knowledge must have a single, unambiguous representation in the system.
- Repetition of logic calls for abstraction. Repetition of process calls for automation.
- Once and only once
- Duplication is Evil
- Use of Magic strings
- Duplicate logic in multiple location
- Repeated if then logic in the code
- Applying DRY to remove magic string
- assign the magic string to a variable or in config file, this is just to avoid the repetition of value of connection string
- if then logic can be moved into a loop
Related fundamentals:
- Template method
- command pattern
- Depdendency Inversion principle
The author of the course Steven Smith has done an amazing job here kudos to him.
Tell don't Ask:
Don't interrotgate objects for their internals -- move behavior to the object.
Tell the object what you want it to do.
Consider Refactoring to a new Base Class
- Given 2 classes share a lot of behavior refactor them to a base class
Interface segragation principle:
- Clients should not be forced to depend on methids they do not user.
- Prefer small, cohesive interfaces to fat interfaces
- Interface Segragation principle violations result in classses that depend on things they do not need,
increasing coupling and reducing flexibility and maintainability.
Smells:
- Unimplemented Interface methods
- Client references a class but only uses a portion of it.
- If you find yourself depending on a fat interface you own
- if you find fat interfaces are problematic but you don't own them
- Create a smaller interface with what you need
- Implement this interface using an adapter that implements the full interface.
Tips
Dependency Inversion Principle PART I:
- Highlevel modules should not depent on lowlevel modules. both should depend on abstractions.
- Abstractions should not depend on details rather details should depend on abstractions.
- What are the depdendencies ?
- Framework is a dependency, ohter dependencies are third party libraries, Database, File system, Email, Webservices, System Resources, configuration, the new keyword (this means direct dependency), Static methods, thread.sleep, Random(difficult to test if the code uses Random instead use a inteface to generate random so that during testing its possible to make sure that random returns the expected value by mocking and faking the objects)
- Classes dependencies should be honest
- Classes whose constructors make this clear are called as explicit dependencies
- Classes that do not have impplicit or hidden dependencies
- Classes should declare on what they need.
Dependency Injection : is a technique that is used to allow calling code to inject the dependencies a class needs when it is instantiated.
The hollywood principle: Don't call us; we'll call you.
The techniques:
1. Constructor Injection : Strategy Pattern
Pros:
- Classes self document on what they need to perform ofr their work
- Works well without a container
- Classes are always in a valid state once constructed
Cons:
- Constructors can have many parameters/dependencies
- Some features may require default constructor.(Serialization)
- Some methods in the calls may not require things other methods require but the constructor injection.
makes all the dependencies available for all the methods which is a design smell.
2. Property Injection: Setter Injection
Pros:
- Dependencies can be changed at any time during the lifetime of the object
- Very flexible
Cons:
- Objects may be in invalid state between the construction and seetion of dependencies via setters
- Less intuitive
3. Parameter Injection: dependencies are passed in via a method parameter
Pros:
- Most Granular
- very flexible
- Requires no change to the rest of the class
Cons:
- Breaks method signature
- Can result in many parameters
Consider if only one method has the dependency otherwise prefer constructor injection.
How to refactor to achieve dependency inversion principle;
- Extract dependencies to Interfaces
- Inject Implementaytion of interfaces into order
- Reduce Orders responsibility (apply SRP)
Design Smells which can be addressed via Dependency Inversion principle
- Use of new Keyword
- Use of Static method and properties
- Good way of using static method is the place where there is no dependency in the method apart from the parameters which are being passed
- static methods should not instantiate other classes which might have dependencies of their own then it becomes a problem.
Where do we instantiate the objects:
- Default Constructor
- Startup of the application or the main method of the application.
- Use an IOC container.
IOC Containers:
- Responsible for object graph instantiation
- Inititated at application startup via code or configuration
- Managed interfaces and the implementation to be used are Registered with the container
- Dependencies on interfaces are Resolved at application startup or runtime.
Dependency Inversion Principle PART II:
- Traditional application architecture follows the model where in we have UI --> BLL --> DAL
- The problem with such a design is that the dependencies flow towards the Infrastructure
- Core/Business/Domain classes depend on the Implementation details.
- This results in tight coupling
- No way to change implementation details without recompile(OCP violation)
- Difficult to test
- Dependencies is transitive
- If UI depends on BLL depends on DAL depends on DB. Then everything depends on database.
- Depend on abstraction
Don't Repeat Yourself :
- Every piece of knowledge must have a single, unambiguous representation in the system.
- Repetition of logic calls for abstraction. Repetition of process calls for automation.
- Once and only once
- Duplication is Evil
- Use of Magic strings
- Duplicate logic in multiple location
- Repeated if then logic in the code
- Applying DRY to remove magic string
- assign the magic string to a variable or in config file, this is just to avoid the repetition of value of connection string
- if then logic can be moved into a loop
Related fundamentals:
- Template method
- command pattern
- Depdendency Inversion principle