SlideShare a Scribd company logo
So S.O.L.I.D Fu
Designing Better Code
Abstract
A chat about some of the most important
principles in software development. Discover
or get a refresher on these tried and tested
techniques for designing better code.
SaaS eCommerce Platform
So S.O.L.I.D Fu - Designing Better Code
What’s SOLID?
5 Principles
● Single Responsibility Principle
● Open / Closed Principle
● Liskov Substitution Principle
● Interface Segregation Principle
● Dependency Inversion Principle
SRP
OCP
LSPISP
DIP
S.O.L.I.D
Why S.O.L.I.D?
● Maintainable
● Understandable
● Extendable
● Testable
● Debuggable
● Reusable
● Robust, less fragile
BETTER
SOFTWARE
SRP
OCP
LSPISP
DIP
class Product
{
public function getId()
public function getName()
public function getPrice()
public function getStock()
public function setStock($stock)
public function getDescription()
}
https://github.com/neilcrookes/SoSOLIDFu
class CreditCard
{
public function getExpiryYear()
public function getExpiryMonth()
public function getLast4()
public function getToken()
}
https://github.com/neilcrookes/SoSOLIDFu
class Gateway
{
public function purchase(Shop $shop, CreditCard $card)
}
https://github.com/neilcrookes/SoSOLIDFu
class Shop
{
public function addToBasket(Product $product)
public function removeFromBasket(Product $product)
public function getTotal()
public function getBasket()
public function checkout(CreditCard $card)
protected function sendOrderConfirmationEmail(CreditCard $card)
}
https://github.com/neilcrookes/SoSOLIDFu
Single
Responsibility
States that
● Classes should have only one reason to change
● Therefore should have only one responsibility
class Shop
{
public function addToBasket(Product $product)
public function removeFromBasket(Product $product)
public function getTotal()
public function getBasket()
public function checkout(CreditCard $card)
protected function sendOrderConfirmationEmail(CreditCard $card)
}
https://github.com/neilcrookes/SoSOLIDFu
class Shop
{
public function addToBasket(Product $product)
public function removeFromBasket(Product $product)
public function getTotal()
public function getBasket()
public function checkout(CreditCard $card)
protected function sendOrderConfirmationEmail(CreditCard $card)
}
https://github.com/neilcrookes/SoSOLIDFu
class Basket
{
public function addToBasket(Product $product)
public function removeFromBasket(Product $product)
public function getTotal()
public function getBasket()
}
Class Checkout
{
public function checkout(CreditCard $card)
protected function sendOrderConfirmationEmail(CreditCard $card)
}
https://github.com/neilcrookes/SoSOLIDFu
Class Checkout
{
public function checkout(Basket $basket, CreditCard $card)
{
try
{
$reference = $this->gateway->purchase($basket, $card);
$this->sendOrderConfirmationEmail($basket, $card);
return true;
}
catch (GatewayException $e)
{
return false;
}
}
}
https://github.com/neilcrookes/SoSOLIDFu
Open / Closed
Objects or libraries should be open for extension, but closed for modification.
● Easy to add new features OR change behaviour
● Without modifying original
● Purists: without extending original…!?
Eh?
Open / Closed cont
Extension points
● Events
● Plugin architecture
● Composition
● Strategy pattern
● Callbacks
Open / Closed cont
Closed for modification - Clarity of intent
● Final classes
● Private members
● Encourage extension in expected / supported way
● Encourages decoupling
● Reduces risk of breaking changes
final class Checkout
{
public function checkout(Basket $basket, CreditCard $card)
{
try
{
$reference = $this->gateway->purchase($basket, $card);
$this->sendOrderConfirmationEmail($basket, $card);
fire(new CheckoutEvent($basket));
return true;
}
catch (GatewayException $e)
{
return false;
}
}
}
https://github.com/neilcrookes/SoSOLIDFu
final class Checkout
{
public function sendOrderConfirmationEmail(Basket $basket, CreditCard $card)
{
$message = "Thank you for your order.n";
foreach ($basket as $item)
{
/** @var Product $product */
$product = $item['product'];
$message .= "n" . $product->getName() . ' x ' . $item['quantity']
. ' @ £' . $product->getPrice();
}
$message .= "nnPayment has been taken from: xxxx xxxx xxxx " . $card->getLast4()
. ' Ex: ' . $card->getExpiryMonth() . '/' . $card->getExpiryYear();
mail('customer@domain.com', 'Your order at my store', $message);
}
}
https://github.com/neilcrookes/SoSOLIDFu
Liskov Substitution
States that you should be able to swap dependencies for a subclass class without
causing unexpected results
final class Checkout
{
public function sendOrderConfirmationEmail(Basket $basket, CreditCard $card)
{
$message = "Thank you for your order.n";
foreach ($basket as $item)
{
/** @var Product $product */
$product = $item['product'];
$message .= "n" . $product->getBasketTitle() . ' x ' . $item['quantity']
. ' @ £' . $product->getPrice();
}
$message .= "nnPayment has been taken from: xxxx xxxx xxxx " . $card->getLast4()
. ' Ex: ' . $card->getExpiryMonth() . '/' . $card->getExpiryYear();
mail('customer@domain.com', 'Your order at my store', $message);
}
}
https://github.com/neilcrookes/SoSOLIDFu
interface PurchasableInterface
{
public function getId();
public function getPrice();
public function getStock();
public function setStock($stock);
public function getBasketTitle();
}
https://github.com/neilcrookes/SoSOLIDFu
Interface
Segregation
● An interface should only impose the methods that a client relies on
● Split unrelated interface methods into separate interfaces
interface PurchasableInterface
{
public function getId();
public function getPrice();
public function getBasketTitle();
}
interface StockableInterface
{
public function getStock();
public function setStock($stock);
}
https://github.com/neilcrookes/SoSOLIDFu
final class Checkout
{
public function checkout(Basket $basket, CreditCard $card)
}
class Gateway
{
public function purchase(Basket $basket, CreditCard $card)
}
https://github.com/neilcrookes/SoSOLIDFu
Dependency
Inversion
● High level should not depend on low level modules, both should depend on
abstractions
● Abstractions should not depend upon details. Details should depend upon
abstractions.
● Depend on abstractions (abstracts / interfaces), not concretes
● Code to an Interface
interface ChargeableInterface
{
public function getChargeableAmount();
}
interface GatewayInterface
{
public function charge(ChargeableInterface $chargeable,
PaymentMethodInterface $paymentMethod);
}
interface PaymentMethodInterface
{
public function getToken();
public function getDetails();
}
https://github.com/neilcrookes/SoSOLIDFu
final class Checkout
{
public function checkout(ChargeableInterface $basket, PaymentMethodInterface $card)
}
class Gateway
{
public function purchase(ChargeableInterface $basket, PaymentMethodInterface $card)
}
https://github.com/neilcrookes/SoSOLIDFu
Conclusion:
Get Classy
● Actually only add some Interfaces, and an Event
● Our code is designed much better
● Easy to understand, extend
● More robust, less likely to introduce bugs
● Lots of classes is fine
● Lots of interfaces is fine
Questions
● Now?
● At the pub?
● @neilcrookes

