SlideShare ist ein Scribd-Unternehmen logo
1 von 22
Downloaden Sie, um offline zu lesen
A Dependency Injection Primer

     In which @rowan_m discovers a 
        gateway drug to quality.
Chapter 1  The Green Field

   In which our heroine begins a new 
     endeavour for a local publican
Developers shouldn't couple

 How one might start to write their application code:
$bar = new DrinkMapper();
$drink = $bar->getCocktail('bloody mary');
Naïve use of patterns

Supporting code as written by our eager, young protagonist:
 
// our data mapper
class DrinkMapper {
    public function getCocktail($name) {
        $bar = new PitcherAndPiano();
        $row = $bar->getCocktail($name);
        return new Cocktail($row);
    }
}
 
// our domain object
class Cocktail extends ArrayObject {}
Naïve use of patterns (continued)

Supporting code as written by our eager, young protagonist:
 
// our storage
class PitcherAndPiano {
    public function getCocktail($name) {
        $db = new PDO('mysql:host=localhost;'.
            'dbname=pnp', 'puser', 'ppass');
        $row = $db
            ->query("SELECT * FROM cocktails'.
                ' WHERE name = '$name'")
            ->fetch();
        return $row;
    }
}
Chapter 2  Foreboding Clouds

    In which the gruff senior developer 
      mutters darkly about unit tests 
Constructors for a house of cards

  Our heroine attempts to test 
from the deepest class upwards.
                
               
 Emboldened by her success 
with PHPUnit_Extensions_
 Database_TestCase on the 
PitcherAndPiano class, she 
        moves on...
Foundations begin to crumble

    This method  cannot  be unit tested due to these
          concrete dependencies within the code.
 
// our data mapper
class DrinkMapper {
    public function getCocktail($name) {
        $bar = new PitcherAndPiano();
        $row = $bar->getCocktail($name);
        return   new Cocktail($row);
    }
}
Filling in the cracks

    After some research, our intrepid heroine tries Setter Injection:
class DrinkMapper {
    private $_bar;

        public function setBar(
                PitcherAndPiano $bar) {
            $this->_bar = $bar;
        }

        public function getCocktail($name) {
            $row = $this->_bar->getCocktail($name);
            return new Cocktail($row);
        }
}
Setter Injection Abuse

              Still the saturnine senior shows scorn
                  for the implied improvements.
                                  
                               
                               
    Setters should be used with caution as they introduce 
                         mutability.
      Immutable classes are simpler and more efficient.
                               
                               
                                   
 This setter requires that it is called before the finder method.
       The object cannot be constructed in a valid state.
Constructing correctly

    Enlightened, our heroine progresses to Constructor Injection:

class DrinkMapper {
    private $_bar;

        public function setBar__construct(
                PitcherAndPiano $bar) {
            $this->_bar = $bar;
        }

        public function getCocktail($name) {
            $row = $this->_bar->getCocktail($name);
            return new Cocktail($row);
        }
}
Understand rules to break them

   Of course, our senior now provides contrary observations.
                                
                              
                                   
A long list of constructor parameters may indicate the class has 
  too many responsibilities. However, it may be valid. Setter 
             injection is the right solution in places.
                                   
                                  
                                   
 Constructor parameters are not self­documenting. One must 
                refer to the code of the called class.
Chapter 3   Weather the Storm

   In which our heroine puts her new skills 
     into practice via a training montage.
The other class

Our heroine ponders why her new skills do not fit the other class.
class DrinkMapper {
    private $_bar;

        public function __construct(
                PitcherAndPiano $bar) {
            $this->_bar = $bar;
        }

    public function getCocktail( 
            $name, Cocktail $cocktail) {
        $row = $this->_bar->getCocktail($name);
        return $cocktail->exchangeArray($row);
    }
}
An awkward feeling

 Without disturbing the senior's slumber, our heroine ponders...

                               
 That is now dependent on another mutable class. It does not 
       make sense for a Cocktail to exist sans content.
                              
                               
 Callers must now construct the return type too, leading to a 
                great deal of repeated code.
The industrial revolution

