<blockquote class="gmail_quote" style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-width:1px;border-left-color:rgb(204, 204, 204);border-left-style:solid;padding-left:1ex"><meta http-equiv="content-type" content="text/html; charset=utf-8"><span class="Apple-style-span" style="border-collapse: collapse; color: rgb(80, 0, 80); font-family: arial, sans-serif; font-size: 13px; "><blockquote class="gmail_quote" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex; ">

This means you want dependency injection.  Classes should *not* know how<br>to build things that they have; that's the job for some other part of<br>the program.</blockquote><div><meta http-equiv="content-type" content="text/html; charset=utf-8"><span class="Apple-style-span" style="color: rgb(0, 0, 0); "><div class="im" style="color: rgb(80, 0, 80); ">

<blockquote class="gmail_quote" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex; ">

</blockquote></div></span></div></span></blockquote><div>... </div><blockquote class="gmail_quote" style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-width:1px;border-left-color:rgb(204, 204, 204);border-left-style:solid;padding-left:1ex">

<span class="Apple-style-span" style="border-collapse: collapse; color: rgb(80, 0, 80); font-family: arial, sans-serif; font-size: 13px; "><div><span class="Apple-style-span" style="color: rgb(0, 0, 0); "><div class="im" style="color: rgb(80, 0, 80); ">

<blockquote class="gmail_quote" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex; ">

Bread::Board is a Moose-based module for dependency injection.</blockquote></div><blockquote class="gmail_quote" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex; ">

... </blockquote><div><br></div></span></div></span></blockquote><div>
<div><br></div><div>It took some experimenting, but I've got something using Bread::Board that is way better than I had and still meets my goals of maximizing reuse and minimizing boiler plate.</div><div><br></div><div>

Since most of my classes use the same resources, I have one app container class that has app, log, db and ssh services defined. This container is sub-classed from Bread::Board::Container a la <a href="http://search.cpan.org/~stevan/Bread-Board-0.18/lib/Bread/Board/Manual/Concepts/Advanced.pod#Subclassing">http://search.cpan.org/~stevan/Bread-Board-0.18/lib/Bread/Board/Manual/Concepts/Advanced.pod#Subclassing</a></div>

<meta http-equiv="content-type" content="text/html; charset=utf-8"><div><br></div><div><a href="http://search.cpan.org/~stevan/Bread-Board-0.18/lib/Bread/Board/Manual/Concepts/Advanced.pod#___top"></a>The container uses a variable for the class name, and I pass that name to the container class constructor and it creates all the resources and returns an instance of the class I want. This gives me the reuse so I don't have to create the same container for different application classes. I'll probably have a few "standard" containers.</div>

<meta http-equiv="content-type" content="text/html; charset=utf-8"><div><br></div><div>The dependency management between resources is divine. It's giving me the ability to make cleaner, hierarchical services with more finely grained encapsulation. I had been using Moose::Role's 'with' and 'require' which provided primitive forms of encapsulation and dependency management, but the shortcomings are now especially clear.</div>

<div><br></div><div>It's kind of hard to show a complete example in an email, but here's how to get the app and run it, and then the container class from a working example. Feedback always appreciated.</div><div>
<br>
</div><meta http-equiv="content-type" content="text/html; charset=utf-8"><div>==========================</div><div></div><div><div>use app_cntnr;</div><div><br></div><div>my $c = app_cntnr->new(</div><div><span class="Apple-tab-span" style="white-space:pre">   </span>name  => 'app_cntnr',</div>

<div><span class="Apple-tab-span" style="white-space:pre">      </span>class => 'app',</div><div>);</div><div><br></div><div>my $app = $c->resolve( service => 'application' );</div><div><br></div><div>

$app->do_something();</div></div><div><br></div><div>==========================</div><div><div>package app_cntnr;</div><div><br></div><div>use Moose;</div><div>use Bread::Board;</div><div><br></div><div>extends 'Bread::Board::Container';</div>

<div><br></div><div>has 'class' => (</div><div><span class="Apple-tab-span" style="white-space:pre">   </span>is       => 'ro',</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>isa      => 'Str',</div>

<div><span class="Apple-tab-span" style="white-space:pre">      </span>required => 1,</div><div>);</div><div><br></div><div>sub BUILD {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>my $s = shift;</div>

<div><br></div><div><span class="Apple-tab-span" style="white-space:pre">     </span>container $s => as {</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">             </span>service 'log_svc' => (</div>

<div><span class="Apple-tab-span" style="white-space:pre">                      </span>class        => 'log_svc',</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>lifecycle    => 'Singleton',</div>

<div><span class="Apple-tab-span" style="white-space:pre">              </span>);</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">          </span>service 'db_svc' => (       #-- svc for the raw DBI database handle</div>

<div><span class="Apple-tab-span" style="white-space:pre">                      </span>class        => 'db_svc',</div><div><span class="Apple-tab-span" style="white-space:pre">                 </span>dependencies => { log_svc => depends_on('log_svc'), }</div>

<div><span class="Apple-tab-span" style="white-space:pre">              </span>);</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">          </span>service 'exec_db_svc' => (  #-- interacts with the database</div>

