The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# PODNAME: Bread::Board::Manual::Concepts
# ABSTRACT: An overview of the concepts in Bread::Board

__END__

=pod

=head1 NAME

Bread::Board::Manual::Concepts - An overview of the concepts in Bread::Board

=head1 VERSION

version 0.27

=head1 INTRODUCTION

This document attempts to convey the central concepts of Bread::Board
and show how they work together to manage both object lifecycles and
object dependencies.

In this document we use the raw OO syntax of Bread::Board, this is
so that the concepts being illustrated are not clouded by syntactic
sugar. We only introduce the I<sugar> layer at the end, at which point
we hope that it will become clear what is going on "under the hood"
when you use it.

=head1 CONCEPTS

=head2 What is Inversion of Control?

Inversion of Control (or IoC) is the very simple idea of releasing
control of some part of your application over to some other part
of your application, be it your code or an outside framework.

IoC is a common paradigm in GUI frameworks, whereby you give up
control of your application flow to the framework and install your
code at callbacks hooks within the framework. For example, take a
very simple command line interface; the application asks a
question, the user responds, the application processes the answer
and asks another question, and so on until it is done. Now consider
the GUI approach for the same application; the application displays
a screen and goes into an event loop, users actions are processed
with event handlers and callback functions. The GUI framework has
inverted the control of the application flow and relieved your
code from having to deal with it.

IoC is also sometimes referred to as 'Dependency Injection' or the
'Dependency Injection Principle', and many people confused the two.
However IoC and dependency injection are not the same, in fact the
concepts behind dependency injection are actually just an
I<example of> IoC principles in action, in particular about your
applications dependency relationships. IoC is also sometimes
referred to as the Hollywood Principle because of the I<don't call
us we'll call you> approach of things like callback functions and
event handlers.

Howard Lewis Ship, the creator of the HiveMind IoC Framework, once
referred to dependency injection as being the inverse of garbage
collection. With garbage collection you hand over the details of
the destruction of your objects to the garbage collector. With
dependency injection you are handing over control of object
creation, which also includes the satisfaction of your dependency
relationships.

The following sections will explain the basis concepts around the
Bread::Board and how it relates to the concept of IoC.

=head2 Containers

The central part of just about any IoC framework is the container.
A container's responsibilities are roughly to dispense services and
to handle the resolution of said service's dependency relationships.

First we can start with a simple container for our services to
live in. We give the container a name so that we can address it
later on, think of this like a package namespace.

  my $c = Bread::Board::Container->new( name => 'Application' );

Next we need to add a service to that container (we will explain
services a little later on).

  $c->add_service(
      Bread::Board::BlockInjection->new(
          name  => 'logger',
          block => sub { Logger->new() }
      )
  );

Now if we want an instance of our 'logger' service, we simply ask the
container for it.

  my $logger_service = $c->fetch('logger');

And we then can ask the service to give us an instance of our Logger
object.

  my $logger = $logger_service->get;

Or if we want to make this even simpler we can use the C<resolve> method
of the container object.

  my $logger = $c->resolve( service => 'logger' );

The C<resolve> method will look up the service asked for and return the
instance, which is basically equivalent to the chained C<fetch> and C<get>
calls above.

=head2 Dependency Management

Dependency management is also quite simple, and is easily shown
with an example. But first lets create another component for our
container, a database connection.

  $c->add_service(
      Bread::Board::BlockInjection->new(
          name  => 'db_conn',
          block => sub { DBI->connect('dbi:mysql:test', '', '') }
      )
  );

Now lets add an authenticator to our container. The authenticator
requires both a database connection and a logger instance in its
constructor. We specify dependency relationships between services
by providing a HASH of Bread::Board::Dependency objects which
themselves have a path to the services they depend upon. In this
case since all these services are in the same container, the
service path is simply the name.

  $c->add_service(
      Bread::Board::BlockInjection->new(
          name  => 'authenticator',
          block => sub {
                my $service = shift;
                Authenticator->new(
                    db_conn => $service->param('db_conn'),
                    logger  => $service->param('logger')
                );
          },
          dependencies => {
              db_conn => Bread::Board::Dependency->new(
                  service_path => 'db_conn'
              ),
              logger  => Bread::Board::Dependency->new(
                  service_path => 'logger'
              ),
          }
      )
  );

As you can see, the first argument to our service subroutine is
actually our service instance. Through this we can access the
resolved dependencies and use them in our Authenticator object's
constructor.

The above example is deceptively simple, but really powerful.
What you don't see on the surface is that Bread::Board is
completely managing initialization order for you. No longer to
do you need to worry if your database is connected or your logger
initialized and in what order you need to do that initialization,
Bread::Board handles that all for you, including circular
dependencies. This may not seem terribly interesting in such a
small example, but the larger an application grows, the more
sensitive it becomes to these kinds of initialization order issues.