 Inspiration strikes and our heroine recalls the Factory Pattern:
class DrinkFactory {
    public static $ctClass = 'Cocktail';
   
    public static function getCocktail(array $data) {
        return new self::$ctClass($data);
    }
}
 
class DrinkMapper { [...]
    public function getCocktail($name) {
        $row = $this->_bar->getCocktail($name);
        return DrinkFactory::getCocktail($row);
    }
}
Mass production

          With a few tweaks, our heroine obtains her
                 holy grail of 100% coverage!

                              
Factories can replace constructors within libraries. Controllers 
may arguably use constructors directly due to their specialised 
                            nature.
                                
                              
Factories may also detect the presence of an object over a class 
            name to aid in injecting mock objects.
Chapter 4   Pastures New

 In which our heroine travels on her 
    new wheel, only to discover...
      she did not invent it first!
Exploring the frontier

          Our heroine begins to push the boundaries.

                               
 Define interfaces for injected classes for even looser coupling.

                               
      Swap implementations in real­life, not just mocks.
Founding fathers

          Martin Fowler first coined the term as
         a specialisation of Inversion of Control:
    http://martinfowler.com/articles/injection.html
                               
                          
       He additionally covers Interface Injection
                 and Service Locators

                          
            Goodness, he's a sharp fellow:
           http://twitter.com/martinfowler
They are among us!

 Richard Miller has written rather extensively on the subject
                  with respect to Symfony 2:
 http://miller.limethinking.co.uk/tag/dependency­injection/

                             
            Take advantage of his delicious brain.

                             
              He may also be found on Twitter:
               http://twitter.com/mr_r_miller
Questions & Discussion

          fin

Weitere ähnliche Inhalte

Ähnlich wie A Dependency Injection Primer

laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutesBarang CK
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 MinutesAzim Kurt
 
Migrating to dependency injection
Migrating to dependency injectionMigrating to dependency injection
Migrating to dependency injectionJosh Adell
 
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
 
Dependency Injection and Pimple
Dependency Injection and PimpleDependency Injection and Pimple
Dependency Injection and PimpleDQNEO
 
Does your code spark joy? Refactoring techniques to make your life easier.
Does your code spark joy? Refactoring techniques to make your life easier.Does your code spark joy? Refactoring techniques to make your life easier.
Does your code spark joy? Refactoring techniques to make your life easier.Juciellen Cabrera
 
Rich Model And Layered Architecture in SF2 Application
Rich Model And Layered Architecture in SF2 ApplicationRich Model And Layered Architecture in SF2 Application
Rich Model And Layered Architecture in SF2 ApplicationKirill Chebunin
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
WordPress Capabilities Magic
WordPress Capabilities MagicWordPress Capabilities Magic
WordPress Capabilities Magicmannieschumpert
 
Effective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good PracticesEffective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good PracticesNaresha K
 
PHP OOP Lecture - 02.pptx
PHP OOP Lecture - 02.pptxPHP OOP Lecture - 02.pptx
PHP OOP Lecture - 02.pptxAtikur Rahman
 
Михаил Крайнюк - Form API + Drupal 8: Form and AJAX
Михаил Крайнюк - Form API + Drupal 8: Form and AJAXМихаил Крайнюк - Form API + Drupal 8: Form and AJAX
Михаил Крайнюк - Form API + Drupal 8: Form and AJAXDrupalSib
 
Object Trampoline: Why having not the object you want is what you need.
Object Trampoline: Why having not the object you want is what you need.Object Trampoline: Why having not the object you want is what you need.
Object Trampoline: Why having not the object you want is what you need.Workhorse Computing
 
Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0Yevhen Kotelnytskyi
 
Ioc container | Hannes Van De Vreken | CODEiD
Ioc container | Hannes Van De Vreken | CODEiDIoc container | Hannes Van De Vreken | CODEiD
Ioc container | Hannes Van De Vreken | CODEiDCODEiD PHP Community
 
Corinna-2023.pptx
Corinna-2023.pptxCorinna-2023.pptx
Corinna-2023.pptxCurtis Poe
 
Task 2
Task 2Task 2
Task 2EdiPHP
 

Ähnlich wie A Dependency Injection Primer (20)

PHPSpec BDD for PHP
PHPSpec BDD for PHPPHPSpec BDD for PHP
PHPSpec BDD for PHP
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 
Migrating to dependency injection
Migrating to dependency injectionMigrating to dependency injection
Migrating to dependency injection
 
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...
 
Dependency Injection and Pimple
Dependency Injection and PimpleDependency Injection and Pimple
Dependency Injection and Pimple
 
PHPSpec BDD Framework
PHPSpec BDD FrameworkPHPSpec BDD Framework
PHPSpec BDD Framework
 
Does your code spark joy? Refactoring techniques to make your life easier.
Does your code spark joy? Refactoring techniques to make your life easier.Does your code spark joy? Refactoring techniques to make your life easier.
Does your code spark joy? Refactoring techniques to make your life easier.
 
Rich Model And Layered Architecture in SF2 Application
Rich Model And Layered Architecture in SF2 ApplicationRich Model And Layered Architecture in SF2 Application
Rich Model And Layered Architecture in SF2 Application
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
WordPress Capabilities Magic
WordPress Capabilities MagicWordPress Capabilities Magic
WordPress Capabilities Magic
 
Effective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good PracticesEffective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good Practices
 
PHP OOP Lecture - 02.pptx
PHP OOP Lecture - 02.pptxPHP OOP Lecture - 02.pptx
PHP OOP Lecture - 02.pptx
 
Михаил Крайнюк - Form API + Drupal 8: Form and AJAX
Михаил Крайнюк - Form API + Drupal 8: Form and AJAXМихаил Крайнюк - Form API + Drupal 8: Form and AJAX
Михаил Крайнюк - Form API + Drupal 8: Form and AJAX
 
Object Trampoline: Why having not the object you want is what you need.
Object Trampoline: Why having not the object you want is what you need.Object Trampoline: Why having not the object you want is what you need.
Object Trampoline: Why having not the object you want is what you need.
 
Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0Как получить чёрный пояс по WordPress? v2.0
Как получить чёрный пояс по WordPress? v2.0
 
Ioc container | Hannes Van De Vreken | CODEiD
Ioc container | Hannes Van De Vreken | CODEiDIoc container | Hannes Van De Vreken | CODEiD
Ioc container | Hannes Van De Vreken | CODEiD
 
Corinna-2023.pptx
Corinna-2023.pptxCorinna-2023.pptx
Corinna-2023.pptx
 
Task 2
Task 2Task 2
Task 2
 
My Development Story
My Development StoryMy Development Story
My Development Story
 

Mehr von Rowan Merewood

Estimation or, "How to Dig your Grave"
Estimation or, "How to Dig your Grave"Estimation or, "How to Dig your Grave"
Estimation or, "How to Dig your Grave"Rowan Merewood
 
Algorithm, Review, Sorting
Algorithm, Review, SortingAlgorithm, Review, Sorting
Algorithm, Review, SortingRowan Merewood
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy CodeRowan Merewood
 
State Machines to State of the Art
State Machines to State of the ArtState Machines to State of the Art
State Machines to State of the ArtRowan Merewood
 

Mehr von Rowan Merewood (6)

Sensible scaling
Sensible scalingSensible scaling
Sensible scaling
 
Estimation or, "How to Dig your Grave"
Estimation or, "How to Dig your Grave"Estimation or, "How to Dig your Grave"
Estimation or, "How to Dig your Grave"
 
TDD and Getting Paid
TDD and Getting PaidTDD and Getting Paid
TDD and Getting Paid
 
Algorithm, Review, Sorting
Algorithm, Review, SortingAlgorithm, Review, Sorting
Algorithm, Review, Sorting
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
State Machines to State of the Art
State Machines to State of the ArtState Machines to State of the Art
State Machines to State of the Art
 

Kürzlich hochgeladen

Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 

Kürzlich hochgeladen (20)

Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 

A Dependency Injection Primer