Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

Newbie OO module-structure question

by Anonymous Monk
on Apr 29, 2019 at 19:41 UTC ( [id://1233154] : perlquestion . print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I'm new to object-oriented programming in Perl; I've used OO modules, of course, but for my own code I've never had to do anything relying on inheritance or anything like that.

I'm about to convert a very large procedural program to Moose, but even here, I'm not doing it so that I can override different methods.

This program has five main tasks in it, each one over 1000 lines long; right now, everything's just one huge file, with comment lines saying "Task #3: archive old files" or whatever to divide it up. For organizational purposes, I'd like to break this up into separate modules, so that my main package would be DoSomething and then I'd have DoSomething::Task1, DoSomething::Task2, etc. The main DoSomething module will have all the core code (setting up logging, reading config, etc.), and then would just call the different tasks as necessary. The end user would just write a small script invoking this, and wouldn't have to know that there are all these different submodules.

Is this the right way to set this up? How would the DoSomething module call routines in the submodules? Is there some other way I should be accomplishing this? Again, I'm not doing this for inheritance or overriding purposes, I'm doing it so that I have five separate thousand-line modules instead of one five-thousand-line mess.

Replies are listed 'Best First'.
Re: Newbie OO module-structure question
by eyepopslikeamosquito (Archbishop) on Apr 29, 2019 at 21:08 UTC
Re: Newbie OO module-structure question
by choroba (Cardinal) on Apr 29, 2019 at 21:30 UTC
    You didn't provide enough information for a detailed answer. We don't know how the tasks depend on each other, what parts of the code are common to the tasks, etc. But here is a short example (using Moo) that just stores the tasks in the "tasks" attribute and runs them one by one. All the tasks share a role that says they have a name and must be runnable. A possible next step might be the introduction of the Factory pattern to build the tasks...

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

      ... but can you introspect the tasks with My::Task role, in order to DRY°?


      In other words, is it possible to loop over all classes which have a role instead of hardcoding it at the end?

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      °) don't repeat yourself


      fixed auto-correction: s/introspective/introspect/

        I don't see any loop over classes. There's a loop over objects.

        If you don't like the constructors of the particular TaskN objects, that's what I'd solve with a factory.

        map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
        " order to DRY...have a role instead of hardcoding...

        Insisting so much on DRY is sometimes remote from everyday life. Because RY is human nature. Why? Remember how often your parents, siblings, aunts, uncles, spouses, colleagues, fellow monks etc. told you to become a better person. In the long run they have been successful. Sometimes WET is better. Or faster - as you like.

        «The Crux of the Biscuit is the Apostrophe»

        perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Re: Newbie OO module-structure question
by pwagyi (Monk) on Apr 30, 2019 at 04:07 UTC

    First you've to think if OO is suitable for your problem domain. Could modularization (even plain functions) simplify? (ease to refactor, isolated, testability).

    I am saying this because I have seen people writing messier OO code while attempting to refactor one big monolith code.

Re: Newbie OO module-structure question
by tobyink (Canon) on Apr 30, 2019 at 17:35 UTC

    If you're thinking in terms of breaking it into tasks with a main module that has the core code, then you've probably already taken a wrong turn at OO. Tasks are verbs. Object-oriented code is structured around nouns.

    So rather than having a module for archiving old files, you might have a class for representing files, and one of the methods it provided might be archive.

      OP here. This, and BillKSmith's comment below, certainly makes sense, but in both cases, I'm not sure what the right approach would then be. That is, it seems to me that it's not unreasonable to have core code (as above, e.g. config, database connections, logging, etc.) in one central place, and other things in other places. But if I'm treating OO things as nouns, refactoring this code along these lines won't solve my (perceived) problem, which is that the code is really large.

      That is, if this program does deal with files (not exactly the case, but it works for this purpose), having a class representing files, and then methods for archive, delete, convert, etc., will still leave me a five-thousand line class with five methods in it, instead of a five-thousand line program with five sections.

      Am I worrying too much about the size of the monolithic block? Would five methods of this sort (which will, of course, have a number of accessory or utility sub-methods) be cleaner? It seems to me that it wouldn't, but....

Re: Newbie OO module-structure question
by BillKSmith (Monsignor) on Apr 30, 2019 at 20:55 UTC
    The time spent in dividing a large program into modules will pay dividends in future maintenance. Converting it to OO is such a big job that I doubt that the benefit will ever justify the cost. The module names that you propose suggest that you are not prepared to fully adopt the OO model. Merely converting to perl's OO syntax is unlikely to have any advantage.