=head2 Lifecycle Management

The default lifecycle for Bread::Board::Service components is a
'prototype' lifecycle, which means each time we ask for say, the
logger, we will get a new instance back. There is also another
option for lifecycle management that we call 'Singleton'. Here
is an example of how we would use the 'Singleton' lifecycle to
ensure that you always get back the same logger instance.

  $c->add_service(
      Bread::Board::BlockInjection->new(
          lifecycle => 'Singleton',
          name      => 'logger',
          block     => sub { Logger->new() }
      )
  );

Now each time we request a new logger component from our container
we will get the exact same instance. Being able to change between
the different lifecycles by simply changing one service parameter
can come in very handy as you application grows. Extending this
idea, it is possible to see how you could create your own custom
service objects to manage your specific lifecycle needs, such as
a pool of database connections.

=head2 Services

Up until now, we have shown the default way of creating a service
by using the Bread::Board::BlockInjection and an anonymous
subroutine. But this is not the only way to go about this. Those
who have encountered IoC in the Java world may be familiar with
the idea that there are 3 'types' of IoC/Dependency Injection;
Constructor Injection, Setter Injection, and Interface Injection.
In Bread::Board we support both Constructor and Setter injection,
it is the authors opinion though that Interface injection was not
only too complex, but highly java specific and the concept did
not adapt itself well to perl.

=over 4

=item Block Injection

While not in the 'official' 3 types (mostly because it's not
possible in Java), but found in a few Ruby IoC frameworks,
BlockInjection is by far the most versatile type. It simply
requires a subroutine and a name and you do all the rest of
it yourself.

  $c->add_service(
      Bread::Board::BlockInjection->new(
          name  => 'logger',
          class => 'ComplexLogger',
          block => sub {
              my $s = shift;
              my $l = ComplexLogger->new(
                  file => $s->param('log_file')
              );
              $l->init_with_timezone( $s->param('timezone') );
              $l->log_timestamp;
              $l;
          },
          dependencies => {
              log_file => Bread::Board::Dependency->new(
                  service_path => 'log_file'
              ),
              timezone => Bread::Board::Dependency->new(
                  service_path => 'timezone'
              ),
          }
      )
  );

BlockInjection comes in really handy when your object requires
more then just constructor parameters and needs some more complex
initialization code. As long as your subroutine block returns an
object, everything else is fair game. Also note the optional 'class'
parameter, which when supplied will perform a basic type check on
the result of the subroutine block.

=item Constructor Injection

Bread::Board also supports Constructor Injection. With constructor
injection, the service calls the class's constructor and feeds it
the dependencies you specify. This promotes what is called a
"Good Citizen" object, or an object who is completely initialized
upon construction.

  $c->add_service(
      Bread::Board::ConstructorInjection->new(
          name         => 'authenticator',
          class        => 'Authenticator',
          dependencies => {
              db_conn => Bread::Board::Dependency->new(
                  service_path => 'db_conn'
              ),
              logger  => Bread::Board::Dependency->new(
                  service_path => 'logger'
              ),
          }
      )
  );

Since Bread::Board is built both with L<Moose> and for use with
L<Moose> objects, it makes the assumption here that the constructor
takes named arguments. Here is our earlier authenticator service
rewritten to use constructor injection. This is by far the simplest
injection type as it requires little more then a class name and
a HASH of dependencies.

=item Setter Injection

Bread::Board also supports Setter Injection. The idea behind
setter injection is that for each component dependency a
corresponding setter method must exist. This style has been
popularized by the Spring java framework. I will be honest,
I don't find this type of injection as useful as block of
constructor, but it can come in handy if your object prefers
you to call setters to initialize it. Here is a fairly contrived
 example using the L<JSON> module.

  $c->add_service(
      Bread::Board::SetterInjection->new(
          name         => 'json',
          class        => 'JSON',
          dependencies => {
              utf8   => Bread::Board::Literal->new(
                  name  => 'true',
                  value => 1
              )
              pretty => Bread::Board::Literal->new(
                  name  => 'true',
                  value => 1
              )
          }
      )
  );

Setter injection actually creates the object without passing any
arguments to the constructor, then loops through the keys in the
dependency HASH and treats each key as a method name, and each
value as that method's argument. In this case, the above is the
equivalent of doing:

   my $json = JSON->new;
   $json->utf8(1);
   $json->pretty(1);

You might have been wondering about the fact we didn't specify
Bread::Board::Dependency objects in our dependency HASH, but
instead supplied Bread::Board::Literal instances. Bread::Board::Literal
is just another Service type that simply holds a literal value,
or a constant. When dependencies are specified like this,
Bread::Board internally converts them into Bread::Board::Dependency
whose service is already resolved to that service.

=back

=head2 Hierarchal Containers

