SlideShare a Scribd company logo
by Jon Kruger
   Definition:

“A method of programming based on a hierarchy of
classes, and well-defined and cooperating objects.”

 The SOLID principles are principles of object-
oriented class design
   Your code is going to change
   Make your code more reusable (DRY)
   Testability
   Make our lives easier!
 Fewer bugs – it costs money to find bugs, fix
bugs, and clean up the mess created by bugs.
 More flexibility – since code will need to change, it
should be easy to change
   It costs money to develop software
   It costs money to fix bugs
   It costs money to make changes to software
Agile Software
Development
Principles, Patterns, and
Practices,
by Robert C. Martin (aka
“Uncle Bob” Martin)
Clean Code: A Handbook of
Agile Software Craftsmanship,
by Robert C. Martin (aka
“Uncle Bob” Martin)
   These are guidelines, not hard and fast rules
   Use your brain – do what makes sense
   Ask why
   Software should be:
     Easy to test
     Easy to change
     Easy to add features to
   Easy != not learning a new way of doing things
 Have only as much complexity as you need – have a
reason for complexity
 “I don’t want to learn this new way” != too complex
A class should have one, and only one, reason to
change.
public class Person
{
    private const decimal _minimumRequiredBalance = 10m;

    public string Name { get; set; }
    public decimal Balance { get; set; }

    public decimal AvailableFunds
    {
        get { return Balance - _minimumRequiredBalance; }
    }

    public void DeductFromBalanceBy(decimal amountToDeduct)
    {
        if (amountToDeduct > Balance)
            throw new InvalidOperationException(“Insufficient funds.”);

        Balance -= amountToDeduct;
    }
}
public class Account
{
    private const decimal _minimumRequiredBalance = 10m;

    public decimal Balance { get; set; }
    public IList<Person> AccountHolders { get; set; }

    public decimal AvailableFunds
    {
        get { return Balance - _minimumRequiredBalance; }
    }

    public void DeductFromBalanceBy(decimal amountToDeduct)
    {
        if (amountToDeduct > Balance)
            throw new InvalidOperationException(“Insufficient funds.”);

        Balance -= amountToDeduct;
    }
}
public class Person
{
    public string Name { get; set; }
    public Account Account { get; set; }

    public decimal AvailableFunds
    {
        get { return Account.AvailableFunds; }
    }

    public decimal AccountBalance
    {
        get { return Account.Balance; }
    }

    public void DeductFromBalanceBy(decimal amountToDeduct)
    {
        Account.DeductFromBalanceBy(amountToDeduct);
    }
}
public class OrderProcessingModule {
               public void Process(OrderStatusMessage orderStatusMessage) {
                // Get the connection string from configuration
SRP             string connectionString = ConfigurationManager.ConnectionStrings["Main"].ConnectionString;

                      Order order = null;
Violation -           using (SqlConnection connection = new SqlConnection(connectionString)) {

Spaghetti               // go get some data from the database
                        order = fetchData(orderStatusMessage, connection);
                      }
Code                  // Apply the changes to the Order from the OrderStatusMessage
                      updateTheOrder(order);

                      // International orders have a unique set of business rules
                      if (order.IsInternational)
                        processInternationalOrder(order);

                      // We need to treat larger orders in a special manner
                      else if (order.LineItems.Count > 10)
                        processLargeDomesticOrder(order);

                      // Smaller domestic orders
                      else
                        processRegularDomesticOrder(order);

                      // Ship the order if it's ready
                      if (order.IsReadyToShip()) {
                        ShippingGateway gateway = new ShippingGateway();

                       // Transform the Order object into a Shipment
                       ShipmentMessage message = createShipmentMessageForOrder(order);
                       gateway.SendShipment(message);
                  }
              }
UI

Business Logic (Domain Model)

        Data Access

            Database
public class OrderService
{
    public Order Get(int orderId) { ... }
    public Order Save(Order order) { ... }
    public Order SubmitOrder(Order order) { ... }
    public Order GetOrderByName(string name) { ... }
    public void CancelOrder(int orderId) { ... }
    public void ProcessOrderReturn(int orderId) { ... }
    public IList<Order> GetAllOrders { ... }
    public IList<Order> GetShippedOrders { ... }
    public void ShipOrder { ... }
}
Fill out the XML doc comments for the class – be
wary of words like if, and, but, except, when, etc.

/// <summary>
/// Gets, saves, and submits orders.
/// </summary>
public class OrderService
{
    public Order Get(int orderId) { ... }
    public Order Save(Order order) { ... }
    public Order SubmitOrder(Order order) { ... }
}
Domain services should have a verb in the class
name
public class GetOrderService
{
    public Order Get(int orderId) { ... }
}

public class SaveOrderService
{
    public Order Save(Order order) { ... }
}

public class SubmitOrderService
{
    public Order SubmitOrder(Order order) { ... }
}
   We want it to be easy to reuse code
   Big classes are more difficult to change
   Big classes are harder to read

Smaller classes and smaller methods will give you
more flexibility, and you don’t have to write much
extra code (if any) to do it!
 The violating class is not going to be reused and
other classes don’t depend on it
 The violating class does not have private fields that
store values that the class uses
 Your common sense says so
 Example: ASP.NET MVC controller classes, web
services
 Don’t code for situations that you won’t ever need
 Don’t create unneeded complexity
 However, more class files != more complicated
 Remember, this is supposed to make your lives
easier! (but not easier to be lazy)
 You can always refactor later (if you write tests)
  A method should have one purpose (reason to
change)
 Easier to read and write, which means you are less
likely to write bugs
 Write out the steps of a method using plain English
method names
public void SubmitOrder(Order order)
{
    // validate order
    if (order.Products.Count == 0)
    {
        throw new InvalidOperationException(
            "Select a product.");
    }

    // calculate tax
    order.Tax = order.Subtotal * 1.0675;

    // calculate shipping
    if (order.Subtotal < 25)
         order.ShippingCharges = 5;
    else
         order.ShippingCharges = 10;

    // submit order
    _orderSubmissionService.SubmitOrder(order);
}
public void SubmitOrder(Order order)
{
    ValidateOrder(order);
    CalculateTax(order);
    CalculateShipping(order);
    SendOrderToOrderSubmissionService(order);
}
public void SubmitOrder(Order order)
          {
              ValidateOrder(order);
Small         CalculateTax(order);
              CalculateShipping(order);
Methods   }
              SendOrderToOrderSubmissionService(order);


- After   public void ValidateOrder(Order order)
          {
              if (order.Products.Count == 0)
                  throw new InvalidOperationException("Select a product.");
          }

