Copland an IOC Containers in Real Use

  • Thread starter Carsten Eckelmann
  • Start date
C

Carsten Eckelmann

Hi,

every so often I go and read the wonderful stuff, that Jamis has put
together for copland (http://copland.rubyforge.org). Everything makes
sense to me so far and the examples are simple enough to follow how it
works.

Still I just don't get it. I still can't grasp what it is that I get,
when I use copland. So my question to you, fellow rubyists: Is someone
out there actually using it for a real world project? Would care and
enlighten me why you chose copland and how it improves your project?

Yes and thanks to Jamis for making such a nice Product even if it's way
over my head :)

Cheers,
Carsten.
 
J

Jamis Buck

Carsten said:
Hi,

every so often I go and read the wonderful stuff, that Jamis has put
together for copland (http://copland.rubyforge.org). Everything makes
sense to me so far and the examples are simple enough to follow how it
works.

I'm so glad to hear that the documentation is readable. :)
Still I just don't get it. I still can't grasp what it is that I get,
when I use copland. So my question to you, fellow rubyists: Is someone
out there actually using it for a real world project? Would care and
enlighten me why you chose copland and how it improves your project?

This is a common complaint that I hear about IoC containers in general,
and Copland specifically. Especially in Ruby. Given Ruby's dynamic
nature, I will confess that an IoC container does not buy you as much
functionality as in a language like, say, Java. However, I have found
that for large projects, Copland *can* make life easier. I'll say it
again: *for large projects, Copland can make life easier.* Copland will
buy you very little for small projects, and can in fact overcomplicate
things if the project is of insufficient scope.

One more caveat before I launch into my use case: everything I use
Copland for, can *definately* be done in another way in Ruby. I just
know I'm going to get someone saying "but you can do that in Ruby by
doing X, instead of using Copland!" 'Tis true. However, Copland brings
together lots of interesting features in one place, and implements them
for you. Why not take advantage of an existing project, instead of
reinventing the wheel? :)

So, on to my use-case:

I'm (off-and-on) working on a personal finance manager, written in Ruby,
using ActiveRecord for the OR mapping and some to-be-determined
WEBrick-based front-end. This is one of the larger-scale apps I've
implemented (by myself--for work I fry much larger fish, but on a team).
For me, in this app, Copland fills the following niches:

1) Debugging. By using logging interceptors, Copland will automatically
log whenever a method of a service is invoked, what it returned, and
whether it threw an exception or not. This removes a lot of boilerplate
code from my app. What is more, the interceptors are "attached" to
services via configuration files, which means I can easily remove them
(or reattach them) without the possibility of accidentally deleting
crucial LOC. :) I've done it before... it hurts.

2) Delayed Instantiation. This is of dubious usefulness. I like it,
others may not. What it means is, a service is not instantiated until a
method is actually invoked on it. For services that are expensive to
instantiate, this can save some cycles, especially if the service your
request may not actually be used for some paths through your code. (I
should note: the delayed instantiation feature is configurable. You can
define services in such a way that they will always be instantiated
immediately, if you prefer.)

3) Dependency Injection. By putting most of my functionality in various
Copland services, I no longer have to explicitly instantiate
dependencies between these services in code. Instead, I just specify the
dependencies in the configuration files, and Copland "magically"
determines the dependencies at instantiation time. It will instantiate
dependant services, assign properties, etc, etc, all behind the
curtains. This may make some people nervous, but it cleans up your code
a lot more than you'd think. And clean code, is maintainable code.

Let me elaborate on #3 a bit more, since that's the one that took me the
longest to grasp. Specifically, take the "Server" service in my PFM. It
is simply a WEBrick server instance. In my configuration file, I specify
that when the service is instantiated, it should be magically "hooked
up" to a "Servlet" service. (The servlet is the WEBrick servlet that
implements the front-end for the app.) The servlet service, in turn, may
depend on other services, such as a "template" service for parsing and
rendering templated data.

Copland, in this case, would process the dependency graph, and determine
that it needs to first instantiate the "template" service, followed by
the "servlet" service. Then it would assign the "template" service to
some property of the servlet (as defined in the configuration file), or
perhaps pass the template service as a parameter to the servlet's
constructor. Once the servlet has been instantiated, Copland will
instantiate the server.

When delayed instantiation is thrown into the mix, this becomes a bit
muddier, since (for instance) the template service will not actually be
instantiated until the servlet service tries to render a template...and
the servlet service may not actually be instantiated until the server
service tries to pass a request to it... But from the developer's
perspective, it really doesn't matter (usually) when a service is
instantiated, so long as it is instantiated in time to do what it is
asked to do. And Copland makes sure that all happens.
Yes and thanks to Jamis for making such a nice Product even if it's way
over my head :)

You're welcome. :) Thanks for asking the question: the fact that it
needed to be asked just shows that there remain some pretty significant
holes in my documentation. *sigh* ;)

--
Jamis Buck
(e-mail address removed)
http://www.jamisbuck.org/jamis

ruby -ropenssl
-e'k="01234567";p((c,c.padding,c.iv,c.key=OpenSSL::Cipher::BF.new,0,k,k*2)[0].decrypt.update("1A81803C452C324619D319F980D5B84DBB45FC0FE2BAA045".scan(/../).map{|n|n.to_i(16).chr}.join))'
 
M

Michael Campbell

I use a little IOC in java, and for me it was one of those
unexplainable "ah hah!" moments. I didn't think I needed it (and in
truth, you don't /need/ it..., but you don't /need/ dynamicity or OO,
either), but when I figured it out it became darned useful.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top