Showing posts with label Bread::Board. Show all posts
Showing posts with label Bread::Board. Show all posts

Oct 23, 2013

Providing with Providers and Bread::Board

So when I started using Dependency Injection the following problem happened, how do I Inject this dependency when the container is not accessible at this point. Ok, that sentence even confused me a little bit, so what do I mean. Let's say I have a Repository for Products that is injected into my controller. Each Product stored has one or more ProductVariants that is part of it's aggregate, which itself has Nested Categories. Loading this entire graph at once would be relatively expensive, so we decide to do some lazy loading via DBI in the classes. One problem, how on earth do we Inject a Database Handle all the way down to Categories. Most of these ways are against DI, but they are solutions to the problem, there are also ways to combine these. Also, your model class having a database handle is probably bad design itself, but I'm not going to get into that. Sadly I've done every one of these

Manual

Well at least you aren't hard coding the way to read your config file, or your database driver. You're smart enough to rely on an Interface rather than an Implementation. This is fraught with so many problems. Firstly if your web server (assuming it's a web application) is getting any kind of traffic at all you'll end up creating tons of database connections, you'll also be reading that config file every time (ok I forget if Config::Merge caches to memory, it might, but often when I see people design this way, they are basically slurping the file every time). Someday 5 years from now, someone is going to hate you because now they need to support replicants... and the config needs to support more connection strings, which means modifying every place you've done this. Also, you've completely lost the ability to inject your dependencies for whatever reason you may want to.

Inheritance/Composition

Ok, this is a little bit better than before, at least now you have Inverted your dependencies, you could provide the config or the database handle to the class. You've also put the code in a centralized place so it's easy to change when you need to. You're still reading the file fairly often, though perhaps less because it now depends on how long Product variant is alive. So what happens if your connection is lost? We still have a connection for each class, a connection that may now be held much longer. Why does Product Variant need access to the config? this is a violation of the Law of Demeter.

Naive Service Locator

We need to get rid of knowledge of the config. We can do this by using a Service Locator, which is simply a well known service to retrieve other services, usually a global singleton. In our example we're at least smart enough to allow ourselves to change the class out via injection for testing. We no longer have tons of connections or config reads. However, we now have a new problems, what happens when our Application Server forks a process and we lose the database connection? What about when our locator gets more complex, like nested containers, that could change or access, specifically with replication. Also our class is now directly dependent on Bread::Board, and its interface. At least we've stopped caring how our database handle is built. Our locator is a global singleton, and we can't change our Container class for testing.

Robust Service Locator

Ok, so this is much better we can now configure which locator instance we use at runtime. We have removed the dependency on the Bread::board interface. There is no longer a problem with database connections being dropped. However, our container is still a global singleton, and our class still knows about it, which again, law of Demeter.

Dependency Injection and Pass it down

For now I've been basically ignoring other classes because with all of these other approaches they aren't really a concern because you would do the same thing in every class, fetch your service. Much of the code is required here anyways, we always would have to do the sql, the transforms the loops. Dependency inversion is the opposite, do not think of how to retrieve the dependency instead have the dependency provided. But this becomes tricky to think of when you're 3 or more levels deep in your hierarchy. One way to do it simply pass the reference. We create a specific problem here, our Repository lifecycle is a singleton so we need to ensure re-connection, thus we must inject the connector which means we are immediately dependent on the DBIx::Connector interface. This doesn't seem that tricky until you add more than one service, which still may not seem that bad, until you have to add one later, and oh my god, now you're modifying several classes.

Dependency Injection with Providers

This next and final sample show's one way of doing this with Providers. A little context on a Provider first, a Provider is simply an object that can be used to retrieve a an instance of an object you need. It's really just a kind of factory, but tends to be specific to dependency injection, in scenarios where you need a new instance of an object each time. It seems that it might also work well for other cases, such as objects with a longer lifespan than a new instance on every request from the injector, but shorter than a permanent singleton. In short a provider should be able to provide you with an instance on request, without requiring to to depend on retrieval.

The code that I'm demonstrating will not work currently practical scenario, meaning one where variant parameters are required. I've opened a bug about resolving the issue. In the mean time, the patch is simple and you could apply it yourself. You could use BUILDARGS to rename an alternate key to the primary hashkey, in your models. You could also just define each model service one at a time instead of looping them, and actually validating their parameters.

You may note that I've removed the config, this was simply so I could build the code out so it works in completion. It maybe advantageous not to put config processing code in the Dependency injector, but rather provide the config to Bread::Board::Declare at the constructor via required services. This way of doing things requires much more code, but is also much more flexible. Every piece of the model, even those hat could not normally be accessed by the injector, can now have it's dependencies injected to it.

Jan 3, 2013

Inversion of Control Principle

If you're not familiar with the term "Inversion of Control"( IoC ) or "Dependency Injection" ( DI )you may wish to start with Martin Fowler's post on the subject. If you're looking for a way to do it with Perl, Bread::Board is the way to go. This post however is about the theory behind it, and a path to grokitude if you're finding the concepts challenging. I should advise that I am not yet a buddha on implementation.

What is it?

Now that you're familiar with an understanding of the terms that is not mine (or even if you didn't bother), you may be wondering what I mean by "Inversion of Control Principle", seeing as how we have the Dependency Injection Pattern and Inversion of Control Containers. I'm not sure if anyone actually uses the term "Inversion of Control Principle", though google seems to suggest I am not the first.