          public void CalculateTax(Order order)
          {
              order.Tax = order.Subtotal * 1.0675;
          }

          public void CalculateShipping(Order order)
          {
              if (order.Subtotal < 25)
                  order.ShippingCharges = 5;
              else
                  order.ShippingCharges = 10;
          }

          public void SendOrderToOrderSubmissionService(Order order)
          {
              _orderSubmissionService.SubmitOrder(order);
          }
Software entities (classes, modules, methods) should
be open for extension but closed for modification.
public class GetUserService
{
    public IList<UserSummary> FindUsers(UserSearchType type)
    {
        IList<User> users;
        switch (type)
        {
             case UserSearchType.AllUsers:
                 // load the “users” variable here
                 break;
             case UserSearchType.AllActiveUsers:
                 // load the “users” variable here
                 break;
             case UserSearchType.ActiveUsersThatCanEditQuotes:
                 // load the “users” variable here
                 break;
        }
        return ConvertToUserSummaries(users);
    }
}
public interface IUserQuery
{
    IList<User> FilterUsers(IList<User> allUsers);
}

public class GetUserService
{
    public IList<UserSummary> FindUsers(IUserQuery query)
    {
        IList<User> users = query.FilterUsers(GetAllUsers());
        return ConvertToUserSummaries(users);
    }
}
 Anytime you change code, you have the potential to
break it
 Sometimes you can’t change libraries (e.g. code that
isn’t yours)
 May have to change code in many different places
to add support for a certain type of situation
 When the number of options in the if or switch
statement is unlikely to change (e.g. switch on enum)
public void UpdateFontStyle (Paragraph paragraph)
{
    switch (IsBoldCheckBox.CheckState)
    {
        case CheckState.Checked:
            paragraph.IsBold = true;
            break;
        case CheckState.Unchecked:
            paragraph.IsBold = false;
            break;
        case CheckState.Indeterminate:
            break;
    }
}
  Use if/switch if the number of cases is unlikely to
change
 Use strategy pattern when the number of cases are
likely to change
 Always use common sense!
 Don’t code for situations that you won’t ever need
 Don’t create unneeded complexity
 However, more class files != more complicated
 Remember, this is supposed to make your lives
easier!
 You can always refactor later (if you write tests)
Functions that use references to base classes must be
able to use objects of derived classes without knowing
it.
public class Product
{
    public string Name { get; set; }
    public string Author { get; set; }
}

public class Book : Product    {}

public class Movie : Product    {}



If someone had a Product object (which was actually
a Movie) and asked for the Author, what should it do
(a Movie doesn’t have an Author)?
People using derived classes should not encounter
unexpected results when using your derived class.
public class MyList<T> : IList<T>
{
    private readonly List<T> _innerList = new List<T>();

    public void Add(T item)
    {
        if (_innerList.Contains(item))
            return;
        _innerList.Add(item);
    }

    public int Count
    {
        get { return _innerList.Count; }
    }
}
Throw exceptions for cases that you can’t support (still
not recommended)
public class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }
    public override double Area
    {
        get { return Width * Height; }
    }
}

public class Cube : Shape
{
    public override double Area
    {
        get { throw new NotSupportedException(); }
    }
}
Clients should not be forced to depend on interfaces
that they do not use.
ASP.NET
MembershipProvider
class – a very “fat”
interface!
 If you implement an interface or derive from a base
class and you have to throw an exception in a method
because you don’t support it, the interface is probably
too big.
 Single Responsibility Principle for interfaces/base
classes
 If your interface has members that are not used by
some inheritors, those inheritors may be affected by
changes in the interface, even though the methods
that they use did not change.
   Why would you want to?
   Use common sense
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.
 Two classes are “tightly coupled” if they are linked
together and are dependent on each other
 Tightly coupled classes can not work independent of
each other
 Makes changing one class difficult because it could
launch a wave of changes through tightly coupled
classes
UI

Business Logic (Domain Model)

        Data Access

            Database
UI
           Interfaces

Business Logic (Domain Model)
           Interfaces

        Data Access

            Database
 Each layer should not know anything about the
details of how the other layers work.
 Example: your domain model should not know how
data access is done – it shouldn’t know if you’re using
stored procedures, an ORM, etc.
 Tight coupling is bad – if your business layer
contains code related to data access, changes to how
data access is done will affect business logic
 Harder to test because you have to deal with
implementation details of something you’re not trying
to test
How do you know that your code is working?
How do you know that your code will continue to
work after you change it?
   Unit tests:
     Tests a small unit of functionality
     Mock or “fake out” external dependencies (e.g. databases)
     Run fast

   Integration tests:
     Test the whole system working together
     Can run slow
     Can be brittle
Stubs, mocks, and fakes in unit tests are only
possible when we have an interface to implement

The main reason for the Dependency Inversion
Principle is to help us write unit tests.
public class ProductRepository : IProductRepository
{
    public Product Get(int id) { ... }
}

public interface IProductRepository
{
    Product Get(int id);
}
public class GetProductService : IGetProductService
{
    private IProductRepository _productRepository;

    public GetProductService(
        IProductRepository productRepository)
    {
        _productRepository = productRepository;
    }

