SOLIDNot Just a State of Matter, It’s Principles for OO Propriety                      Chris Weldon
Me•   Fightin’ Texas Aggie•   .Net and PHP Developer•   UNIX and Windows Sysadmin•   Senior Consultant at Improving Enterp...
Agile, Microsoft, Open Technologies, UXApplied Training, Coaching, MentoringCertified ConsultingRural SourcingRecruiting Se...
What is OOD?
Abstraction  What is OOD?
Abstraction   Inheritance  What is OOD?
Abstraction     Inheritance   What is OOD?Encapsulation
Abstraction      Inheritance   What is OOD?Encapsulation   Polymorphism
What is SOLID?
?
Is it law?
They be more like  “guidelines”
An Order
public class Order{    private int _id;    private int _userId;    private Product[] _products;    public int getId() {   ...
public Product[] getProducts() {    return this._products;}public void addProduct(Product product) {    this._products.add...
private DBConnection _db;public Order(){    // Read from configuration to get connection string.    string connectionStrin...
public static Order CreateOrder(int userId, Product[] products)    {        Order order = new Order();        order.setUse...
public void deliverOrder(){    try {        WebServiceConnection networkConnection =            new WebServiceConnection("...
public void notifyCustomer()    {        try {            mailer = new Mailer();            mailer.setFrom(“orders@chriswe...
OMG
OMGWho vomited in my codebase?
“There should never be more than one reason           for a class to change”
Improve
public class Order{  // I’m just a model}                        Improve
public class OrderDao                          {public class Order          // I just talk to the database{               ...
public class OrderDao                                  {public class Order                  // I just talk to the database...
public class OrderDao                                  {public class Order                  // I just talk to the database...
public class OrderDao                                  {public class Order                  // I just talk to the database...
Next Sample
public void ActivateDrillBit(string customerOption) {    if (customerOption == "small") {        SmallBit drillBit = new S...
Requirements Change! Customer Needs to Specify Options
public void ActivateDrillBit(string customerOption, string freq,Options options) {    if (freq == "") freq = "240hz";    i...
You Broke  My  App!@#!@
public class DrillBitActivator {    public void ActivateDrillBit(string customerOption) {        // ...    }}public class ...
public function ActivateDrillBit(string customerOption)    IDrillBit drillBit = DrillBitFactory::CreateDrillBit(customerOp...
Next:A Familiar Example
public interface IManageCustomers {    void TakeSpecifications(Specs specs);    void ReviewSpecifications(Specs specs);   ...
public class GoodManager : IManageCustomers {    public void TakeSpecifications(Specs specs) {        this.ReviewSpecifica...
public class Tom : IManageCustomers {    public void TakeSpecifications(Specs specs) {        throw new DelegateToSecretar...
public interface ITakeSpecifications {    function TakeSpecifications(Specs specs);}public interface IReviewSpecifications...
public class GoodManager :    IManageCustomers, ITakeSpecifications, IReviewSpecifications, IGiveToEngineers{    public vo...
public class Tom : IManageCustomers {    public void DealWithTheGoshDarnCustomers() {        // Your gosh darn right I do!...
Hand Tom off to our consultants
Next Up
public interface IDataResource{    void Load();    void Save();}
public class AppSettings : IDataResource {    public void Load() {        // Load application settings.    }    public voi...
public class UserSettings : IDataResource {    public void Load() {        // Load user settings.    }    public void Save...
static IDataResource[] LoadAll() {    IDataResource[] resources = new IDataResource[2] {        new AppSettings(),        ...
Our “Duck”
public class UnsaveableSettings : AppSettings {    public override void Load() {        // Loads settings.    }    public ...
static IDataResource[] LoadAll() {    IDataResource[] resources = new IDataResource[3] {        new AppSettings(),        ...
static IDataResource[] LoadAll() {    IDataResource[] resources = new IDataResource[3] {        new AppSettings(),        ...
static IDataResource[] LoadAll() {    IDataResource[] resources = new IDataResource[3] {        new AppSettings(),        ...
teh fix!static void SaveAll(IDataResource[] resources) {    foreach (IDataResource resource in resources) {        if (reso...
teh fix!static void SaveAll(IDataResource[] resources) {    foreach (IDataResource resource in resources) {        if (reso...
teh fix!static void SaveAll(IDataResource[] resources) {    foreach (IDataResource resource in resources) {        if (reso...
The Real Fix
The Real Fix Interface Segregation +      Polymorphism
public interface IDataResource{    void Load();}public interface ISaveResource{    void Save();}
public class AppSettingsLoaderBase : IDataResource {    public virtual void Load() {        // Load application settings. ...
public class AppSettings extends AppSettingsLoaderBase    implements ISaveResource {    public function Save() {        //...
public class UnsaveableSettings extends AppSettingsLoaderBase {    public override void Load() {        // Loads settings....
static IDataResource[] LoadAll() {    IDataResource[] resources = new IDataResource[3] {        new AppSettings(),        ...
Final Problem
public class Authenticator {    private DataAccessLayer _repository;    public DataAccessLayer() {        this._repository...
Problems?
Problems?          Authenticator      authenticate() : bool        DataAccessLayerfindByUsernameAndPassword : array
Problems?                Authenticator            authenticate() : bool              DataAccessLayer      findByUsernameAnd...
Dependency Inversion•   “High-level modules should not depend upon low level modules. They    should depend upon abstracti...
Step 1Invert Dependency
class Authenticator {    private DataAccessLayer _repository;    public Authenticator(DataAccessLayer repository) {       ...
Coupling = Bad
Step 2Depend on Abstractions
public interface IUserRepository {    User findByUsernameAndPassword(string username, string password);}public class DataA...
class Authenticator {    private IUserRepository _repository;    public Authenticator(IUserRepository repository) {       ...
Comparison
Comparison          Authenticator      authenticate() : bool        DataAccessLayerfindByUsernameAndPassword : array
Comparison          Authenticator      authenticate() : bool        DataAccessLayerfindByUsernameAndPassword : array
Comparison                                                 Authenticator                                             authe...
Benefit: Flexibilitypublic class WebServiceUserRepository : IUserRepository {    public User findByUsernameAndPassword(stri...
Recap
S = SRP - Single Responsibility Principle
S = SRP - Single Responsibility Principle  O = OCP - Open/Closed Principle
S = SRP - Single Responsibility Principle  O = OCP - Open/Closed PrincipleL = LSP - Liskov Substitution Principle
S = SRP - Single Responsibility Principle  O = OCP - Open/Closed PrincipleL = LSP - Liskov Substitution PrincipleI = ISP -...
S = SRP - Single Responsibility Principle   O = OCP - Open/Closed Principle  L = LSP - Liskov Substitution Principle I = I...
Questions?
Thank You!Check improvingaggies.com   http://spkr8.com/neraath
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 Propriety
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 Propriety
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 Propriety
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 Propriety
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 Propriety
Upcoming SlideShare
Loading in …5
×

SOLID - Not Just a State of Matter, It's Principles for OO Propriety

1,341 views

Published on

0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,341
On SlideShare
0
From Embeds
0
Number of Embeds
94
Actions
Shares
0
Downloads
44
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • SOLID - Not Just a State of Matter, It's Principles for OO Propriety

    1. 1. SOLIDNot Just a State of Matter, It’s Principles for OO Propriety Chris Weldon
    2. 2. Me• Fightin’ Texas Aggie• .Net and PHP Developer• UNIX and Windows Sysadmin• Senior Consultant at Improving Enterprises• Contact Me: chris@chrisweldon.net
    3. 3. Agile, Microsoft, Open Technologies, UXApplied Training, Coaching, MentoringCertified ConsultingRural SourcingRecruiting Services
    4. 4. What is OOD?
    5. 5. Abstraction What is OOD?
    6. 6. Abstraction Inheritance What is OOD?
    7. 7. Abstraction Inheritance What is OOD?Encapsulation
    8. 8. Abstraction Inheritance What is OOD?Encapsulation Polymorphism
    9. 9. What is SOLID?
    10. 10. ?
    11. 11. Is it law?
    12. 12. They be more like “guidelines”
    13. 13. An Order
    14. 14. public class Order{ private int _id; private int _userId; private Product[] _products; public int getId() { return this._id; } public void setId(int id) { this._id = id; } public int getUserId() { return this._userId; } public void setUserId(int userId) { this._userId = userId; }
    15. 15. public Product[] getProducts() { return this._products;}public void addProduct(Product product) { this._products.add(product);}public void setProducts(Product[] products) { this._products = products;}
    16. 16. private DBConnection _db;public Order(){ // Read from configuration to get connection string. string connectionString = string.Empty; Handle fileHandle = fopen("/etc/database/app.config", "r"); while (string row = readLine(fileHandle)) { if (row.StartsWith("dbo")) { connectionString = row; } } fclose(fileHandle); this._db = new DBConnection(connectionString);}
    17. 17. public static Order CreateOrder(int userId, Product[] products) { Order order = new Order(); order.setUserId(userId); order.setProducts(products); return order; } public static Order getOrderById(int orderId) { if (orderId == null || orderId < 0) { DBCommand command = this._db.exec("SELECT * FROM orders"); Order[] results = this._db.getResults(command); // Get the first result. return results[0]; } DBCommand command = this._db.exec("SELECT * FROM orders WHERE id= ?", orderId); Order order = this._db.getSingle($command); return order; }
    18. 18. public void deliverOrder(){ try { WebServiceConnection networkConnection = new WebServiceConnection("http://shpt1/shipctrl.svc"); networkConnection->open(); ShippingManager shippingManager = new ShippingManager(networkConnection); shippingManager.setOrder(this); shippingManager.setDeliveryType(DeliveryType.EXPRESS); shippingManager.shipViaWebService(); this.notifyCustomer(); } catch (Exception e) { Handle logFile = fopen("/tmp/logfile.log", "a"); fwrite("An error occurred while delivering the order.", logFile); fclose(logFile); }}
    19. 19. public void notifyCustomer() { try { mailer = new Mailer(); mailer.setFrom(“orders@chrisweldon.net”, “Grumpy Baby Orders”); mailer.setSubject(“Order #” + this.getId() + “ out forDelivery”); mailer.setBodyText(“Your order is being shipped!”); mailer.send(); } catch (Exception $e) { Handle logFile = fopen("/tmp/logfile.log", "a"); fwrite("An error occurred while emailing the notice.", logFile); fclose(logFile); } }}
    20. 20. OMG
    21. 21. OMGWho vomited in my codebase?
    22. 22. “There should never be more than one reason for a class to change”
    23. 23. Improve
    24. 24. public class Order{ // I’m just a model} Improve
    25. 25. public class OrderDao {public class Order // I just talk to the database{ public OrderDao(); // I’m just a model public static Order CreateOrder(int userId,} Product[] products); public static Order getOrderById(int orderId); } Improve
    26. 26. public class OrderDao {public class Order // I just talk to the database{ public OrderDao(); // I’m just a model public static Order CreateOrder(int userId,} Product[] products); public static Order getOrderById(int orderId); } Improvepublic class OrderDeliverer{ // I just deliver orders public void deliverOrder();}
    27. 27. public class OrderDao {public class Order // I just talk to the database{ public OrderDao(); // I’m just a model public static Order CreateOrder(int userId,} Product[] products); public static Order getOrderById(int orderId); } Improvepublic class OrderDeliverer public class CustomerNotifier{ { // I just deliver orders // I just deliver orders public void deliverOrder(); public void notifyCustomer();} }
    28. 28. public class OrderDao {public class Order // I just talk to the database{ public OrderDao(); // I’m just a model public static Order CreateOrder(int userId,} Product[] products); public static Order getOrderById(int orderId); } Improve it’s what we dopublic class OrderDeliverer public class CustomerNotifier{ { // I just deliver orders // I just deliver orders public void deliverOrder(); public void notifyCustomer();} }
    29. 29. Next Sample
    30. 30. public void ActivateDrillBit(string customerOption) { if (customerOption == "small") { SmallBit drillBit = new SmallBit(); drillBit.activate(); } else if (customerOption == "medium") { MediumBit drillBit = new MediumBit(); drillBit.activate("120hz"); } else if (customerOption == "large") { LargeBit drillBit = new LargeBit(); drillBit.activate("240hz", Options.Water); }}
    31. 31. Requirements Change! Customer Needs to Specify Options
    32. 32. public void ActivateDrillBit(string customerOption, string freq,Options options) { if (freq == "") freq = "240hz"; if (options == null) options = Options.NoWater; if (customerOption == "small") { SmallBit drillBit = new SmallBit(); drillBit.activate(freq, options); } else if (customerOption == "medium") { MediumBit drillBit = new MediumBit(); drillBit.activate(freq, options); } else if (customerOption == "large") { LargeBit drillBit = new LargeBit(); drillBit.activate(freq, options); }}
    33. 33. You Broke My App!@#!@
    34. 34. public class DrillBitActivator { public void ActivateDrillBit(string customerOption) { // ... }}public class DrillBitConfigurableActivator : DrillBitActivator { public DrillBitConfigurableActivator(string freqency, Options options) { // Configurable! } public override function ActivateDrillBit(string customerOption) { // ... }}
    35. 35. public function ActivateDrillBit(string customerOption) IDrillBit drillBit = DrillBitFactory::CreateDrillBit(customerOption); drillBit.activate(this._freq, this._options);}
    36. 36. Next:A Familiar Example
    37. 37. public interface IManageCustomers { void TakeSpecifications(Specs specs); void ReviewSpecifications(Specs specs); void GiveToEngineers(Specs specs); void DealWithTheGoshDarnCustomers(); bool IsPeoplePerson();}
    38. 38. public class GoodManager : IManageCustomers { public void TakeSpecifications(Specs specs) { this.ReviewSpecifications(specs); } public void ReviewSpecifications(Specs specs) { // If specs seem good. this.GiveToEngineers(specs); } public void GiveToEngineers(Specs specs) { // E-mails specs to engineers. } public void DealWithTheGoshDarnCustomers() { // You better believe he does. } public bool IsPeoplePerson() { return true; // Absolutely! }}
    39. 39. public class Tom : IManageCustomers { public void TakeSpecifications(Specs specs) { throw new DelegateToSecretary(); } public void ReviewSpecifications(Specs specs) { throw new DelegateToSecretary(); } public void GiveToEngineers(Specs specs) { throw new DelegateToSecretary(); } public void DealWithTheGoshDarnCustomers() { // Your gosh darn right I do! } public bool IsPeoplePerson() { return true; // I AM a people person, dammit! }}
    40. 40. public interface ITakeSpecifications { function TakeSpecifications(Specs specs);}public interface IReviewSpecifications { function ReviewSpecifications(Specs specs);}public interface IGiveToEngineers { function GiveToEngineers(Specs specs);}public interface IManageCustomers { function DealWithTheGoshDarnCustomers(); function IsPeoplePerson();}
    41. 41. public class GoodManager : IManageCustomers, ITakeSpecifications, IReviewSpecifications, IGiveToEngineers{ public void TakeSpecifications(Specs specs) { this.ReviewSpecifications(specs); } public void ReviewSpecifications(Specs specs) { // If specs seem good. this.GiveToEngineers(specs); } public void GiveToEngineers(Specs $specs) { // E-mails specs to engineers. } public void DealWithTheGoshDarnCustomers() { // You better believe he does. } public bool IsPeoplePerson() { return true; // Absolutely! }}
    42. 42. public class Tom : IManageCustomers { public void DealWithTheGoshDarnCustomers() { // Your gosh darn right I do! } public bool IsPeoplePerson() { return true; // I AM a people person, dammit! }}
    43. 43. Hand Tom off to our consultants
    44. 44. Next Up
    45. 45. public interface IDataResource{ void Load(); void Save();}
    46. 46. public class AppSettings : IDataResource { public void Load() { // Load application settings. } public void Save() { // Save application settings. }}
    47. 47. public class UserSettings : IDataResource { public void Load() { // Load user settings. } public void Save() { // Save user settings. }}
    48. 48. static IDataResource[] LoadAll() { IDataResource[] resources = new IDataResource[2] { new AppSettings(), new UserSettings() }; foreach (IDataResource resource in resources) { resource.Load(); } return resources;}static void SaveAll(IDataResource[] resources) { foreach (IDataResource resource in resources) { resource.Save(); }}
    49. 49. Our “Duck”
    50. 50. public class UnsaveableSettings : AppSettings { public override void Load() { // Loads settings. } public override void Save() { throw new CannotSaveException(); }}
    51. 51. static IDataResource[] LoadAll() { IDataResource[] resources = new IDataResource[3] { new AppSettings(), new UserSettings(), new UnsaveableSettings() }; foreach (IDataResource resource in resources) { resource.Load(); } return resources;}static void SaveAll(IDataResource[] resources) { foreach (IDataResource resource in resources) { resource.Save(); }}
    52. 52. static IDataResource[] LoadAll() { IDataResource[] resources = new IDataResource[3] { new AppSettings(), new UserSettings(), new UnsaveableSettings() }; foreach (IDataResource resource in resources) { resource.Load(); } return resources;}static void SaveAll(IDataResource[] resources) { foreach (IDataResource resource in resources) { resource.Save(); }}
    53. 53. static IDataResource[] LoadAll() { IDataResource[] resources = new IDataResource[3] { new AppSettings(), new UserSettings(), new UnsaveableSettings() }; foreach (IDataResource resource in resources) { resource.Load(); } return resources;}static void SaveAll(IDataResource[] resources) { foreach (IDataResource resource in resources) { resource.Save(); }} What happens with UnsaveableSettings?
    54. 54. teh fix!static void SaveAll(IDataResource[] resources) { foreach (IDataResource resource in resources) { if (resource is UnsaveableSettings) continue; resource.Save(); }}
    55. 55. teh fix!static void SaveAll(IDataResource[] resources) { foreach (IDataResource resource in resources) { if (resource is UnsaveableSettings) continue; resource.Save(); }}
    56. 56. teh fix!static void SaveAll(IDataResource[] resources) { foreach (IDataResource resource in resources) { if (resource is UnsaveableSettings) continue; resource.Save(); }} omg shoot me good job reducing abstraction
    57. 57. The Real Fix
    58. 58. The Real Fix Interface Segregation + Polymorphism
    59. 59. public interface IDataResource{ void Load();}public interface ISaveResource{ void Save();}
    60. 60. public class AppSettingsLoaderBase : IDataResource { public virtual void Load() { // Load application settings. }}
    61. 61. public class AppSettings extends AppSettingsLoaderBase implements ISaveResource { public function Save() { // Save application settings. }}
    62. 62. public class UnsaveableSettings extends AppSettingsLoaderBase { public override void Load() { // Loads settings. }}
    63. 63. static IDataResource[] LoadAll() { IDataResource[] resources = new IDataResource[3] { new AppSettings(), new UserSettings(), new UnsaveableSettings() }; foreach (IDataResource resource in resources) { resource.Load(); } return resources;}static void SaveAll(ISaveResource[] resources) { foreach (ISaveResource resource in resources) { resource.Save(); }}
    64. 64. Final Problem
    65. 65. public class Authenticator { private DataAccessLayer _repository; public DataAccessLayer() { this._repository = new DataAccessLayer(); } public bool authenticate(string username, string password) { string hashedPassword = md5(password); User user = this._repository.findByUsernameAndPassword( username, hashedPassword); return user == null; }}
    66. 66. Problems?
    67. 67. Problems? Authenticator authenticate() : bool DataAccessLayerfindByUsernameAndPassword : array
    68. 68. Problems? Authenticator authenticate() : bool DataAccessLayer findByUsernameAndPassword : arrayStrongly coupled to DataAccessLayer
    69. 69. Dependency Inversion• “High-level modules should not depend upon low level modules. They should depend upon abstractions.• “Abstractions should not depend upon details. Details should depend upon abstractions.” Robert Martin
    70. 70. Step 1Invert Dependency
    71. 71. class Authenticator { private DataAccessLayer _repository; public Authenticator(DataAccessLayer repository) { this._repository = repository; } public bool authenticate(string username, string password) { string hashedPassword = md5(password); User user = this._repository.findByUsernameAndPassword( username, hashedPassword); return user == null; }}
    72. 72. Coupling = Bad
    73. 73. Step 2Depend on Abstractions
    74. 74. public interface IUserRepository { User findByUsernameAndPassword(string username, string password);}public class DataAccessLayer : IUserRepository { public User findByUsernameAndPassword(string username, string password) { // Do some database stuff. }}
    75. 75. class Authenticator { private IUserRepository _repository; public Authenticator(IUserRepository repository) { this._repository = repository; } public bool authenticate(string username, string password) { string hashedPassword = md5(password); User user = this._repository.findByUsernameAndPassword( username, hashedPassword); return user == null; }}
    76. 76. Comparison
    77. 77. Comparison Authenticator authenticate() : bool DataAccessLayerfindByUsernameAndPassword : array
    78. 78. Comparison Authenticator authenticate() : bool DataAccessLayerfindByUsernameAndPassword : array
    79. 79. Comparison Authenticator authenticate() : bool Authenticator authenticate() : bool IUserRepository findByUsernameAndPassword : array DataAccessLayerfindByUsernameAndPassword : array DataAccessLayer findByUsernameAndPassword : array
    80. 80. Benefit: Flexibilitypublic class WebServiceUserRepository : IUserRepository { public User findByUsernameAndPassword(string username, string password) { // Fetch our user through JSON or SOAP }}public class OAuthRepository : IUserRepository { public User findByUsernameAndPassword(string username, string password) { // Connect to your favorite OAuth provider }}
    81. 81. Recap
    82. 82. S = SRP - Single Responsibility Principle
    83. 83. S = SRP - Single Responsibility Principle O = OCP - Open/Closed Principle
    84. 84. S = SRP - Single Responsibility Principle O = OCP - Open/Closed PrincipleL = LSP - Liskov Substitution Principle
    85. 85. S = SRP - Single Responsibility Principle O = OCP - Open/Closed PrincipleL = LSP - Liskov Substitution PrincipleI = ISP - Interface Segregation Principle
    86. 86. S = SRP - Single Responsibility Principle O = OCP - Open/Closed Principle L = LSP - Liskov Substitution Principle I = ISP - Interface Segregation PrincipleD = DIP - Dependency Inversion Principle
    87. 87. Questions?
    88. 88. Thank You!Check improvingaggies.com http://spkr8.com/neraath

    ×