Solid Principal
Solid Principal
Outline
SRP Defined The Problem An Example Refactoring to Apply SRP Related Fundamentals
SRP: The Single Responsibility Principle The Single Responsibility Principle states that every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class. Wikipedia There should never be more than one reason for a class to change. Robert C. Uncle Bob Martin
Demo
The Problem With Too Many Responsibilities
The Problem
Cash Transactions Dont Need Credit Card Processing Point of Sale Transactions Dont Need Inventory Reservations
The customer doesnt provide an email The customer knows immediately that the order was a success
Any change to notifications, credit card processing, or inventory management will affect Order as well as the Web and Point of Sale implementations of Order!
Demo
Refactoring to a Better Design
What is a Responsibility?
a reason to change A difference in usage scenarios from the clients perspective Multiple small interfaces (follow ISP) can help to achieve SRP
Summary
Following SRP leads to lower coupling and higher cohesion Many small classes with distinct responsibilities result in a more flexible design Related Fundamentals:
Recommended Reading:
Credits
Images Used Under License
http://www.lostechies.com/blogs/derickbailey/archive/2009/02/11/soliddevelopment-principles-in-motivational-pictures.aspx
SRP Article
http://www.objectmentor.com/resources/articles/srp.pdf
Outline
OCP Defined The Problem An Example Refactoring to Apply OCP Related Fundamentals
The Open / Closed Principle states that software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification. Wikipedia
The Open / Closed Principle Open to Extension New behavior can be added in the future Closed to Modification Changes to source or binary code are not required
Dr. Bertrand Meyer originated the OCP term in his 1988 book, Object Oriented Software Construction
Demo
A Price Calculator That Is Not Closed To Change
The Problem
Adding new rules require changes to the calculator every time Each change can introduce bugs and requires re-testing, etc. We want to avoid introducing changes that cascade through many modules in our application Writing new classes is less likely to introduce problems
Nothing depends on new classes (yet) New classes have no legacy coupling to make them hard to design or test
Allow client to control behavior specifics via a parameter Combined with delegates/lambda, can be very powerful approach
Client code depends on abstraction Provides a plug in model Implementations utilize Inheritance; Client utilizes Composition
Demo
Refactoring to a Better Design
10
Otherwise Fool me once, shame on you; fool me twice, shame on me Dont apply OCP at first If the module changes once, accept it. If it changes a second time, refactor to achieve OCP Remember TANSTAAFL There Aint No Such Thing As A Free Lunch OCP adds complexity to design No design can be closed against all changes
Summary
Conformance to OCP yields flexibility, reusability, and maintainability Know which changes to guard against, and resist premature abstraction Related Fundamentals:
Recommended Reading:
Agile Principles, Patterns, and Practices by Robert C. Martin and Micah Martin [http://amzn.to/agilepppcsharp]
Credits
Images Used Under License
http://www.lostechies.com/blogs/derickbailey/archive/2009/02/11/soliddevelopment-principles-in-motivational-pictures.aspx
Outline
LSP Defined The Problem An Example Refactoring to Apply LSP Related Fundamentals
The Liskov Substitution Principle states that Subtypes must be substitutable for their base types. Agile Principles, Patterns, and Practices in C# Named for Barbara Liskov, who first described the principle in 1988.
Substitutability Child classes must not: 1) Remove base class behavior 2) Violate base class invariants And in general must not require calling code to know they are different from their base type.
Nave OOP teaches use of IS-A to describe child classes relationship to base classes
Invariants
Consist of reasonable assumptions of behavior by clients Can be expressed as preconditions and postconditions for methods Frequently, unit tests are used to specify expected behavior of a method or class Design By Contract is a technique that makes defining these pre- and post-conditions explicit within code itself. To follow LSP, derived classes must not violate any constraints defined (or assumed by clients) on the base classes
Demo
Violating LSP using Shapes
The Problem
Non-substitutable code breaks polymorphism Client code expects child classes to work in place of their base classes Fixing substitutability problems by adding if-then or switch statements quickly becomes a maintenance nightmare (and violates OCP)
10
Follow ISP! Use small interfaces so you dont require classes to implement more than they need!
11
Demo
Refactoring to a Better Design
12
LSP Tips
Tell, Dont Ask
Dont interrogate objects for their internals move behavior to the object Tell the object what you want it to do
Given two classes that share a lot of behavior but are not substitutable Create a third class that both can derive from Ensure substitutability is retained between each class and the new base
Summary
Conformance to LSP allows for proper use of polymorphism and produces more maintainable code Remember IS-SUBSTITUTABLE-FOR instead of IS-A Related Fundamentals:
Recommended Reading:
Agile Principles, Patterns, and Practices by Robert C. Martin and Micah Martin [http://amzn.to/agilepppcsharp]
Credits
Images Used Under License
http://www.lostechies.com/blogs/derickbailey/archive/2009/02/11/soliddevelopment-principles-in-motivational-pictures.aspx
Outline
ISP Defined The Problem An Example Refactoring to Apply ISP Related Fundamentals
The Interface Segregation Principle states that Clients should not be forced to depend on methods they do not use. Agile Principles, Patterns, and Practices in C# Corollary:
Prefer small, cohesive interfaces to fat interfaces
Whats an Interface? Interface keyword/type public interface IDoSomething { } Public interface of a class public class SomeClass { } What does the client see and use?
Demo
Violating ISP
The Problem
Client Class (Login Control) Needs This:
The Problem
AboutPage simply needs ApplicationName and AuthorName Forced to deal with huge ConfigurationSettings class Forced to deal with actual configuration files
Interface Segregation violations result in classes that depend on things they do not need, increasing coupling and reducing flexibility and maintainability
Demo
Refactoring to a Better Design
ISP Smells
Unimplemented interface methods: public override string ResetPassword( string username, string answer) { throw new NotImplementedException(); }
ISP Smells
Client references a class but only uses small portion of it
Create a smaller interface with just what you need Have the fat interface implement your new interface Reference the new interface with your code
If you find fat interfaces are problematic but you do not own them
Create a smaller interface with just what you need Implement this interface using an Adapter that implements the full interface
ISP Tips
Keep interfaces small, cohesive, and focused Whenever possible, let the client define the interface Whenever possible, package the interface with the client
Alternately, package in a third assembly client and implementation both depend upon
Summary
Dont force client code to depend on things it doesnt need Keep interfaces lean and focused Refactor large interfaces so they inherit smaller interfaces Related Fundamentals:
Recommended Reading:
Agile Principles, Patterns, and Practices by Robert C. Martin and Micah Martin [http://amzn.to/agilepppcsharp]
Credits
Images Used Under License
http://www.lostechies.com/blogs/derickbailey/archive/2009/02/11/soliddevelopment-principles-in-motivational-pictures.aspx
Outline
DIP Defined The Problem An Example Refactoring to Apply DIP Related Fundamentals
DIP: The Dependency Inversion Principle High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions. Agile Principles, Patterns, and Practices in C#
Static methods are used for convenience or as Faade layers Class instantiation / Call stack logic is scattered through all modules
Demo
Violating DIP
The Problem
Order has hidden dependencies:
Result
Tight coupling No way to change implementation details (OCP violation) Difficult to test
10
Dependency Injection
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
11
Constructor Injection
Dependencies are passed in via constructor Pros
Strategy Pattern
Classes self-document what they need to perform their work Works well with or without a container Classes are always in a valid state once constructed
Cons
Constructors can have many parameters/dependencies (design smell) Some features (e.g. Serialization) may require a default constructor Some methods in the class may not require things other methods require (design smell)
12
Property Injection
Dependencies are passed in via a property
Pros
Dependency can be changed at any time during object lifetime Very flexible
Cons
Objects may be in an invalid state between construction and setting of dependencies via setters Less intuitive
13
Parameter Injection
Dependencies are passed in via a method parameter Pros
Cons
Consider if only one method has the dependency, otherwise prefer constructor injection
14
Refactoring
Extract Dependencies into Interfaces Inject implementations of interfaces into Order Reduce Orders responsibilities (apply SRP)
15
Demo
Refactoring to a Better Design
16
DIP Smells
Use of new keyword foreach(var item in cart.Items) { try { var inventorySystem = new InventorySystem(); inventorySystem.Reserve(item.Sku, item.Quantity); } }
DIP Smells
Use of static methods/properties message.Subject = "Your order placed on " + DateTime.Now.ToString(); Or DataAccess.SaveCustomer(myCustomer);
You can provide a default constructor that news up the instances you expect to typically need in your application Referred to as poor mans dependency injection or poor mans IoC
Main
You can manually instantiate whatever is needed in your applications startup routine or main() method
IoC Container
IoC Containers
Responsible for object graph instantiation Initiated 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 Examples of IoC Containers for .NET
Summary
Depend on abstractions. Dont force high-level modules to depend on low-level modules through direct instantiation or static method calls Declare class dependencies explicitly in their constructors Inject dependencies via constructor, property, or parameter injection Related Fundamentals:
Single Responsibility Principle Interface Segregation Principle Faade Pattern Inversion of Control Containers
Recommended Reading:
Agile Principles, Patterns, and Practices by Robert C. Martin and Micah Martin [http://amzn.to/agilepppcsharp] http://www.martinfowler.com/articles/injection.html
Credits
Images Used Under License
http://www.lostechies.com/blogs/derickbailey/archive/2009/02/11/soliddevelopment-principles-in-motivational-pictures.aspx
Outline
Project Dependencies The Problem An Example Refactoring to Apply DIP Related Fundamentals
For instance User Interface (UI) Business Logic Layer (BLL) Data Acces Layer (DAL)
Work at the abstraction level appropriate Each level only knows about one level deep (ideally)
Common
Inverted Architecture
Data Access
Database
UI
Tests
Demo
Violating DIP with Projects and Assemblies
The Problem
Dependencies Flow Toward Infrastructure Core / Business / Domain Classes Depend on Implementation Details Result
Tight coupling No way to change implementation details without recompile (OCP violation) Difficult to test
Dependency Injection
Dependency is transitive
If UI depends on BLL depends on DAL depends on Database Then *everything* depends on the Database
Depend on abstractions (DIP) Package interfaces (abstractions) with the client (ISP) Structure Solutions and Projects so Core / BLL is at center, with fewest dependencies
Demo
Refactoring to a Better Design
Summary
Dont Depend on Infrastructure Assemblies from Core Apply DIP to reverse dependencies Related Fundamentals:
Recommended Reading:
Agile Principles, Patterns, and Practices by Robert C. Martin and Micah Martin [http://amzn.to/agilepppcsharp] http://www.martinfowler.com/articles/injection.html
Outline
DRY Defined Demo: Repetition in Code Analysis Demos: Refactoring to apply DRY Code Generation Repetition in Process Demo: Automation to apply DRY Summary and Related Fundamentals
Demo
Violating DRY in a simple Data Warehouse Sample Overview
Analysis
Magic Strings/Values Duplicate logic in multiple locations Repeated if-then logic Conditionals instead of polymorphism Repeated Execution Patterns Lots of duplicate, probably copy-pasted, code Only manual tests Static methods everywhere
Demo
Applying DRY to Remove Magic Strings
Demo
Applying DRY to Duplicate Logic in Multiple Locations
10
Demo
Applying DRY to Repeated if-then Logic
12
Demo
Applying DRY to use of Conditional Instead of Polymorphism
14
Summary Repetition breeds errors and waste Refactor code to remove repetition Recommended Reading:
The Pragmatic Programmer: From Journeyman to Master http://amzn.to/b2gJdK 97 Things Every Programmer Should Know http://amzn.to/cAse1Y
Outline
Part 1 DRY Defined Demo: Repetition in Code Analysis Demos: Refactoring to apply DRY
Refactoring for greater testability Adding Tests
Part 2
Code Generation Repetition in Process Demo: Automation to apply DRY Summary and Related Fundamentals
Analysis
Part 1 Magic Strings/Values Duplicate logic in several methods Repeated if-then logic Conditionals instead of polymorphism Repeated Execution Patterns (part 3) Lots of duplicate, probably copy-pasted, code (part 3) Only manual tests Static methods everywhere
No Tests
Only manual tests More and more expensive to verify all results are correct as new operations are added More and time wasted as long-running queries are added
Static Methods
Tightly coupled Difficult to test Difficult to change behavior (violates OCP) Cannot use object oriented design techniques
Inheritance Polymorphism
Demo
Refactoring to Eliminate Static Cling and Add Tests
Summary
Repetition breeds errors and waste Abstract repetitive logic in code Related Fundamentals:
Recommended Reading:
The Pragmatic Programmer: From Journeyman to Master http://amzn.to/b2gJdK 97 Things Every Programmer Should Know http://amzn.to/cAse1Y
Outline
Part 1 DRY Defined Demo: Repetition in Code Analysis Demos: Refactoring to apply DRY
Refactoring for greater testability Adding Tests
Part 2
Code Generation Repetition in Process Demo: Automation to apply DRY Summary and Related Fundamentals
Analysis
Part 2 Only manual tests Static methods everywhere Part 1 Magic Strings/Values Duplicate logic in several methods Repeated if-then logic Conditionals instead of polymorphism Repeated Execution Patterns Lots of duplicate, probably copy-pasted, code
Demo
Refactoring Repeated Execution Patterns
Atomiq (http://GetAtomiq.com)
Full disclosure: Im one of the owners of the company that produces Atomiq
Demo
Find Duplicate Code using Tools
Reduce repetitive data access code Eliminate common data access errors
Commercial Tools:
Repetition in Process
Testing
Builds
Deployments
Demo
Automating Processes
10
Summary
Repetition breeds errors and waste Use an ORM tool to eliminate repeated data access code Use Tools to Locate Repeated Code Automate repetitive actions in your processes Recommended Reading:
The Pragmatic Programmer: From Journeyman to Master http://amzn.to/b2gJdK 97 Things Every Programmer Should Know http://amzn.to/cAse1Y
Related Tool
Atomiq http://GetAtomiq.com
Final Code
Check out the final version of the demo in this modules demo zip file
12