Rework Catalyst component setup code
André Walker
Short description: This project aims to remove the current component loading mechanism in Catalyst, which is very poor and simple, and replace it using Bread::Board, an IoC (Inversion of Control) framework providing a more customizable setup of the components. This will allow more control of how each component is instantiated and loaded, while also simplifying Catalyst code.
Additional info: http://perl.andrewalker.net/
André Walker <andre@andrewalker.net>
Google ID: andrewalker
Rework Catalyst component setup code
Abstract
This project aims to remove the current component loading mechanism in Catalyst, which is very poor and simple, and replace it using Bread::Board, an IoC (Inversion of Control) framework providing a more customizable setup of the components. This will allow more control of how each component is instantiated and loaded, while also simplifying Catalyst code.
Benefits to the Perl/Open Source Community
- Users of the Catalyst framework, that is, application developers, will be able to define how components are instantiated, and their lifetime. That would remove the need for Catalyst::Component::InstancePerContext and Catalyst::Model::Adaptor, for example. Also, it would be possible to define components without the actual file existing, as implemented in CatalystX::DynamicComponent::ModelsFromConfig.
- Repetition in the application config will become unnecessary. It can be defined once, and then called as dependencies with Bread::Board.
- It would make it easier to separate application code from the specific Catalyst bits. That way, the code can be wired to Catalyst as a webapp just as easily as to a crontab script.
- Catalyst core developers will also benefit from my project, as Catalyst source will be simpler, having the components setup logic moved over to Bread::Board.
Deliverables
- a reworked component loading system for Catalyst, using Bread::Board;
- update Justin Hunter's work on Catalyst::Plugin::ConfigLoader and merge it into core;
- extension API, so that applications can override the default container;
- documentation on the new API;
- a comprehensive test suite, using the new features and making sure the back compatibility was maintained, both on ConfigLoader and on the framework extension API.
Project Details
Inversion of Control (IoC) is a programming principle in which the control of a given application flow is handed over to a framework. That way, the application doesn't have to deal with how each component is instantiated, or the order of creation.
In Catalyst, there is a simple mechanism for component loading, so that the controllers, models and views are created by the Catalyst framework and accessible by the context (usually referred as $c or $ctx) in $c->model, $c->view and $c->controller.
The problem is that the instantiation and loading of these components is very rigid, and does not allow much customization. Configuration is also very coupled to Catalyst; it's hard to reuse it outside of Catalyst.
For example, to make a model in Catalyst, the developer must create it in the MyApp::Model::* namespace, and make it inherit from Catalyst::Model, so that it is specific to Catalyst. Otherwise, it won't be instantiated and available in the context object. To overcome it, and have a model that can be reused, and tested outside of Catalyst, it's necessary for the model to inherit from Catalyst::Model::Adaptor. It loads the generic model, and ties it to Catalyst. To make the object last for only one request, the model has to inherit from Catalyst::Model::Factory::PerRequest. And to make it build a new instance at each call to $ctx->model(), Catalyst::Model::Factory. If the user want's his controllers to last for only one request, there's also a module enabling that, Catalyst::Component::InstancePerRequest.
So, in order to change the default behavior of the component loading mechanism, many hacks had to be created. The setup of the components is too inflexible, and requires a lot of work to do more than the default.
Bread::Board is an IoC framework created to solve this kind of issue. It handles the instantiation and configuring of each object, and the order it has to be created. It is a much more powerful implementation than the current loading mechanism in Catalyst, and it would allow a much more extended configuration of each component. Having a separate framework handling the IoC part would make Catalyst code simpler, and would make it much easier to implement new features in the IoC framework, as it is separated from the Catalyst specific bits.
Bread::Board is also focused in Dependency Injection. So each component can ask for what it needs, and Bread::Board just passes it over. Configuration becomes much easier, because it's no longer necessary to define a common object or data in multiple places; it can be just defined once, and then be called as dependencies.
The end result would be that the application code would be more customizable, and less tightly coupled to Catalyst. It could be easily reused for a crontab script, or ported to another kind of application, because the Catalyst specifics would be just a container wiring the components using Bread::Board.
Also, the IoC framework would render the modules mentioned above unnecessary. It will be possible to tie a component to Catalyst just by defining it in the container. The lifetime of the objects could be easily defined in the container too. The whole process would be a lot more customizable.
So the first step would be to change Catalyst::Plugin::ConfigLoader to use Bread::Board. Actually this has already been done, as this project has been tried on a previous Google Summer of Code by arcanez (Justin Hunter). I'll try and get the most use of what has been done. Then, ConfigLoader would be merged into core, and Catalyst would be reworked to load it's components using Bread::Board. Finally, an API would be created to extend the default container in Catalyst, so that each application could have a custom container, defining how their components will be loaded, changing the default lifetime, assign custom configuration to components, etc.
Obviously, tests would be created in each part of the process, for every new feature, and every change in the code.
Project Schedule
April 25 to May 23: Study Bread::Board more thoroughly, and start finding my way in Catalyst source code. Understand better how components are loaded, and how the current Catalyst component setup works, and how it should work using Bread::Board.
Week of...
- May 23: review and improve automated tests to ensure backwards compatibility by the end of the project
- May 30: study, review and update arcanez' Catalyst::Container
- June 6: further development and improvements on Catalyst::Container, and modify Catalyst's setup_components() to use it
- June 13: continue work on Catalyst::Container/setup_components()
- June 20: write tests for the new Container, and new setup_components()
- June 27: study arcanez work on Catalyst::Plugin::ConfigLoader; update possible API changes in Bread::Board; debug or make minor changes, if necessary
- July 4: begin the process of merging ConfigLoader into core
- July 11: finish merging ConfigLoader into core
- July 18: write tests for the new core ConfigLoader, ensuring new features work, and maintaining backward compatibility for applications trying to load it as a plugin.
- July 25: run the tests created on the first 2 weeks, along with Catalyst existing ones, to ensure backward compatibility was maintained. Run apps that work on current Catalyst, and ensure they still run with this project changes. Debug and correct possibly broken backward compatibility
- August 1: Document the new API
- August 8: More documentation
- August 15: Suggested "pencils down" date, by Google. If there were any delays in previous weeks, this week can be used to finish any remaining tasks.
References and Likely Mentors
I talked to dhoss at first, in February, asking for suggestions on what to study and focus, as I hadn't picked a project yet. Later on, when trying to understand better the need for this project, t0m and rafl, among others on IRC, like mst, arcanez and joel, were very helpful, pointing me to the right directions and explaining how it should be done. Lastly, edenc showed interest in the project, and offered to mentor me.
License
All code will be released in the same terms as Perl itself (Artistic + GPL)
Bio
I'm a Brazilian student, 19 years old. I took a three year IT course, focused on programming, during high-school. They didn't teach Perl, but in my final project, during the last year in that school, I created a photo sharing website using CGI::Application, DBIx::Class and Template Toolkit.
I wanted to take that course because I had already been experimenting with programming, and I was really liking it. I had created some web pages, first in static HTML, then PHP, and finally Perl. I read Beginning Perl, by Simon Cozens, when I was 13, and since then, it has been by far my favorite language.
I've also been working for the last year and a half (roughly), using mostly PHP, but also Perl and Catalyst whenever possible, making websites and internal systems for companies. In January I was accepted in a university course, in Computer Science.
I haven't contributed to any open source project yet, this will be my first time. Despite not being very experienced, I believe I can deliver this project because it will be my chance to work with something I actually like, and to give something back to the Perl community.
My tools are the terminal windows, a browser, vim (preferably with perl-support plugin), and git.
Eligibility
I am an enrolled student in a well-known Brazilian university, and I can provide paperwork upon request.