<div><span class="Apple-tab-span" style="white-space:pre">                      </span>class        => 'exec_db_svc',</div><div><span class="Apple-tab-span" style="white-space:pre">                    </span>dependencies => {</div><div><span class="Apple-tab-span" style="white-space:pre">                         </span>log_svc => depends_on('log_svc'),</div>

<div><span class="Apple-tab-span" style="white-space:pre">                              </span>db_svc  => depends_on('db_svc'),</div><div><span class="Apple-tab-span" style="white-space:pre">                  </span>}</div><div><span class="Apple-tab-span" style="white-space:pre">            </span>);</div>

<div><br></div><div><span class="Apple-tab-span" style="white-space:pre">             </span>service 'ssh_svc' => (      #-- svc for the raw Net::SSH2 connection</div><div><span class="Apple-tab-span" style="white-space:pre">                      </span>class        => 'ssh_svc',</div>

<div><span class="Apple-tab-span" style="white-space:pre">                      </span>dependencies => { log_svc => depends_on('log_svc'), }</div><div><span class="Apple-tab-span" style="white-space:pre">          </span>);</div><div>

<br></div><div><span class="Apple-tab-span" style="white-space:pre">                </span>service 'exec_ssh_svc' => ( #-- Interacts with remote OS over ssh</div><div><span class="Apple-tab-span" style="white-space:pre">                 </span>class        => 'exec_ssh_svc',</div>

<div><span class="Apple-tab-span" style="white-space:pre">                      </span>dependencies => {</div><div><span class="Apple-tab-span" style="white-space:pre">                         </span>log_svc => depends_on('log_svc'),</div><div><span class="Apple-tab-span" style="white-space:pre">                         </span>ssh_svc  => depends_on('ssh_svc'),</div>

<div><span class="Apple-tab-span" style="white-space:pre">                      </span>}</div><div><span class="Apple-tab-span" style="white-space:pre">            </span>);</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">          </span>service 'application' => (</div>

<div><span class="Apple-tab-span" style="white-space:pre">                      </span>class        => $s->class,</div><div><span class="Apple-tab-span" style="white-space:pre">                     </span>dependencies => {</div><div><span class="Apple-tab-span" style="white-space:pre">                         </span>log_svc  => depends_on('log_svc'),</div>

<div><span class="Apple-tab-span" style="white-space:pre">                              </span>exec_db  => depends_on('exec_db_svc'),</div><div><span class="Apple-tab-span" style="white-space:pre">                            </span>exec_ssh => depends_on('exec_ssh_svc'),</div>

<div><span class="Apple-tab-span" style="white-space:pre">                      </span>}</div><div><span class="Apple-tab-span" style="white-space:pre">            </span>);</div><div><span class="Apple-tab-span" style="white-space:pre">   </span>};</div>

<div>}</div><div><br></div><div>no Moose;</div><div><br></div><div>1;</div><div><br></div></div><div><br></div><div><br></div><div><br></div><div><br></div>Regards,<br>Sean<br><br><br></div><div><br><br><div class="gmail_quote">

On Mon, May 2, 2011 at 12:43 PM, Sean Blanton <span dir="ltr"><<a href="mailto:sean@blanton.com" target="_blank">sean@blanton.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>Awesome, thanks for the detailed feedback.</div><div><div> </div><blockquote class="gmail_quote" style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-width:1px;border-left-color:rgb(204, 204, 204);border-left-style:solid;padding-left:1ex">



This means you want dependency injection.  Classes should *not* know how<br>to build things that they have; that's the job for some other part of<br>the program.</blockquote><div><br></div></div><div>Time to review my OO patterns!</div>


<div>
<div><br></div><blockquote class="gmail_quote" style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-width:1px;border-left-color:rgb(204, 204, 204);border-left-style:solid;padding-left:1ex">



Bread::Board is a Moose-based module for dependency injection.</blockquote></div><blockquote class="gmail_quote" style="margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0.8ex;border-left-width:1px;border-left-color:rgb(204, 204, 204);border-left-style:solid;padding-left:1ex">