    public IList<Product> GetProductById(int id)
    {
        return _productRepository.Get(id);
    }
}
   Use of “new”

    public class GetProductService
    {
        public IList<Product> GetProductById(int id)
        {
            var productRepository = new ProductRepository();
            return productRepository.Get(id);
        }
    }
   Use of “static”

    public class SecurityService
    {
        public static User GetCurrentUser()
        {
            // do something
        }
    }
   Use of singletons using “static”

    public class ProductCache
    {
        private static readonly _instance = new ProductCache();
        public static ProductCache Instance
        {
            get { return _instance; }
        }
    }
public class GetProductService : IGetProductService
{
    private IProductRepository _productRepository;

    public GetProductService(
        IProductRepository productRepository)
    {
        _productRepository = productRepository;
    }

    public IList<Product> GetProductById(int id)
    {
        return _productRepository.Get(id);
    }
}


Problem: How do we create these objects?
 Creates objects that are ready for you to use
 Knows how to create objects and their
dependencies
 Knows how to initialize objects when they are
created (if necessary)
 Popular .NET choices:
   StructureMap, Ninject
 Other .NET choices:
   Unity, Castle Windsor, Autofac, Spring .NET
 Java
   Spring
 Ruby
   We don’t need no stinkin’ DI containers!
ObjectFactory.Initialize(x =>
{
    x.For<IGetProductService>().Use<GetProductService>();
});
ObjectFactory.Initialize(x =>
{
    x.Scan(scan =>
    {
        scan.WithDefaultConventions();
        scan.AssemblyContainingType<IProductRepository>();
    });
});



 Automatically map “ISomething” interface to
“Something” class
ObjectFactory.Initialize(x =>
{
    x.For<IProductRepository>()
     .Use<ProductRepository>()
     .OnCreation(repository =>
         repository.ConnectionString =
         ConfigurationManager.AppSettings["MainDB"]);
});


 We just reduced duplication and complexity by
setting this up here!
ObjectFactory.Initialize(x =>
{
    x.ForSingletonOf<IProductCache>().Use<ProductCache>();
});




   There will only ever be one IProductCache
   We don’t violate DIP by having static variables
ObjectFactory.Initialize(x =>
{
    x.For<ICurrentUser>()
     .Use(c => new CurrentUser(Thread.CurrentPrincipal));
});




Testing will be easier because we won’t reference
Thread.CurrentPrincipal
   Don’t “new” up anything that is a dependency
       Don’t new up classes that you want to create a fake for in a test
       Do new up entity objects
       Do new up value types (e.g. string, DateTime, etc.)
       Do new up .NET Framework types (e.g. SqlConnection)
  Entity objects should not have dependencies
  If you have to have static variables, isolate them
behind the DI container (e.g. example in previous
slide)
 Use ObjectFactory.GetInstance() to create objects
when you can’t take them in as constructor
parameters
 Don’t use the DI container when writing unit tests
USE YOUR BRAIN!!!!
   Uncle Bob’s SOLID articles
     http://bit.ly/solid1
   Uncle Bob talking about SOLID on Hanselminutes
     http://bit.ly/solid2
   My slides
     http://bit.ly/solid3
   ALT.NET mailing list
     http://bit.ly/solid4

My Info:
email: jon@jonkruger.com
twitter: @jonkruger / blog: http://jonkruger.com/blog
TDD training: http://tddbootcamp.com

More Related Content

What's hot

Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...
go_oh
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDDeveloping application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDD
Michele Capra
 
The IoC Hydra
The IoC HydraThe IoC Hydra
The IoC Hydra
Kacper Gunia
 
JavaScript Promises
JavaScript PromisesJavaScript Promises
JavaScript Promises
L&T Technology Services Limited
 
Design Patterns in PHP5
Design Patterns in PHP5 Design Patterns in PHP5
Design Patterns in PHP5 Wildan Maulana
 
Backbone js
Backbone jsBackbone js
Backbone js
rstankov
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
rstankov
 
Why ruby
Why rubyWhy ruby
Why ruby
rstankov
 
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Raimonds Simanovskis
 
Design Patterns Reconsidered
Design Patterns ReconsideredDesign Patterns Reconsidered
Design Patterns Reconsidered
Alex Miller
 
Powerful JavaScript Tips and Best Practices
Powerful JavaScript Tips and Best PracticesPowerful JavaScript Tips and Best Practices
Powerful JavaScript Tips and Best Practices
Dragos Ionita
 
Java Script Promise
Java Script PromiseJava Script Promise
Java Script PromiseAlok Guha
 
Understanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptUnderstanding Asynchronous JavaScript
Understanding Asynchronous JavaScript
jnewmanux
 
Art of Javascript
Art of JavascriptArt of Javascript
Art of Javascript
Tarek Yehia
 
Rails on Oracle 2011
Rails on Oracle 2011Rails on Oracle 2011
Rails on Oracle 2011
Raimonds Simanovskis
 
FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6
Dmitry Soshnikov
 
Hacking hhvm
Hacking hhvmHacking hhvm
Hacking hhvm
wajrcs
 
Node.js in action
Node.js in actionNode.js in action
Node.js in action
Simon Su
 
Building a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing StrategiesBuilding a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing Strategies
CiaranMcNulty
 

What's hot (20)

Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...Singletons in PHP - Why they are bad and how you can eliminate them from your...
Singletons in PHP - Why they are bad and how you can eliminate them from your...
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDDeveloping application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDD
 
The IoC Hydra
The IoC HydraThe IoC Hydra
The IoC Hydra
 
JavaScript Promises
JavaScript PromisesJavaScript Promises
JavaScript Promises
 
Design Patterns in PHP5
Design Patterns in PHP5 Design Patterns in PHP5
Design Patterns in PHP5
 
Backbone js
Backbone jsBackbone js
Backbone js
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
Why ruby
Why rubyWhy ruby
Why ruby
 
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Design Patterns Reconsidered
Design Patterns ReconsideredDesign Patterns Reconsidered
Design Patterns Reconsidered
 