Up until now, we have seen basic containers which only have a single
level of components. As your application grows larger it may become
useful to have a more hierarchal approach to your containers.
Bread::Board::Container supports this behavior through its many
subcontainer methods. Here is an example of how we might re-arrange
the previous examples using subcontainers.

  my $app_c = Bread::Board::Container->new( name => 'app' );

  my $db_c = Bread::Board::Container->new( name => 'database' );
  $db_c->add_service(
      Bread::Board::BlockInjection->new(
          name  => 'db_conn'
          block => sub {
              my $s = shift;
              return DBI->connect(
                  $s->param('dsn'),
                  $s->param('username'),
                  $s->param('password')
              );
          },
          dependencies => {
              dsn      => Bread::Board::Literal->new(
                  name  => 'dsn',
                  value => 'dbi:mysql:test'
              ),
              username => Bread::Board::Literal->new(
                  name  => 'username',
                  value => 'user'
              ),
              password => Bread::Board::Literal->new(
                  name  => 'password',
                  value => '****'
              ),
          }
      )
  );

  $app_c->add_sub_container( $db_c );

  my $log_c = Bread::Board::Container->new( name => 'logging' );
  $log_c->add_service(
      Bread::Board::Literal->new(
          name  => 'log_file',
          value => '/var/log/app.log'
      )
  );
  $log_c->add_service(
      Bread::Board::ConstructorInjection->new(
          name  => 'logger',
          class => 'Logger',
          dependencies => {
              log_file => Bread::Board::Dependency->new(
                  service_path => 'log_file'
              )
          }
      )
  );

  $app_c->add_sub_container( $log_c );

  my $sec_c = Bread::Board::Container->new( name => 'security' );
  $sec_c->add_service(
      Bread::Board::ConstructorInjection->new(
          name         => 'authenticator',
          class        => 'Authenticator',
          dependencies => {
              db_conn => Bread::Board::Dependency->new(
                  service_path => '../database/db_conn'
              ),
              logger  => Bread::Board::Dependency->new(
                  service_path => '../logging/logger'
              ),
          }
      )
  );

  $app_c->add_sub_container( $sec_c );

  $app_c->add_service(
      Bread::Board::ConstructorInjection->new(
          name         => 'app',
          class        => 'Application',
          dependencies => {
              auth    => Bread::Board::Dependency->new(
                  service_path => '/security/authenticator'
              ),
              db_conn => Bread::Board::Dependency->new(
                  service_path => '/database/db_conn'
              ),
              logger  => Bread::Board::Dependency->new(
                  service_path => '/logging/logger'
              ),
          }
      )
  );

So, as an example that can be seen above, hierarchal containers can be used as a
form of namespacing to organize your Bread::Board
configuration better. As it is shown with the 'authenticator' service,
it is possible to address services outside of your container
using path notation. In this case the 'authenticator' service
makes the assumption that its parent container has both a
'database' and a 'logging' sub-container and they contain a
'db_conn' and 'logger' service respectively. And as is shown
in the 'app' service, it is also possible to address services
using an absolute path notation.

=head2 Sugar Layer

So, up until now we have been creating all our Bread::Board objects
by hand. As you can tell, this is both verbose and tedious. To
make your life easier, Bread::Board provides a simple I<sugar>
layer over these objects. Here is the equivalent of the above
Bread::Board configuration using the sugar layer.

  my $c = container 'app' => as {

      container 'database' => as {
          service 'db_conn' => (
              block => sub {
                  my $s = shift;
                  return DBI->connect(
                      $s->param('dsn'),
                      $s->param('username'),
                      $s->param('password')
                  );
              },
              dependencies => {
                  dsn      => ( service 'dsn'      => 'dbi:mysql:test' ),
                  username => ( service 'username' => 'user' ),
                  password => ( service 'password' => '****' ),
              }
          )
      };

      container 'logging' => as {
          service 'log_file' => '/var/log/app.log';
          service 'logger' => (
              class        => 'Logger',
              dependencies => {
                  log_file => depends_on('log_file'),
              }
          )
       };

      container 'security' => as {
          service 'authenticator' => (
              class => 'Authenticator',
              dependencies => {
                  db_conn => depends_on('../database/db_conn'),
                  logger  => depends_on('../logging/logger'),
              }
          )
      };

      service 'app' => (
          class => 'Application',
          dependencies => {
              auth    => depends_on('/security/authenticator'),
              db_conn => depends_on('/database/db_conn'),
              logger  => depends_on('/logging/logger'),
          }
      )
  };

As you can see this not only makes the code shorter, but more
declarative and easier to read.

=head1 SEE ALSO

This article is based on an article I wrote for The Perl Journal
about my earlier L<IOC> module. That article can be found online
at L<http://www.drdobbs.com/windows/184416179>.

=head1 AUTHOR

Stevan Little <stevan@iinteractive.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2013 by Infinity Interactive.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut