Hi monks.
I have been browsing for a while now for modules to manage and test an application, and came up with a possible model for mine. Yet, I'm quite new in Perl and don't master its logic and principles: hence, I'd like to ask any of you for an enlighted opinion about what I came up to so far, if you please.
Background
I've got an existing piles of scripts and modules, made by Perl rookies for urgent needs and with no hope that would grow any further. But it did, and now, with my poor knowledge of Perl, I am to try to organize the existing in a proper architecture the best I can.
The existing application
The main traits of the existing code are as follows, running on Perl 5.10:
- we have 'processes' (coded as old plain classes), each of them designed to fulfill a particular task (then, one script per process is runned via cron to make that task executed)
- our processes have access to an 'application' (mix of global variables), to factorize certains variables and behaviours. Scripts were originally designed to be called upon CGI AND command-line, so for example a variable $nl globally provides a value for 'carriage return/new line', used in output strings (and equalling <br> or \n accordingly).
- our processes shares the code of 'services' (mix of global methods and old plain classes), which provides common functionnality (DB access, FTP access, Logger, etc.)
TO BE NOTED: the services have themselves the use of other services
- we have test classes (old plain classes) designed to test our processes with various input data. It's to be noted that one test class may have to run several processes to perform a complete test.
The problem that really arises now is the unability of mocking the services that the processes use during our tests. Also, different tested processes might need different mocked services (as a basic example: most tests will want to avoid actually sending emails and to use a mocked emailing service instead; but one test could need the actual emailing service to check the real sending/receiving of emails).
A target framework to criticize
I've checked things like App::Cmd and CLI::Framework, but those seems to be designed merely to help managing different command-lines, and don't provide much functionnality for stubbing and such.
I've been checking App::Framework which seems to be very complete, and with some tweaks could maybe fit my needs, especially by providing a Dependency Injection system via its Features and Personnalities. Here's the big picture I got to:
- MyCompany::App::Xxx
extends App:Framework, one App per process (defined above)
- MyCompany::App::Feature::Nominal::Xxx
Features implementing actual nominal behaviour (for 'Nominal' personnality) for my services (defined above)
- MyCompany::App::Feature::Test::Xxx
Features extending MyCompany::App::Feature::Nominal features, stubbing their methods for general test purposes (likely, a dry-run behaviour)
- MyCompany::App::Feature::SpecificTest::Xxx
Features extending MyCompany::App::Feature::Nominal features, stubbing some of their methods in accordance to specific test purposes
That way, I believe that:
- I could benefit of all the power of App::Framework (documentation, command-line help, etc.) for each processes of mine
- my services (Features) would be application-aware, and could use other services (Features) themselves
- a process (Application) could itself run other processes (Applications), with or without sharing services (Features) between Applications
- I could use Personnalities to run a process (Application) with different behaviours, that way:
MyCompany::App:Xxx->new( { specification => ':Nominal' } ); # to use my process in a nominal way
MyCompany::App:Xxx->new( { specification => ':Test' } ); # to use my process in a test situation
MyCompany::App:Xxx->new( { specification => ':SpecificTest' } ); # to use my process for a specific test
If I'm right, defining a Personnality will have App::Framework to load Features in specific folders first (hence the hierarchy I suggest).
Note: I couldn't find living examples of specifying the Personnality in the constructor, but documentation and source code seem to indicate that's the way I should call it.
For testing, I'm considering using Test::Class::Moose to structure my tests.
Questions
- does that model make sense, or is it far-fetched for some reasons?
- any suggestion for an alternative? maybe something exists which does what I aim to, and which I missed
- is there anything wrong in my reasoning? all critics gladly welcomed
Thanks for your time!