The essence of the Inversion of Control Principle is do not attempt to control your code, let its callers control it. Give your caller as much power as you can.

This is of course not a very academic statement

Dependency Inversion

An important piece of the Inversion of Control Principle is the common "Dependency Inversion". It is defined as:

  1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
  2. Abstractions should not depend upon details. Details should depend upon abstractions.
In more laymans terms depend on an interface and not a concrete implementation. For the Perler's. Do not depend on LWP or DBI, but depend on their interface. This is covered more in my post on Interface Driven Design.

Lifecycle Inversion of Control

A second piece of Inversion of Control is do not attempt to control your objects lifecycle. This means, do not enforce a singleton pattern, do not enforce a flyweight pattern, do not enforce an instance. Your objects should be instances always, if you want a singleton put it at the top level of your application or use a Dependency Injection framework to manage the lifecycle. Also package variables that are not constants are evil, they will bite you because they are essentially singletons. Always make your objects instances and let their client code determine their lifecycle.

How do I do it?

Well you don't have to use a fancy IoC/DI framework to do it. Those are simple tools to make life easier after you've designed your software to be consumed by them. To properly invert your control you first start by letting go. Huh? yeah I know.

You start by ensuring that your software has as few concrete dependencies as possible. Like I said you depend on interfaces. Some concrete dependencies are unavoidable, but try to make them uninteresting, or architecturally significant.

With Perl

Start by ensuring that concrete dependencies can be easily replaced at runtime. The easiest way to accomplish this is by allowing them to be passed to your constructor. when using Moose I tend to use lazy loading defaults a lot. Here's an example from cybersource.

sub _build_cybs_wsdl {
    my $self = shift;
 
    my $dir = $self->_production ? 'production' : 'test';
 
    load 'File::ShareDir::ProjectDistDir', 'dist_file';
    return load_class('Path::Class::File')->new(
            dist_file(
                'Business-CyberSource',
                $dir
                . '/'
                . 'CyberSourceTransaction_'
                . $self->cybs_api_version
                . '.wsdl'
            )
        );
}

has cybs_wsdl => (
    required  => 0,
    lazy      => 1,
    is        => 'ro',
    isa       => File,
    builder   => '_build_cybs_wsdl',
);
Although I don't consider it likely that anyone will ever need to use another WSDL for Cybersource, one could easily inject a new Path::Class::File to one when creating the client at the constructor. Another perfect example is the Client itself. It's designed to be useable as a singleton, because I never intend for someone to need to instantiate it twice, however I have not made it a singleton and internally I'm not aware of any code that it actually is treated as such (it appears to usually be instantiated at every request ).

Prefer Class, and Object interfaces to functional ones. Here's some code that demonstrates why.

# this works

use Class::Load 0.20 'load_class';

my $var = 'baz';

my $class = 'Foo::Bar';

my $result = load_class( $class )->class_method( $var ); # works wonders with ->new

# sometimes this will work, but not always. Try this with the various Dumper functions and see which ones work.

use Module::Load 'load';

my $package = 'Foo::Bar';

load $package, 'function';

my $result = function( $var ); # seems to only work if Foo::Bar's exporter works right, many packages have to be exported at compile time not runtime

# perl doesn't like stuff like this or really anything where I've tried substituting the package name into calling a function. at least not with strict on. This is a large reason I'd avoid functional interfaces. They are hard to substitute at runtime. 

load( $package );

my $function = $package . '::' . 'function';

$function->( $var );

I have even better real examples, such as my one in interfaces where I replaced LWP with the AnyEvent::LWP... but unfortunately that code has not been released to the public. The examples given are basically the same principle.

Dependency Injection Frameworks

Dependency Injection Frameworks are not required to use the Inversion of Control Principle they simply make injecting your dependencies and managing lifecycles easier. It also allows you to do concrete class substitution from one place along with deciding that objects lifecyle, and have it's dependencies inserted. When using a DI framework you should strive to call it only once per controller. Though a book that I've read suggests this is Domain Model controller and not an MVC controller, I was unable to make a full distinction.

This example runs particularly slow, probably due to reasons that people hate moose, however, if you remove the loop at the end you'll notice executing one time is about the same as ten, which means that most of this is due to class compiling and loading, actual runtime is fast (or at least, fast enough).

The important thing to pick up is how the Order object requires a payment_gateway that does submit, but it doesn't know how to get that object, or what the implementation will be. Our Dependency Injection framework then simply provides that dependency as needed. It would be trivial to replace our implementation of payment gateway with a different one.

The code is commented, to explain what it's doing where.