12 toward solid code
TRANSCRIPT
Moving toward SOLID code
Refactoring is changing the internal implementation to make it more maintainable
� If the user sees a change, it isn't refactoring
Agile projects advocate refactoring mercilessly
YAGNI You Aren't Going to Need It
SOLID Principles
Single Responsibility Principle Open Closed Principle Liskov Substitution Principle Interface Segregation Principle Dependency Inversion Principle
� asdf
Single Responsibility Principle “If a class has more then one responsibility, then the responsibilities become coupled. Changes to one responsibility may impair or inhibit the class’ ability to meet the others. This kind of coupling leads to fragile designs that break in unexpected ways when changed.”
- Robert C. Martin
Single Responsibility Principle � A class should have one and only one
reason to change � Maybe we should call it the Single
Change Reason Principle
Problem: We have a user interface that reads from/writes to the database. This is not cohesive
UI
Goal: To get the business logic out of the UI. Let the UI do what it does exclusively
Business Logic
UI
Problem: DB logic In the UI code public void Click(object o, EventArgs e) { var name = txtName.Text; var phone = txtPhone.Text; var db = new SqlConnection(); db.Open(); var sql ="insert into ... name ..."; var cmd = new SqlCommand(sql, db); cmd.ExecuteNonQuery(); }
Solution: Create a Person class public class Person { public string Name { get; set; } public string Phone { get; set; } public void Save() { //Write to database here //Connection, Command, ExecuteNonQuery } public Person Read(int Id) { //Read from database here //Connection, Command, ExecuteNonQuery } }
Problem: We still have db logic in the business logic
Business Logic
UI
Business Logic
Infrastructure
UI
Solution: Create a DB layer
Create a repository class Public class PersonRepository { public void Save(Person) { //Write to database here } public Person Read(int Id){ //Read from database here return thePerson; } }
New class w/o DB logic public class Person { public string Name { get; set; } public string Phone { get; set; } public void Save() { var r = new PersonRepository(); r.Save(this); } public Person Read(int Id) { var r = new PersonRepository(); return r.Read(Id); } }
� asdf
Open-Closed Principle Modules that conform to the open-closed principle have two primary attributes. 1. They are “Open For Extension”.
This means that the behavior of the module can be extended. That we can make the module behave in new and different ways as the requirements of the application change, or to meet the needs of new applications.
2. They are “Closed for Modification”. The source code of such a module is inviolate. No one is allowed to make source code changes to it.
- Robert C. Martin
Open-Closed Principle � Classes should be open for extension but
closed for modification � To properly change behavior, you should
inherit from it and add or override functionality in the child class
Examples � Physical world
� Ryobi lawn tool
� In the Matrix � Visual inheritance in WinForms or WebForms � Custom exceptions
� sdfsd
Liskov Substitution Principle “If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.”
- Barbara Liskov “Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.”
-Robert Martin
Liskov Substitution Principle in real-people words. � Any object must be semantically similar to
everything above it in the inheritance tree � No matter how poorly named they are � Semantically substituted, not syntactically
substituted
Example: Bike & Motorcycle public interface IBicycle !{! int speed;! void Brake();! void Accelerate();!}!public class Motorcycle : IBicycle!{! public Motor Engine { get; set; }!}!
� sadf
Interface Segregation Principle “This principle deals with the disadvantages of ‘fat’ interfaces. Classes that have ‘fat’ interfaces are classes whose interfaces are not cohesive. In other words, the interfaces of the class can be broken up into groups of member functions. Each group serves a different set of clients. Thus some clients use one group of member functions, and other clients use the other groups.”
- Robert Martin
Interface Segregation Principle � An implementing class should not be
forced to depend on an interface that it doesn’t need
� Split fat interfaces up � Very much like SRP
Example: All-in-one printer
28
� sadf
Dependency Inversion Principle “What is it that makes a design rigid, fragile and immobile? It is the interdependence of the modules within that design. A design is rigid if it cannot be easily changed. Such rigidity is due to the fact that a single change to heavily interdependent software begins a cascade of changes in dependent modules.”
- Robert Martin
Dependency Inversion Principle � Depend on interfaces, not concrete
implementations
Example Problem: The business classes are worthless without the DB logic. They're too tightly coupled.
Business Logic
Infrastructure
UI
Person Repository
Person
� Goal: Have a business object that maintains its state in the database
Business Logic
Infrastructure
UI
IPerson Repository
Person Repository
Person
Step 1: Create an interface public interface IPersonRepository { public void Save(); public Person Read(int Id); } public class PersonRepository : IPersonRepository { //Same concrete implementations }
Step 2: Using the interface public class Person { public string Name { get; set; } public string Phone { get; set; } public void Save() { IPersonRepository r = new PersonRepository(); r.Save(this); } public Person Read(int Id) { IPersonRepository r = new PersonRepository(); return r.Read(Id); } }
Step 3: Pass an IPersonRepository into the constructor public class Person { private IPersonRepository ipr; public string Name { get; set; } public string Phone { get; set; } public Person(IPersonRepository PersonRepo) { ipr = PersonRepo; } public void Save() { ipr.Save(this); } public Person Read(int Id) { return ipr.Read(Id); } }
Business Logic
Infrastructure
UI
Person Repository
Person
Step 4: Move the IPersonRepository to the Person Business Logic project
IPerson Repository
� sdfgd
Summary � We can't write perfect code and we shouldn't try � It helps us to write faster if we use good design
patterns and know we'll be back later to refactor the code
� We should use the SOLID design patterns to make more maintainable code � S - Each class should do one only one thing � O - Classes can be inherited, but not changed � L - Design to Interfaces, not classes � I - Classes shouldn't rely on things they don't use � D - Code should depend on interfaces, not classes