establishing a solid foundation - an intro to software design

Post on 22-Jan-2017

118 Views

Category:

Software

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Establishing a SOLID FoundationAn Intro To Software Design

Cameron Presley@pcameronpresley

http://blog.thesoftwarementor.com

Outline What is SOLID?

Why should our code be SOLID?

Exploring the SOLID principles

Additional Resources

What is SOLID?

What is SOLID? Clever mnemonic for a set of principles that would allow us to write easier to

maintain code

Concepts aren’t new Barbara Liskov – 1987 (Liskov Substitution) Bertrand Meyer – 1988 (Open/Closed)

Robert C. Martin (Uncle Bob) would introduce these concepts in Agile Principles, Patterns, and Practices

Michael Feathers (Working Effectively with Legacy Code) would come up with SOLID

What is SOLID?Single ResponsibilityOpen/ClosedLiskov SubstitutionInterface SegregationDependency Inversion

Why Should We Write SOLID Code? Easier to maintain

Easier to debug Easier to extend

The most expensive part of software development is maintenance Steve McConnell (Code Complete)

It’s fiscally responsible for us to write maintainable code

Why Should We Write SOLID Code? By following SOLID

Small, focused classes Interchangeable abstractions

This allows our code to easily evolve and adapt to changing specifications Which in turn decreases the time it takes to develop features and the likelihood of shipping a bug Which lowers our maintenance cost

This in turn will lead to us to write more testable code Which in turn allows us a way to make sure we don’t ship broken code Which lowers our maintenance cost

Single ResponsibilityOpen/ClosedLiskov SubstitutionInterface SegregationDependency Inversion

Single Responsibility Principle

Single Responsibility Principle Classes should have only one reason to change

NOTE: Doesn’t mean that classes can only do one thing Repository

Coined by Robert C. Martin

Referred to as SRP

SRP – Problem It Solves Large classes are hard to maintain

If multiple developers need to work on the class at the same time… What do you call a group of developers … a merge conflict

SRP forces us to write smaller classes

Easier to combine many small classes than using a large one

SRP – Signs of Violation Opening the class in an editor and the scroll bar disappears

SRP – Signs of Violation 27 public methods

SRP – Signs of Violation 52 private methods, 1 public method

SRP – Resolving Violations Every public method will become a class

Private methods used by a public method will be moved to the new class Private method used everywhere? That becomes a new class

Update places that used the large class to use the smaller classes Can’t change the signature of the large class? Instantiate the newly created class as part of the method

SRP – Violation

SRP – Resolving ViolationsIdentify public methods

SRP – Resolving ViolationsExtract the public methods to new classes

SRP – Resolving ViolationsNow that the methods have been extracted to new classes, identify the helper methods

SRP – Resolving Violations

And add them to the appropriate classes

SRP – Resolving Violations

See the same helper method in multiple places?

Time to move that to a new class

SRP – Resolving Violations

SRP – Resolving ViolationsUpdate the large class to delegate the work to the newly created classes

Single Responsibility PrincipleSummary

Classes should only have one reason to change

By breaking classes down into smaller pieces, it allows us to work on the separate pieces of functionality without stepping on each other

Allows us to combine just-what-we need functionality into new classes

Single ResponsibilityOpen/ClosedLiskov SubstitutionInterface SegregationDependency Inversion

Open/Closed Principle

Open/Closed Principle Classes should be open for extension, closed for modification

Means that we should add new functionality by adding new classes, not modifying existing ones

NOTE: Doesn’t mean that we can’t modify a class to fix bugs

Coined by Bertrand Meyer

Referred to as OCP

OCP – Problem It Solves If we modify a class to add additional functionality, it’s hard to make sure

that we didn’t break something downstream

OCP forces us to add functionality by creating new classes and then using an abstraction

Easier to create a new class and use it then to modify an existing one and make sure we didn’t break anything

OCP – Signs of Violation

OCP – Resolving Violations Instead of adding additional logic, need to move logic to an abstraction

Each if or switch statement needs to be moved to a new class with a public method

Define a new interface that has the method

New classes will implement the interface

Modify the original class to use the new abstraction

OCP – Resolving ViolationsMove logic to new classes

OCP – Resolving ViolationsDefine the new abstraction (Shape) and have the new classes implement it

OCP – Resolving Violations

OCP – Resolving Violations Need to add an additional shape (Triangle)?

Define a Triangle class Have it inherit from Shape abstract class Implement CalculateArea method

Notice how we don’t have to modify the AreaCalculator class to add additional shapes

Open/Closed PrincipleSummary

Classes should be open for extension, closed for modification

By introducing abstractions, we can easily extend our application without worrying about breaking something downstream

Allows us to add additional functionality by creating new classes, not modifying pre-existing ones

Single ResponsibilityOpen/ClosedLiskov SubstitutionInterface SegregationDependency Inversion