... </blockquote><div><br></div>I'm going to start using it.<div><br clear="all">Regards,<br><font color="#888888">Sean<br>
<br></font><div class="gmail_quote"><div>On Sat, Apr 30, 2011 at 12:36 AM, Jonathan Rockway <span dir="ltr"><<a href="mailto:jon-chicagotalk@jrock.us" target="_blank">jon-chicagotalk@jrock.us</a>></span> wrote:<br>


</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>
<div>* On Fri, Apr 29 2011, Sean Blanton wrote:<br>
> Yeah, the 'Maybe' works great, and thanks for pointing me to the doc.<br>
><br>
> My ssh_builder looks like your safe_ssh, not sure what you meant. I<br>
> have one &ssh_builder for all (86!) classes. If a new class wants an<br>
> ssh connection, it consumes the 'SSH' role with the ssh attribute<br>
> populated by &ssh_builder.<br>
<br>
</div><br></div><div><div></div><div>
Bread::Board is a Moose-based module for dependency injection.  You can<br>
write something like this:<br>
<br>
    use Bread::Board;<br>
    my $c = container 'MyApp' as {<br>
        service 'ssh' => (<br>
            class     => 'Net::SSH',<br>
            lifecycle => 'Singleton', # if you want the same<br>
                                      # instance each time<br>
        );<br>
<br>
        service 'LogInAndDeleteEverything' => (<br>
            class        => 'MyApp::Action::LogInAndDeleteEverything',<br>
            dependencies => [ depends_on('ssh') ],<br>
        );<br>
    };<br>
<br>
    my $action = $c->resolve( service => 'LogInAndDeleteEverything' );<br>
    $action->execute; # everything is deleted<br>
<br>
Your MyApp::Action::LogInAndDeleteEverything would look something like:<br>
<br>
    package MyApp::Action::LogInAndDeleteEverything;<br>
    use Moose;<br>
<br>
    has 'ssh' => (<br>
        is => 'ro',<br>
        isa => 'Net::SSH',<br>
        required => 1,<br>
    );<br>
<br>
    sub execute { ... }<br>
<br>
Bread::Board also has support for type mapping, so theoretically there<br>
won't be much boilerplate even if you have 86 classes that all need the<br>
'ssh' service.  I haven't used this feature much, however.<br>
<br>
In addition to class injection, there is also block injection, where you<br>
can use a coderef to build the instance.  Sometimes convenient.<br>
<br>
It's also worth noting that services can have parameters and that you<br>
can pass in args during "resolve", so if your code looked something<br>
like:<br>
<br>
    has 'ssh' => ( ... as above ... );<br>
<br>
    has 'chdir_to' => ( ... );<br>
<br>
Your service could be changed to:<br>
<br>
    service 'LogInAndDeleteEverything' => ( # remind me never to use such<br>
                                            # a long name for an example!<br>
        class        => 'MyApp::Action::LogInAndDeleteEverything',<br>
        dependencies => [ depends_on('ssh') ],<br>
        parameters   => { chdir_to => { default => '/' } },<br>
    );<br>
<br>
Then, if you want to delete /etc, you would say:<br>
<br>
    my $action = $c->resolve(<br>
        service    => 'LogInAndDeleteEverything',<br>
        parameters => { chdir_to => '/etc' },<br>
    );<br>
    $action->execute; # BAI.<br>
<br>
Anyway, Bread::Board is pretty simple and easy to hack on, so it should<br>
be possible to do what you want without making a mess.<br>
<br>
One more thing: you can make diagrams of your services and your<br>
dependencies:<br>
<br>
<a href="https://github.com/jrockway/BreadBoard/commit/83de2f946b0af5a129146a085abfc95173ed0130" target="_blank">https://github.com/jrockway/BreadBoard/commit/83de2f946b0af5a129146a085abfc95173ed0130</a><br>
<br>
Finally, I used Bread::Board::Service as an example in the README here:<br>
<br>
<a href="https://github.com/jrockway/graphviz-hasa" target="_blank">https://github.com/jrockway/graphviz-hasa</a><br>
<br>
Pretty!<br>
<font color="#888888"><br>
--<br>
print just => another => perl => hacker => if $,=$"<br>
</font><div><div></div><div>_______________________________________________<br>
Chicago-talk mailing list<br>
<a href="mailto:Chicago-talk@pm.org" target="_blank">Chicago-talk@pm.org</a><br>
<a href="http://mail.pm.org/mailman/listinfo/chicago-talk" target="_blank">http://mail.pm.org/mailman/listinfo/chicago-talk</a></div></div></div></div></blockquote></div><br></div>
</blockquote></div><br></div>