Powerful JavaScript Tips and Best Practices
Powerful JavaScript Tips and Best PracticesPowerful JavaScript Tips and Best Practices
Powerful JavaScript Tips and Best Practices
 
Java Script Promise
Java Script PromiseJava Script Promise
Java Script Promise
 
Understanding Asynchronous JavaScript
Understanding Asynchronous JavaScriptUnderstanding Asynchronous JavaScript
Understanding Asynchronous JavaScript
 
Art of Javascript
Art of JavascriptArt of Javascript
Art of Javascript
 
Rails on Oracle 2011
Rails on Oracle 2011Rails on Oracle 2011
Rails on Oracle 2011
 
FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6FalsyValues. Dmitry Soshnikov - ECMAScript 6
FalsyValues. Dmitry Soshnikov - ECMAScript 6
 
Hacking hhvm
Hacking hhvmHacking hhvm
Hacking hhvm
 
Node.js in action
Node.js in actionNode.js in action
Node.js in action
 
Building a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing StrategiesBuilding a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing Strategies
 

Viewers also liked

SOLID principles
SOLID principlesSOLID principles
SOLID principles
Dmitry Kandalov
 
software design principles
software design principlessoftware design principles
software design principles
Cristal Ngo
 
Presentation on SOLID design principles
Presentation on SOLID design principlesPresentation on SOLID design principles
Presentation on SOLID design principles
Kostadin Golev
 
SOLID Design Principles
SOLID Design PrinciplesSOLID Design Principles
SOLID Design Principles
Andreas Enbohm
 
SOLID Principles and Design Patterns
SOLID Principles and Design PatternsSOLID Principles and Design Patterns
SOLID Principles and Design Patterns
Ganesh Samarthyam
 
Are You a SOLID Coder?
Are You a SOLID Coder?Are You a SOLID Coder?
Are You a SOLID Coder?
Steve Green
 
SOLID Design Principles
SOLID Design PrinciplesSOLID Design Principles
SOLID Design PrinciplesSamuel Breed
 
SOLID principles
SOLID principlesSOLID principles
SOLID principles
Jonathan Holloway
 
Introduction to SOLID Principles
Introduction to SOLID PrinciplesIntroduction to SOLID Principles
Introduction to SOLID Principles
Ganesh Samarthyam
 
Geecon09: SOLID Design Principles
Geecon09: SOLID Design PrinciplesGeecon09: SOLID Design Principles
Geecon09: SOLID Design Principles
Bruno Bossola
 
SOLID Principles part 2
SOLID Principles part 2SOLID Principles part 2
SOLID Principles part 2
Dennis van der Stelt
 
Solid principles of oo design
Solid principles of oo designSolid principles of oo design
Solid principles of oo design
Confiz
 
SOLID - Principles of Object Oriented Design
SOLID - Principles of Object Oriented DesignSOLID - Principles of Object Oriented Design
SOLID - Principles of Object Oriented Design
Riccardo Cardin
 

Viewers also liked (15)

SOLID principles
SOLID principlesSOLID principles
SOLID principles
 
software design principles
software design principlessoftware design principles
software design principles
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Presentation on SOLID design principles
Presentation on SOLID design principlesPresentation on SOLID design principles
Presentation on SOLID design principles
 
SOLID Design Principles
SOLID Design PrinciplesSOLID Design Principles
SOLID Design Principles
 
SOLID Principles and Design Patterns
SOLID Principles and Design PatternsSOLID Principles and Design Patterns
SOLID Principles and Design Patterns
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Are You a SOLID Coder?
Are You a SOLID Coder?Are You a SOLID Coder?
Are You a SOLID Coder?
 
SOLID Design Principles
SOLID Design PrinciplesSOLID Design Principles
SOLID Design Principles
 
SOLID principles
SOLID principlesSOLID principles
SOLID principles
 
Introduction to SOLID Principles
Introduction to SOLID PrinciplesIntroduction to SOLID Principles
Introduction to SOLID Principles
 
Geecon09: SOLID Design Principles
Geecon09: SOLID Design PrinciplesGeecon09: SOLID Design Principles
Geecon09: SOLID Design Principles
 
SOLID Principles part 2
SOLID Principles part 2SOLID Principles part 2
SOLID Principles part 2
 
Solid principles of oo design
Solid principles of oo designSolid principles of oo design
Solid principles of oo design
 
SOLID - Principles of Object Oriented Design
SOLID - Principles of Object Oriented DesignSOLID - Principles of Object Oriented Design
SOLID - Principles of Object Oriented Design
 

Similar to Solid Software Design Principles

SOLID - Not Just a State of Matter, It's Principles for OO Propriety
SOLID - Not Just a State of Matter, It's Principles for OO ProprietySOLID - Not Just a State of Matter, It's Principles for OO Propriety
SOLID - Not Just a State of Matter, It's Principles for OO ProprietyChris Weldon
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
Jonathan Wage
 
SOLID
SOLIDSOLID
The uniform interface is 42
The uniform interface is 42The uniform interface is 42
The uniform interface is 42
Yevhen Bobrov
 
That’s My App - Running in Your Background - Draining Your Battery
That’s My App - Running in Your Background - Draining Your BatteryThat’s My App - Running in Your Background - Draining Your Battery
That’s My App - Running in Your Background - Draining Your Battery
Michael Galpin
 
CDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptorCDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptor
Caelum
 
Real Life Clean Architecture
Real Life Clean ArchitectureReal Life Clean Architecture
Real Life Clean Architecture
Mattia Battiston
 
Combatendo code smells em Java
Combatendo code smells em Java Combatendo code smells em Java
Combatendo code smells em Java
Emmanuel Neri
 
Bot builder v4 HOL
Bot builder v4 HOLBot builder v4 HOL
Bot builder v4 HOL
Cheah Eng Soon
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
javatwo2011
 
Imagine a world without mocks
Imagine a world without mocksImagine a world without mocks
Imagine a world without mocks
kenbot
 