More Related Content

PDF
Dependency Injection
PDF
Dependency Injection Smells
PDF
Dealing with Legacy PHP Applications
PDF
PHPSpec - the only Design Tool you need - 4Developers
PDF
Refactoring using Codeception
PDF
Forget about index.php and build you applications around HTTP!
PDF
TDC2016SP - Trilha Developing for Business
PDF
Developing for Business
Dependency Injection
Dependency Injection Smells
Dealing with Legacy PHP Applications
PHPSpec - the only Design Tool you need - 4Developers
Refactoring using Codeception
Forget about index.php and build you applications around HTTP!
TDC2016SP - Trilha Developing for Business
Developing for Business

What's hot (20)

PDF
PhpSpec 2.0 ilustrated by examples
PDF
The IoC Hydra
PDF
The IoC Hydra - Dutch PHP Conference 2016
PDF
PHPunit and you
PPTX
Let's write secure Drupal code! - 13.09.2018 @ Drupal Europe, Darmstadt, Germany
PDF
SOLID PRINCIPLES
PDF
PHPUnit Episode iv.iii: Return of the tests
PDF
Building a Portfolio With Custom Post Types
ODP
Rich domain model with symfony 2.5 and doctrine 2.5
PDF
November Camp - Spec BDD with PHPSpec 2
PDF
Forget about Index.php and build you applications around HTTP - PHPers Cracow
PPTX
Hacking Your Way To Better Security - Dutch PHP Conference 2016
PPTX
Crafting beautiful software
PDF
Your code sucks, let's fix it
KEY
Solid principles
PDF
CGI::Prototype (NPW 2006)
PDF
Your code sucks, let's fix it! - php|tek13
PPT
Система рендеринга в Magento
PPTX
Let's write secure Drupal code!
PDF
Domain Driven Design
PhpSpec 2.0 ilustrated by examples
The IoC Hydra
The IoC Hydra - Dutch PHP Conference 2016
PHPunit and you
Let's write secure Drupal code! - 13.09.2018 @ Drupal Europe, Darmstadt, Germany
SOLID PRINCIPLES
PHPUnit Episode iv.iii: Return of the tests
Building a Portfolio With Custom Post Types
Rich domain model with symfony 2.5 and doctrine 2.5
November Camp - Spec BDD with PHPSpec 2
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Crafting beautiful software
Your code sucks, let's fix it
Solid principles
CGI::Prototype (NPW 2006)
Your code sucks, let's fix it! - php|tek13
Система рендеринга в Magento
Let's write secure Drupal code!
Domain Driven Design
Ad