Liskov Substitution Principle

Liskov Substitution Principle If two classes are derived from the same abstraction, then they are

interchangeable

NOTE: Without Special Handling

Coined by Barbara Liskov

Referred to as LSP

LSP – Problem It Solves Abstractions hide implementation details

If we have to special handle the abstraction based on what it is, the code becomes much more complex and harder to maintain

Jeff Atwood (Coding Horror) refers to this as “leaky abstractions” because they leak implementation knowledge throughout the code base

LSP – Signs of Violation

LSP – Signs of Violation

What should happen if Quadrilateral is a Square?

LSP – Signs of ViolationSpecial handling based on the class

LSP – Resolving Violations Some cases, the abstraction doesn’t make sense

Square vs Rectangle Square doesn’t have length and width, it has a side Therefore, Quadrilateral is the wrong abstraction

Makes sense to find a better abstraction (not always possible)

In some cases, it’s possible to move the special handling logic to the offending class

LSP – Resolving Violations

Liskov Substitution PrincipleSummary

If two classes are derived from the same abstraction, then they should be interchangeable

We don’t have to add special handling code in the client

If found, try to find a better abstraction or move the special handling to the offending class

Single ResponsibilityOpen/ClosedLiskov SubstitutionInterface SegregationDependency Inversion

Interface Segregation Principle

Interface Segregation Principle Clients should only depend on what they need

Should not have to implement methods that aren’t used

Coined by Robert C. Martin

Referred to as ISP

ISP – Problem It Solves When we define “fat” interfaces, it’s hard to know what functionality we

actually need Ever tried to autocomplete and there were a lot of choices?

By having tighter interfaces, we can control what we expose to our clients

This in turn allows us to tailor our interfaces to what exactly our client needs Role interfaces vs Header interfaces (Martin Fowler)

ISP – Signs of ViolationAccess to Methods and Properties that aren’t being used

ISP – Resolving Violations Identify which methods are being used

Move those methods/properties to their own interface

Update the client to use the new interface

Update the original class to implement the new interface

Similar to Single Responsibility Principle, need to break the interface down into smaller pieces

ISP – Resolving Violation

ISP – Resolving ViolationIdentify methods that are being used in the client

ISP – Resolving ViolationMove the method to new interface, update Atm to implement both interfaces

ISP – Resolving ViolationUpdate AtmBalanceChecker to use IAtmBalanceChecker

Interface Segregation PrincipleSummary

Clients should only have access to methods and properties that they need

This allows us to create role interfaces, not header interfaces

We can spot violations by checking if our client has access to more than we need

Similar to Single Responsibility, break down large interfaces into smaller ones and update the client accordingly

Single ResponsibilityOpen/ClosedLiskov SubstitutionInterface SegregationDependency Inversion

Dependency Inversion Principle

Dependency Inversion Principle Concrete classes should depend upon abstractions, not other concrete

classes

Two rules Classes shouldn’t depend upon concrete classes Classes shouldn’t be responsible for creating their own dependencies

Coined by Robert C. Martin

Referred to as DIP

DIP – Problem It Solves If we have our concrete classes instantiate their own dependencies, the only

way to change these dependencies is to change the class which violates the Open/Closed Principle

Impossible to write unit tests that cross system boundaries (network communication, database access, file system)

Provides another way to determine if a class is doing too much (32 dependencies)

DIP – Signs of ViolationUsing the “new” keyword

DIP – Signs of ViolationUsing static classes

DIP – Signs of ViolationPassing concrete classes instead of abstractions

DIP – Resolving Violations Two goals

Make sure the dependency can be passed in Make sure the dependency has an abstraction

If the class is static, make it not static If the class doesn’t have an interface, define one (remember ISP)

Inject the dependency using constructor injection or method injection

DIP – Static Classes Static classes suck

Can’t pass them as parameters Can’t implement an interface or base class

Removing the static attribute is ideal, but not always possible

Using the Wrapper pattern, we can define another class that is not static to wrap around the static and then pass that around

DIP – Working With Static Classes

DIP – Working With Static Classes Define an interface that has all the public methods from the static class Create a new class that implements the interface and have the new class

call the static class

DIP – Passing Dependencies Method Injection

Passes the dependency as part of the method call Use when the dependency can change per method call

Constructor Injection Passes the dependency as part of instantiation Use when the dependency should be the same for the lifetime of the object

When deciding, we should ask ourselves “Will this change during the course of the program?”

DIP – Passing Dependencies

DIP – Passing Dependencies

Dependency Inversion PrincipleSummary

Concrete classes should depend upon abstractions, not other concrete classes

Allows us to switch dependencies at runtime Useful for testing

Use the Wrapper pattern to handle static classes

Use method injection or constructor injection for passing dependencies

Summary What is SOLID?

Why should our code be SOLID?

What the principles stand for How to spot violations How to fix them

top related