Pragmatic Functional Refactoring with Java 8
Pragmatic Functional Refactoring with Java 8Pragmatic Functional Refactoring with Java 8
Pragmatic Functional Refactoring with Java 8
Codemotion
 
JDK Power Tools
JDK Power ToolsJDK Power Tools
JDK Power Tools
Tobias Lindaaker
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
Adam Stephensen
 
RESTEasy
RESTEasyRESTEasy
Advanced #2 networking
Advanced #2   networkingAdvanced #2   networking
Advanced #2 networking
Vitali Pekelis
 
May 2010 - RestEasy
May 2010 - RestEasyMay 2010 - RestEasy
May 2010 - RestEasy
JBug Italy
 
TDC2017 | São Paulo - Trilha Android How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Android How we figured out we had a SRE team at ...TDC2017 | São Paulo - Trilha Android How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Android How we figured out we had a SRE team at ...
tdc-globalcode
 
Gwt and Xtend
Gwt and XtendGwt and Xtend
Gwt and Xtend
Sven Efftinge
 

Similar to Solid Software Design Principles (20)

SOLID - Not Just a State of Matter, It's Principles for OO Propriety
SOLID - Not Just a State of Matter, It's Principles for OO ProprietySOLID - Not Just a State of Matter, It's Principles for OO Propriety
SOLID - Not Just a State of Matter, It's Principles for OO Propriety
 
Nancy + rest mow2012
Nancy + rest   mow2012Nancy + rest   mow2012
Nancy + rest mow2012
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
SOLID
SOLIDSOLID
SOLID
 
The uniform interface is 42
The uniform interface is 42The uniform interface is 42
The uniform interface is 42
 
That’s My App - Running in Your Background - Draining Your Battery
That’s My App - Running in Your Background - Draining Your BatteryThat’s My App - Running in Your Background - Draining Your Battery
That’s My App - Running in Your Background - Draining Your Battery
 
CDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptorCDI e as ideias pro futuro do VRaptor
CDI e as ideias pro futuro do VRaptor
 
Real Life Clean Architecture
Real Life Clean ArchitectureReal Life Clean Architecture
Real Life Clean Architecture
 
Combatendo code smells em Java
Combatendo code smells em Java Combatendo code smells em Java
Combatendo code smells em Java
 
Bot builder v4 HOL
Bot builder v4 HOLBot builder v4 HOL
Bot builder v4 HOL
 
比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
 
Imagine a world without mocks
Imagine a world without mocksImagine a world without mocks
Imagine a world without mocks
 
Pragmatic Functional Refactoring with Java 8
Pragmatic Functional Refactoring with Java 8Pragmatic Functional Refactoring with Java 8
Pragmatic Functional Refactoring with Java 8
 
JDK Power Tools
JDK Power ToolsJDK Power Tools
JDK Power Tools
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
RESTEasy
RESTEasyRESTEasy
RESTEasy
 
Advanced #2 networking
Advanced #2   networkingAdvanced #2   networking
Advanced #2 networking
 
May 2010 - RestEasy
May 2010 - RestEasyMay 2010 - RestEasy
May 2010 - RestEasy
 
TDC2017 | São Paulo - Trilha Android How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Android How we figured out we had a SRE team at ...TDC2017 | São Paulo - Trilha Android How we figured out we had a SRE team at ...
TDC2017 | São Paulo - Trilha Android How we figured out we had a SRE team at ...
 
Gwt and Xtend
Gwt and XtendGwt and Xtend
Gwt and Xtend
 

More from Jon Kruger

The Business of You: 10 Steps To Run Your Career Like a Business
The Business of You: 10 Steps To Run Your Career Like a BusinessThe Business of You: 10 Steps To Run Your Career Like a Business
The Business of You: 10 Steps To Run Your Career Like a Business
Jon Kruger
 
Developing an Automated Testing Strategy
Developing an Automated Testing StrategyDeveloping an Automated Testing Strategy
Developing an Automated Testing StrategyJon Kruger
 
A Whole Team Approach To Testing
A Whole Team Approach To TestingA Whole Team Approach To Testing
A Whole Team Approach To TestingJon Kruger
 
An ATDD Case Study
An ATDD Case StudyAn ATDD Case Study
An ATDD Case Study
Jon Kruger
 
Productivity Boosters for .NET Developers
Productivity Boosters for .NET DevelopersProductivity Boosters for .NET Developers
Productivity Boosters for .NET DevelopersJon Kruger
 
Test-Driven Development In Action
Test-Driven Development In ActionTest-Driven Development In Action
Test-Driven Development In Action
Jon Kruger
 
Advanced Object-Oriented/SOLID Principles
Advanced Object-Oriented/SOLID PrinciplesAdvanced Object-Oriented/SOLID Principles
Advanced Object-Oriented/SOLID Principles
Jon Kruger
 

More from Jon Kruger (7)

The Business of You: 10 Steps To Run Your Career Like a Business
The Business of You: 10 Steps To Run Your Career Like a BusinessThe Business of You: 10 Steps To Run Your Career Like a Business
The Business of You: 10 Steps To Run Your Career Like a Business
 
Developing an Automated Testing Strategy
Developing an Automated Testing StrategyDeveloping an Automated Testing Strategy
Developing an Automated Testing Strategy
 
A Whole Team Approach To Testing
A Whole Team Approach To TestingA Whole Team Approach To Testing
A Whole Team Approach To Testing
 
An ATDD Case Study
An ATDD Case StudyAn ATDD Case Study
An ATDD Case Study
 
Productivity Boosters for .NET Developers
Productivity Boosters for .NET DevelopersProductivity Boosters for .NET Developers
Productivity Boosters for .NET Developers
 
Test-Driven Development In Action
Test-Driven Development In ActionTest-Driven Development In Action
Test-Driven Development In Action
 
Advanced Object-Oriented/SOLID Principles
Advanced Object-Oriented/SOLID PrinciplesAdvanced Object-Oriented/SOLID Principles
Advanced Object-Oriented/SOLID Principles
 