Similar to So S.O.L.I.D Fu - Designing Better Code (20)

PDF
Hexagonal architecture
PDF
DDD on example of Symfony (Webcamp Odessa 2014)
PDF
Dependency injection in Drupal 8
PDF
PHP: 4 Design Patterns to Make Better Code
PDF
From framework coupled code to #microservices through #DDD /by @codelytv
ODP
CDI @javaonehyderabad
PDF
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
PDF
Domain-driven Design in PHP and Symfony - Drupal Camp Wroclaw!
PPTX
Practical AngularJS
PDF
Dependency Injection
PDF
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
PPTX
Drupal 8 migrate!
KEY
PDF
Living With Legacy Code
PDF
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
PDF
WebCamp: Developer Day: DDD in PHP on example of Symfony - Олег Зинченко
PPTX
Php on the desktop and php gtk2
PDF
SproutCore and the Future of Web Apps
PDF
DDD on example of Symfony (SfCampUA14)
Hexagonal architecture
DDD on example of Symfony (Webcamp Odessa 2014)
Dependency injection in Drupal 8
PHP: 4 Design Patterns to Make Better Code
From framework coupled code to #microservices through #DDD /by @codelytv
CDI @javaonehyderabad
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
Domain-driven Design in PHP and Symfony - Drupal Camp Wroclaw!
Practical AngularJS
Dependency Injection
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Drupal 8 migrate!
Living With Legacy Code
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
WebCamp: Developer Day: DDD in PHP on example of Symfony - Олег Зинченко
Php on the desktop and php gtk2
SproutCore and the Future of Web Apps
DDD on example of Symfony (SfCampUA14)
Ad

Recently uploaded (20)

PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
medical staffing services at VALiNTRY
PDF
PTS Company Brochure 2025 (1).pdf.......
PDF
Understanding Forklifts - TECH EHS Solution
PDF
Design an Analysis of Algorithms I-SECS-1021-03
PPTX
L1 - Introduction to python Backend.pptx
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PDF
How Creative Agencies Leverage Project Management Software.pdf
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PPTX
Transform Your Business with a Software ERP System
PPTX
Operating system designcfffgfgggggggvggggggggg
PDF
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PPTX
Odoo POS Development Services by CandidRoot Solutions
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
medical staffing services at VALiNTRY
PTS Company Brochure 2025 (1).pdf.......
Understanding Forklifts - TECH EHS Solution
Design an Analysis of Algorithms I-SECS-1021-03
L1 - Introduction to python Backend.pptx
How to Migrate SBCGlobal Email to Yahoo Easily
How Creative Agencies Leverage Project Management Software.pdf
Odoo Companies in India – Driving Business Transformation.pdf
Upgrade and Innovation Strategies for SAP ERP Customers
Transform Your Business with a Software ERP System
Operating system designcfffgfgggggggvggggggggg
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
Design an Analysis of Algorithms II-SECS-1021-03
Navsoft: AI-Powered Business Solutions & Custom Software Development
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
Wondershare Filmora 15 Crack With Activation Key [2025
Odoo POS Development Services by CandidRoot Solutions
2025 Textile ERP Trends: SAP, Odoo & Oracle

So S.O.L.I.D Fu - Designing Better Code

  • 2. Abstract A chat about some of the most important principles in software development. Discover or get a refresher on these tried and tested techniques for designing better code.
  • 5. What’s SOLID? 5 Principles ● Single Responsibility Principle ● Open / Closed Principle ● Liskov Substitution Principle ● Interface Segregation Principle ● Dependency Inversion Principle SRP OCP LSPISP DIP S.O.L.I.D
  • 6. Why S.O.L.I.D? ● Maintainable ● Understandable ● Extendable ● Testable ● Debuggable ● Reusable ● Robust, less fragile BETTER SOFTWARE SRP OCP LSPISP DIP
  • 7. class Product { public function getId() public function getName() public function getPrice() public function getStock() public function setStock($stock) public function getDescription() } https://github.com/neilcrookes/SoSOLIDFu
  • 8. class CreditCard { public function getExpiryYear() public function getExpiryMonth() public function getLast4() public function getToken() } https://github.com/neilcrookes/SoSOLIDFu
  • 9. class Gateway { public function purchase(Shop $shop, CreditCard $card) } https://github.com/neilcrookes/SoSOLIDFu
  • 10. class Shop { public function addToBasket(Product $product) public function removeFromBasket(Product $product) public function getTotal() public function getBasket() public function checkout(CreditCard $card) protected function sendOrderConfirmationEmail(CreditCard $card) } https://github.com/neilcrookes/SoSOLIDFu
  • 11. Single Responsibility States that ● Classes should have only one reason to change ● Therefore should have only one responsibility
  • 12. class Shop { public function addToBasket(Product $product) public function removeFromBasket(Product $product) public function getTotal() public function getBasket() public function checkout(CreditCard $card) protected function sendOrderConfirmationEmail(CreditCard $card) } https://github.com/neilcrookes/SoSOLIDFu
  • 13. class Shop { public function addToBasket(Product $product) public function removeFromBasket(Product $product) public function getTotal() public function getBasket() public function checkout(CreditCard $card) protected function sendOrderConfirmationEmail(CreditCard $card) } https://github.com/neilcrookes/SoSOLIDFu
  • 14. class Basket { public function addToBasket(Product $product) public function removeFromBasket(Product $product) public function getTotal() public function getBasket() } Class Checkout { public function checkout(CreditCard $card) protected function sendOrderConfirmationEmail(CreditCard $card) } https://github.com/neilcrookes/SoSOLIDFu
  • 15. Class Checkout { public function checkout(Basket $basket, CreditCard $card) { try { $reference = $this->gateway->purchase($basket, $card); $this->sendOrderConfirmationEmail($basket, $card); return true; } catch (GatewayException $e) { return false; } } } https://github.com/neilcrookes/SoSOLIDFu
  • 16. Open / Closed Objects or libraries should be open for extension, but closed for modification. ● Easy to add new features OR change behaviour ● Without modifying original ● Purists: without extending original…!? Eh?
  • 17. Open / Closed cont Extension points ● Events ● Plugin architecture ● Composition ● Strategy pattern ● Callbacks
  • 18. Open / Closed cont Closed for modification - Clarity of intent ● Final classes ● Private members ● Encourage extension in expected / supported way ● Encourages decoupling ● Reduces risk of breaking changes
  • 19. final class Checkout { public function checkout(Basket $basket, CreditCard $card) { try { $reference = $this->gateway->purchase($basket, $card); $this->sendOrderConfirmationEmail($basket, $card); fire(new CheckoutEvent($basket)); return true; } catch (GatewayException $e) { return false; } } } https://github.com/neilcrookes/SoSOLIDFu
  • 20. final class Checkout { public function sendOrderConfirmationEmail(Basket $basket, CreditCard $card) { $message = "Thank you for your order.n"; foreach ($basket as $item) { /** @var Product $product */ $product = $item['product']; $message .= "n" . $product->getName() . ' x ' . $item['quantity'] . ' @ £' . $product->getPrice(); } $message .= "nnPayment has been taken from: xxxx xxxx xxxx " . $card->getLast4() . ' Ex: ' . $card->getExpiryMonth() . '/' . $card->getExpiryYear(); mail('customer@domain.com', 'Your order at my store', $message); } } https://github.com/neilcrookes/SoSOLIDFu
  • 21. Liskov Substitution States that you should be able to swap dependencies for a subclass class without causing unexpected results
  • 22. final class Checkout { public function sendOrderConfirmationEmail(Basket $basket, CreditCard $card) { $message = "Thank you for your order.n"; foreach ($basket as $item) { /** @var Product $product */ $product = $item['product']; $message .= "n" . $product->getBasketTitle() . ' x ' . $item['quantity'] . ' @ £' . $product->getPrice(); } $message .= "nnPayment has been taken from: xxxx xxxx xxxx " . $card->getLast4() . ' Ex: ' . $card->getExpiryMonth() . '/' . $card->getExpiryYear(); mail('customer@domain.com', 'Your order at my store', $message); } } https://github.com/neilcrookes/SoSOLIDFu
  • 23. interface PurchasableInterface { public function getId(); public function getPrice(); public function getStock(); public function setStock($stock); public function getBasketTitle(); } https://github.com/neilcrookes/SoSOLIDFu
  • 24. Interface Segregation ● An interface should only impose the methods that a client relies on ● Split unrelated interface methods into separate interfaces
  • 25. interface PurchasableInterface { public function getId(); public function getPrice(); public function getBasketTitle(); } interface StockableInterface { public function getStock(); public function setStock($stock); } https://github.com/neilcrookes/SoSOLIDFu
  • 26. final class Checkout { public function checkout(Basket $basket, CreditCard $card) } class Gateway { public function purchase(Basket $basket, CreditCard $card) } https://github.com/neilcrookes/SoSOLIDFu
  • 27. Dependency Inversion ● High level should not depend on low level modules, both should depend on abstractions ● Abstractions should not depend upon details. Details should depend upon abstractions. ● Depend on abstractions (abstracts / interfaces), not concretes ● Code to an Interface
  • 28. interface ChargeableInterface { public function getChargeableAmount(); } interface GatewayInterface { public function charge(ChargeableInterface $chargeable, PaymentMethodInterface $paymentMethod); } interface PaymentMethodInterface { public function getToken(); public function getDetails(); } https://github.com/neilcrookes/SoSOLIDFu
  • 29. final class Checkout { public function checkout(ChargeableInterface $basket, PaymentMethodInterface $card) } class Gateway { public function purchase(ChargeableInterface $basket, PaymentMethodInterface $card) } https://github.com/neilcrookes/SoSOLIDFu
  • 30. Conclusion: Get Classy ● Actually only add some Interfaces, and an Event ● Our code is designed much better ● Easy to understand, extend ● More robust, less likely to introduce bugs ● Lots of classes is fine ● Lots of interfaces is fine
  • 31. Questions ● Now? ● At the pub? ● @neilcrookes