This post originated from an RSS feed registered with Ruby Buzz
by David Naseby.
Original Post: Inversion of Control
Feed Title: naseby + ruby + stuff
Feed URL: http://homepages.ihug.com.au/~naseby/rss.xml
Feed Description: Random wanderings through Ruby.
There has been a bit of ruby-talk devoted recently to the concept of Inversion of Control (IoC), implemented in Ruby in the Copland library by Jamis Buck. I keep hearing that Copland is well documented, and seems a thorough and interesting library, but noone really knows how to use it. What is this Inversion of control thing, and why would anyone use it? It seems a concept bred from Java, and like many things leaking from Java, may be more to get around Java’s inherent limitations and shackles than to solve a real problem. The concept has enough press from enough credible sources to warrant a serious peek.
IoC moves all of those dependencies out of the code and into configuration files, called (in Copland) package descriptors. These descriptors contain service definitions, configuration information, and so forth.
While I see why moving stuff out of code and into config is reasonably handy for compiled Java, I don’t really see it being useful in an interpreted language like Ruby. I must admit I find declarative Ruby config files flexible enough, and harder to screw up formatting than YAML (I have the same issue with FreeBase).
Fowler brings up plugins as a partial solution to the dependancy problems in his example, then goes on to describe an IoC framework as (more or less) a manager of plugins. Brings to mind Simon Strandgaards instant evocation of FreeBASE after hearing Jamis’ explanation of what IoC does… I think I may be using this study of Copland to get closer to understanding FreeBASE.
Some Practical Usage
Or not. I tried. I really did try. I’d convinced myself of the benefits of the possibility of changing any component without hacking about inside a class. Anyway. I was (and am) building a GUI for a html generator in FXRuby, and I was trying to use Copland to bring the bits together. I think I dived in too deeply to start with, as I couldn’t work out how to initialize all the components when they had slightly interleaving dependancies (the main window had to have a link to the components, and the components had to know their parent as part of initialisation in FXRuby).
On the bright side, knowledge of Copland gave me something to strive for in design. I took my own advice, and wrote (essentially) a declaritive main program, which just initialised all the bits and tied them together. Copland made me think about who should be responsible for initialisation, and it had some good conclusions.
I looked into FreeRIDE, to see how they initialised Fox components via FreeBase. An example:
So again, initialisation of child components is nicely decoupled from parents. When I was in the midst of writing the program though, seeing this turned me off using FreeBase – it just seemed I was making things too complex, trying to force me to remember where in the system something should live. My objections are currently, even as I type, dissolving, as I look at how stupid they appear and how indefensible this attitude seems. FreeBase occurs to me to be an enormously efficient way of handling the complexity of large systems. I think that the overhead of writing plugins is a deterrent on a program of the scale I was writing, and thats the only excuse I can come up with. Damnit, now I need to think again, because the program is starting to grow.
Blogs are for rambling. Hence this paragraph of doubt can follow the last paragraph (which, admittedly, was also of doubt, but in a different direction). Isn’t the FreeBase plugin system just a storehouse for a massive set of global variables? Its true that the plugins provide hooks for observers automatically, but doesn’t it just complicate dependancies? I can pull in any component that exists in the system if I have access to the plugin tree and a slot for the component. So there’s no way to say, on a cursory inspection (like in the initialize function), that component A requires component B to be built. I’m probably both wrong and thinking too much, and confusing myself at the same time. Must stop blogging this now. More later.