Recently uploaded

AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
Product School
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Product School
 
Generating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using SmithyGenerating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using Smithy
g2nightmarescribd
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
Product School
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Jeffrey Haguewood
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Product School
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
Elena Simperl
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Inflectra
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 

Recently uploaded (20)

AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...
 
Generating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using SmithyGenerating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using Smithy
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 

Solid Software Design Principles

  • 2. Definition: “A method of programming based on a hierarchy of classes, and well-defined and cooperating objects.”  The SOLID principles are principles of object- oriented class design
  • 3.
  • 4.
  • 5. Your code is going to change  Make your code more reusable (DRY)  Testability  Make our lives easier!
  • 6.  Fewer bugs – it costs money to find bugs, fix bugs, and clean up the mess created by bugs.  More flexibility – since code will need to change, it should be easy to change
  • 7.
  • 8. It costs money to develop software  It costs money to fix bugs  It costs money to make changes to software
  • 9. Agile Software Development Principles, Patterns, and Practices, by Robert C. Martin (aka “Uncle Bob” Martin)
  • 10. Clean Code: A Handbook of Agile Software Craftsmanship, by Robert C. Martin (aka “Uncle Bob” Martin)
  • 11. These are guidelines, not hard and fast rules  Use your brain – do what makes sense  Ask why
  • 12. Software should be:  Easy to test  Easy to change  Easy to add features to  Easy != not learning a new way of doing things
  • 13.  Have only as much complexity as you need – have a reason for complexity  “I don’t want to learn this new way” != too complex
  • 14. A class should have one, and only one, reason to change.
  • 15.
  • 16. public class Person { private const decimal _minimumRequiredBalance = 10m; public string Name { get; set; } public decimal Balance { get; set; } public decimal AvailableFunds { get { return Balance - _minimumRequiredBalance; } } public void DeductFromBalanceBy(decimal amountToDeduct) { if (amountToDeduct > Balance) throw new InvalidOperationException(“Insufficient funds.”); Balance -= amountToDeduct; } }
  • 17. public class Account { private const decimal _minimumRequiredBalance = 10m; public decimal Balance { get; set; } public IList<Person> AccountHolders { get; set; } public decimal AvailableFunds { get { return Balance - _minimumRequiredBalance; } } public void DeductFromBalanceBy(decimal amountToDeduct) { if (amountToDeduct > Balance) throw new InvalidOperationException(“Insufficient funds.”); Balance -= amountToDeduct; } }
  • 18. public class Person { public string Name { get; set; } public Account Account { get; set; } public decimal AvailableFunds { get { return Account.AvailableFunds; } } public decimal AccountBalance { get { return Account.Balance; } } public void DeductFromBalanceBy(decimal amountToDeduct) { Account.DeductFromBalanceBy(amountToDeduct); } }
  • 19. public class OrderProcessingModule { public void Process(OrderStatusMessage orderStatusMessage) { // Get the connection string from configuration SRP string connectionString = ConfigurationManager.ConnectionStrings["Main"].ConnectionString; Order order = null; Violation - using (SqlConnection connection = new SqlConnection(connectionString)) { Spaghetti // go get some data from the database order = fetchData(orderStatusMessage, connection); } Code // Apply the changes to the Order from the OrderStatusMessage updateTheOrder(order); // International orders have a unique set of business rules if (order.IsInternational) processInternationalOrder(order); // We need to treat larger orders in a special manner else if (order.LineItems.Count > 10) processLargeDomesticOrder(order); // Smaller domestic orders else processRegularDomesticOrder(order); // Ship the order if it's ready if (order.IsReadyToShip()) { ShippingGateway gateway = new ShippingGateway(); // Transform the Order object into a Shipment ShipmentMessage message = createShipmentMessageForOrder(order); gateway.SendShipment(message); } }
  • 20. UI Business Logic (Domain Model) Data Access Database
  • 21. public class OrderService { public Order Get(int orderId) { ... } public Order Save(Order order) { ... } public Order SubmitOrder(Order order) { ... } public Order GetOrderByName(string name) { ... } public void CancelOrder(int orderId) { ... } public void ProcessOrderReturn(int orderId) { ... } public IList<Order> GetAllOrders { ... } public IList<Order> GetShippedOrders { ... } public void ShipOrder { ... } }
  • 22. Fill out the XML doc comments for the class – be wary of words like if, and, but, except, when, etc. /// <summary> /// Gets, saves, and submits orders. /// </summary> public class OrderService { public Order Get(int orderId) { ... } public Order Save(Order order) { ... } public Order SubmitOrder(Order order) { ... } }
  • 23. Domain services should have a verb in the class name public class GetOrderService { public Order Get(int orderId) { ... } } public class SaveOrderService { public Order Save(Order order) { ... } } public class SubmitOrderService { public Order SubmitOrder(Order order) { ... } }
  • 24. We want it to be easy to reuse code  Big classes are more difficult to change  Big classes are harder to read Smaller classes and smaller methods will give you more flexibility, and you don’t have to write much extra code (if any) to do it!
  • 25.  The violating class is not going to be reused and other classes don’t depend on it  The violating class does not have private fields that store values that the class uses  Your common sense says so  Example: ASP.NET MVC controller classes, web services
  • 26.  Don’t code for situations that you won’t ever need  Don’t create unneeded complexity  However, more class files != more complicated  Remember, this is supposed to make your lives easier! (but not easier to be lazy)  You can always refactor later (if you write tests)
  • 27.
  • 28.  A method should have one purpose (reason to change)  Easier to read and write, which means you are less likely to write bugs  Write out the steps of a method using plain English method names
  • 29. public void SubmitOrder(Order order) { // validate order if (order.Products.Count == 0) { throw new InvalidOperationException( "Select a product."); } // calculate tax order.Tax = order.Subtotal * 1.0675; // calculate shipping if (order.Subtotal < 25) order.ShippingCharges = 5; else order.ShippingCharges = 10; // submit order _orderSubmissionService.SubmitOrder(order); }
  • 30. public void SubmitOrder(Order order) { ValidateOrder(order); CalculateTax(order); CalculateShipping(order); SendOrderToOrderSubmissionService(order); }
  • 31. public void SubmitOrder(Order order) { ValidateOrder(order); Small CalculateTax(order); CalculateShipping(order); Methods } SendOrderToOrderSubmissionService(order); - After public void ValidateOrder(Order order) { if (order.Products.Count == 0) throw new InvalidOperationException("Select a product."); } public void CalculateTax(Order order) { order.Tax = order.Subtotal * 1.0675; } public void CalculateShipping(Order order) { if (order.Subtotal < 25) order.ShippingCharges = 5; else order.ShippingCharges = 10; } public void SendOrderToOrderSubmissionService(Order order) { _orderSubmissionService.SubmitOrder(order); }
  • 32.
  • 33. Software entities (classes, modules, methods) should be open for extension but closed for modification.
  • 34.
  • 35. public class GetUserService { public IList<UserSummary> FindUsers(UserSearchType type) { IList<User> users; switch (type) { case UserSearchType.AllUsers: // load the “users” variable here break; case UserSearchType.AllActiveUsers: // load the “users” variable here break; case UserSearchType.ActiveUsersThatCanEditQuotes: // load the “users” variable here break; } return ConvertToUserSummaries(users); } }
  • 36. public interface IUserQuery { IList<User> FilterUsers(IList<User> allUsers); } public class GetUserService { public IList<UserSummary> FindUsers(IUserQuery query) { IList<User> users = query.FilterUsers(GetAllUsers()); return ConvertToUserSummaries(users); } }
  • 37.  Anytime you change code, you have the potential to break it  Sometimes you can’t change libraries (e.g. code that isn’t yours)  May have to change code in many different places to add support for a certain type of situation
  • 38.  When the number of options in the if or switch statement is unlikely to change (e.g. switch on enum) public void UpdateFontStyle (Paragraph paragraph) { switch (IsBoldCheckBox.CheckState) { case CheckState.Checked: paragraph.IsBold = true; break; case CheckState.Unchecked: paragraph.IsBold = false; break; case CheckState.Indeterminate: break; } }
  • 39.  Use if/switch if the number of cases is unlikely to change  Use strategy pattern when the number of cases are likely to change  Always use common sense!
  • 40.  Don’t code for situations that you won’t ever need  Don’t create unneeded complexity  However, more class files != more complicated  Remember, this is supposed to make your lives easier!  You can always refactor later (if you write tests)
  • 41.
  • 42. Functions that use references to base classes must be able to use objects of derived classes without knowing it.
  • 43.
  • 44. public class Product { public string Name { get; set; } public string Author { get; set; } } public class Book : Product {} public class Movie : Product {} If someone had a Product object (which was actually a Movie) and asked for the Author, what should it do (a Movie doesn’t have an Author)?
  • 45. People using derived classes should not encounter unexpected results when using your derived class.
  • 46. public class MyList<T> : IList<T> { private readonly List<T> _innerList = new List<T>(); public void Add(T item) { if (_innerList.Contains(item)) return; _innerList.Add(item); } public int Count { get { return _innerList.Count; } } }
  • 47. Throw exceptions for cases that you can’t support (still not recommended) public class Rectangle : Shape { public double Width { get; set; } public double Height { get; set; } public override double Area { get { return Width * Height; } } } public class Cube : Shape { public override double Area { get { throw new NotSupportedException(); } } }
  • 48.
  • 49. Clients should not be forced to depend on interfaces that they do not use.
  • 50.
  • 51. ASP.NET MembershipProvider class – a very “fat” interface!
  • 52.  If you implement an interface or derive from a base class and you have to throw an exception in a method because you don’t support it, the interface is probably too big.
  • 53.  Single Responsibility Principle for interfaces/base classes  If your interface has members that are not used by some inheritors, those inheritors may be affected by changes in the interface, even though the methods that they use did not change.
  • 54. Why would you want to?  Use common sense
  • 55.
  • 56. 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.
  • 57.
  • 58.  Two classes are “tightly coupled” if they are linked together and are dependent on each other  Tightly coupled classes can not work independent of each other  Makes changing one class difficult because it could launch a wave of changes through tightly coupled classes
  • 59. UI Business Logic (Domain Model) Data Access Database
  • 60. UI Interfaces Business Logic (Domain Model) Interfaces Data Access Database
  • 61.  Each layer should not know anything about the details of how the other layers work.  Example: your domain model should not know how data access is done – it shouldn’t know if you’re using stored procedures, an ORM, etc.
  • 62.  Tight coupling is bad – if your business layer contains code related to data access, changes to how data access is done will affect business logic  Harder to test because you have to deal with implementation details of something you’re not trying to test
  • 63. How do you know that your code is working? How do you know that your code will continue to work after you change it?
  • 64. Unit tests:  Tests a small unit of functionality  Mock or “fake out” external dependencies (e.g. databases)  Run fast  Integration tests:  Test the whole system working together  Can run slow  Can be brittle
  • 65. Stubs, mocks, and fakes in unit tests are only possible when we have an interface to implement The main reason for the Dependency Inversion Principle is to help us write unit tests.
  • 66. public class ProductRepository : IProductRepository { public Product Get(int id) { ... } } public interface IProductRepository { Product Get(int id); }
  • 67. public class GetProductService : IGetProductService { private IProductRepository _productRepository; public GetProductService( IProductRepository productRepository) { _productRepository = productRepository; } public IList<Product> GetProductById(int id) { return _productRepository.Get(id); } }
  • 68. Use of “new” public class GetProductService { public IList<Product> GetProductById(int id) { var productRepository = new ProductRepository(); return productRepository.Get(id); } }
  • 69. Use of “static” public class SecurityService { public static User GetCurrentUser() { // do something } }
  • 70. Use of singletons using “static” public class ProductCache { private static readonly _instance = new ProductCache(); public static ProductCache Instance { get { return _instance; } } }
  • 71. public class GetProductService : IGetProductService { private IProductRepository _productRepository; public GetProductService( IProductRepository productRepository) { _productRepository = productRepository; } public IList<Product> GetProductById(int id) { return _productRepository.Get(id); } } Problem: How do we create these objects?
  • 72.  Creates objects that are ready for you to use  Knows how to create objects and their dependencies  Knows how to initialize objects when they are created (if necessary)
  • 73.  Popular .NET choices:  StructureMap, Ninject  Other .NET choices:  Unity, Castle Windsor, Autofac, Spring .NET  Java  Spring  Ruby  We don’t need no stinkin’ DI containers!
  • 74. ObjectFactory.Initialize(x => { x.For<IGetProductService>().Use<GetProductService>(); });
  • 75. ObjectFactory.Initialize(x => { x.Scan(scan => { scan.WithDefaultConventions(); scan.AssemblyContainingType<IProductRepository>(); }); });  Automatically map “ISomething” interface to “Something” class
  • 76. ObjectFactory.Initialize(x => { x.For<IProductRepository>() .Use<ProductRepository>() .OnCreation(repository => repository.ConnectionString = ConfigurationManager.AppSettings["MainDB"]); });  We just reduced duplication and complexity by setting this up here!
  • 77. ObjectFactory.Initialize(x => { x.ForSingletonOf<IProductCache>().Use<ProductCache>(); });  There will only ever be one IProductCache  We don’t violate DIP by having static variables
  • 78. ObjectFactory.Initialize(x => { x.For<ICurrentUser>() .Use(c => new CurrentUser(Thread.CurrentPrincipal)); }); Testing will be easier because we won’t reference Thread.CurrentPrincipal
  • 79. Don’t “new” up anything that is a dependency  Don’t new up classes that you want to create a fake for in a test  Do new up entity objects  Do new up value types (e.g. string, DateTime, etc.)  Do new up .NET Framework types (e.g. SqlConnection)  Entity objects should not have dependencies  If you have to have static variables, isolate them behind the DI container (e.g. example in previous slide)  Use ObjectFactory.GetInstance() to create objects when you can’t take them in as constructor parameters  Don’t use the DI container when writing unit tests
  • 80.
  • 82. Uncle Bob’s SOLID articles  http://bit.ly/solid1  Uncle Bob talking about SOLID on Hanselminutes  http://bit.ly/solid2  My slides  http://bit.ly/solid3  ALT.NET mailing list  http://bit.ly/solid4 My Info: email: jon@jonkruger.com twitter: @jonkruger / blog: http://jonkruger.com/blog TDD training: http://tddbootcamp.com

Editor's Notes

  1. Each of these Legos have a very specific purpose and a way to interact with each other. Using these simple blocks, you can create amazing Lego structures.
  2. -Imagine if some of our Lego blocks were missing the pins on the top, some were very weird shapes, some couldn’t attach anything to the bottom, some were glued together, etc. – if would be really hard to build different things with them or change what we were building
  3. DRY – if you write less code, you will write less bugs (and you have to do less work)Good software design and testing go hand in hand – testable code is usually well designed code (and vice versa)
  4. I will try to explain situations where (I think) you can not follow these principlesThe goal is to make software development easier. This DOES NOT mean that you shouldn’t follow these principles just because you don’t understand it or don’t know how to do it. Try to understand why you are doing things the way you are doing it. Do what makes sense to you – but make sure you do your homework and make sure you are doing the right thingDon’t just do something because someone says you should – learn why you should do it that way (they could be wrong)You should be able to explain why you made a decision – not “Microsoft told me to do it” or “someone says this is the right way to do it” or “this is how we’ve always done it in the past” Have seen projects that took these principles to extremes, or added unnecessary complexity without knowing why they were doing it, and the project suffered or failed because of it
  5. If you’re not willing to use a technology because you’re not willing to learn something new, that is a big problem not saying that you need to spend all of your time outside of work learning new stuff be open to change and new ideas
  6. - Imagine trying to use this thing! It can do everything you want, but doing what you want will be difficult.
  7. - What happens if the requirements change and now you can have a joint account that is held by two people?
  8. - Person still has methods and properties dealing with accounts, but now all of the account logic is correctly encapsulated in the Account class
  9. - small, useful Lego blocks instead of oddly-shaped ones
  10. Explain what a domain service is – not a web service
  11. - This is not added complexity – I’m not writing any more code than I did when it was all one class
  12. Big classes are harder to read, write, change, or testBig classes often mean tight coupling, so it’s difficult to change one part of the class without affecting the other parts of it
  13. - Common sense – go with your gut – don’t sit there for half an hour trying to figure out if a class violates SRP. If you can’t make a decision, just leave it how it is, you can come back and refactor later if you need to.
  14. - What is this method doing? You can figure it out, but you have to read it carefully and figure out what’s going on, even for this simple example.
  15. - What is this method doing? Even a non-programmer could tell you!
  16. - When you’re writing a one line method, it’s a lot easier because you can concentrate on what that one line is supposed to do… you don’t have to think about the overall flow and logic of what you’re trying to do overall
  17. - We are trying to do 2 things here – find subsets of users, and return user summaries
  18. Now the IUserQuery is responsible for filtering the users, and the FindUsers() method is only responsible for return user summaries for a list of users We can reuse the IUserQuery in other places, and now we don’t have to modify GetUserService.FindUsers() in order to create a new type of query.
  19. - Comments that say “if you want to add another X, you have to add code in these 5 places”
  20. - Probably need a 2DShape and 3DShape base class
  21. - Example – going to a friend’s house and they have the complicated home theater system and you want to watch TV
  22. - example: I want to test my validation code. I just want to test the validation logic, so why should I have to actually save something to the database to do this?
  23. Java: SpringRuby: we don’t need no stinkin’ DI containers!