Follow along with the example (later) @

git hub .com
/ steve desmond - ca
/ solid - example

SOLID

! ! ! (yeah)

What is it good for?

Absolutely

Everything

SOLID

  1. Principles vs Patterns
  2. SOLID Principles
  3. Refactoring Example

Disclaimer

Facts vs Opinions

Principles vs Patterns

Principle:

  • a fundamental truth or proposition that serves as the foundation for a system of belief or behavior or for a chain of reasoning
  • aka "the reason why we do things"

Principles vs Patterns

Pattern:

  • a general, reusable solution to a commonly occurring problem within a given context in software design
  • a description or template for how to solve a problem that can be used in many different situations
  • not a finished design that can be transformed directly into source or machine code

Principles vs Patterns

  • Pattern = how
  • Principle = why
  • Principle = interface
  • Pattern = abstract class

 

Principles => Patterns => Frameworks

Anti-Patterns

  • a common response to a recurring problem that is usually ineffective and risks being highly counterproductive

Pattern = fact

Anti-pattern = opinion

SOLID Principles

  • Single responsibility
  • Open / closed
  • Liskov substitution
  • Interface segregation
  • Dependency inversion

Single Responsibility Principle

"Every module or class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class."

aka "Do one thing and do it well"

SRP Example

                            
                                class User
                                {
                                    int ID;
                                    string Username;
                                    string Email;
                                    string PasswordHash;

                                    static User get(id)
                                    { 
                                        return [user from DB];
                                    }
                                }

                                var user = User::get(123);
                            
                        
                            
                                class User
                                {
                                    int ID;
                                    string Username;
                                    string Email;
                                    string PasswordHash;
                                }

                                class UserRepository
                                {
                                    static User get(id)
                                    { 
                                        return [user from DB];
                                    }
                                }

                                var user = UserRepository::get(123);
                            
                        

Open/Closed Principle

"Software entities should be open for extension, but closed for modification."

aka "Don't override base/parent members"

OCP Example

                            
                                class Animal
                                {
                                    int LegCount()
                                    {
                                        return 4;
                                    }
                                }

                                class Human : Animal
                                {
                                    int LegCount()
                                    {
                                        return 2;
                                    }
                                }
                            
                        
                            
                                interface Animal
                                {
                                    int LegCount();
                                }

                                class Human : Animal
                                {
                                    int LegCount()
                                    {
                                        return 2;
                                    }
                                }

                                abstract class FourLeggedAnimal : Animal
                                {
                                    int LegCount()
                                    {
                                        return 4;
                                    }
                                }
                            
                        

Liskov Substitution Principle

"if S is a subtype of T, then objects of type T may be replaced with objects of type S without altering correctness."

aka "Strong Behavioral Subtyping"

LSP Example

                            
                                abstract class Vehicle
                                {
                                    void StartEngine() { ... }
                                    ...
                                }

                                class Car : Vehicle { ... }
                                
                                void GoSomewhere(Vehicle vehicle)
                                {
                                    vehicle.StartEngine();
                                    ...
                                }

                                class Bicycle : Vehicle { ... }
                            
                        
                            
                                abstract class Vehicle
                                {
                                    ...
                                }

                                abstract class MotorVehicle : Vehicle
                                {
                                    void StartEngine() { ... }
                                }

                                class Car : MotorVehicle { ... }
                                class Bicycle : Vehicle { ... }
                                
                                void GoSomewhere(Vehicle vehicle)
                                {
                                    if (vehicle is MotorVehicle mv)
                                        mv.StartEngine();
                                    ...
                                }
                            
                        

Interface Segregation Principle

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

aka "Many simple interfaces are better than one complex one"

ISP Example

                            
                                interface UserRepository
                                {
                                    User get(id);
                                    void save(user);
                                }

                                class UserServiceClient : UserRepository
                                {
                                    User get(id)
                                    {
                                        return [user from microservice];
                                    }

                                    void save(user)
                                    {
                                        [???]
                                    }
                                }
                            
                        
                            
                                interface UserReader
                                {
                                    User get(id);
                                }

                                class UserServiceReader : UserReader
                                {
                                    User get(id)
                                    {
                                        return [user from microservice];
                                    }
                                }

                                interface UserWriter
                                {
                                    void save(user);
                                }

                                interface UserRepository : UserReader,
                                                            UserWriter
                            
                        

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.

aka "Dependency Injection"

DI Example

                            
                                class UserRepository
                                {
                                    DB db;

                                    new()
                                    {
                                        db = new DB(Global.ConnString);
                                    }

                                    User get(id)
                                    {
                                        return [user from db];
                                    }
                                }

                                var user_repo = new UserRepository();
                                var user = user_repo.get(123);
                            
                        
                            
                                class UserRepository
                                {
                                    DB db;

                                    new(DB injected_db)
                                    {
                                        db = injected_db;
                                    }

                                    User get(id)
                                    {
                                        return [user from db];
                                    }
                                }

                                var db = new DB(Global.ConnString);
                                var user_repo = new UserRepository(db);
                                var user = user_repo.get(123);
                            
                        

SOLID Principles

  • Single responsibility
  • Open / closed
  • Liskov substitution
  • Interface segregation
  • Dependency inversion

Refactoring
Example

Refactoring

"The process of restructuring existing computer code without changing its external behavior."

Tip #1

Use Frameworks

Tip #2

Don't Blindly Use Frameworks

Understand how they work

Tip #3

Libraries can provide great abstraction layers

But are also their own form of coupling

SOLID growth

Lines of code chart

Tip #4

Determine your own "good enough" thresholds

Trade-offs

Shout-Out

Corgibytes

SOLID Principles

  • Single responsibility
  • Open / closed
  • Liskov substitution
  • Interface segregation
  • Dependency inversion

Further Reading

Special thanks
to IWP's
solid organizers

Steve Desmond Software Development