views:

105

answers:

7

Hi there. I have a more or less large Perl script of ~ 1000 lines. The script accepts a few arguments and it runs straight forward. No modules, no functions. The script could be divided into three parts, initialization part, arguments parsing part and work part, but I don't know how to do that. Everything must be kept in a single file. Please, can anyone give me instructions/advice how to structure my Perl script?

Thanks.

+2  A: 

1000 lines and no functions? why not? this is a vague question.

recursive9
there are no functions cuz the script runs straight-forward. It runs a few ffmpeg commands and parses it's output. The commands are almost entirely different, so I didn't thought about putting things in functions.
Vincent
Vincent, just because it's a straight linear run with little multiple use doesn't mean functions lack value. Breaking a program into functions also breaks it into easily understood chunks that do one thing. This makes it easier to understand, design, and most importantly, maintain.
HerbN
and test. don't forget test.
Carl Manaster
@Carl: oh yeah, and test. When I first learned of unit testing the value of functions was reinforce more than it had been since the 80s.
HerbN
+2  A: 

You could break each section into a separate function, and then have a function that runs through each of these functions in the correct order called 'run()' or something similar. This would allow you to break up the program into more mangeable chunks.

p.s. man I think I used the word function too many times in this answer!

Seidr
This seems to be a good idea, why not packaging everything in a module? Can I then do something like the C main()-function in perl? that this is the entry-point where the script starts? Thanks.
Vincent
If you wanted to re-use functionality provided in the script then yes, segmenting the code into a module with appropriately named functions would be a good idea.
Seidr
+2  A: 

Have you refactored at all? At 1000 lines I'd suspect to see some code that could be broken down into functions internal to the script.

Well, if you have three separate sections that's the logical choice.

You could make each one into a function and then have a simple linear control at the top:

 my $var1, $var2, $var3;

   $var1 = init();
   $var2 = parseInput();
   $doWork();

   sub init() {
      some code here
   }

   sub parseInput() {
      some code here
   }

   sub doWork() {
      some code here
   }

The big issue is you're going to be using globals a lot. I'd build them into a structure or two. I would also expect to see the big three broken down into functions themselves. Back in the 80s when the big thing I was learning was structured programming (the best design here I think) the rule of thumb was a function should fit on roughly one screen or less.

HerbN
+2  A: 

If you can see logical parts of your script, you should definitely abstract them into functions. Having a single script of over 1000 lines, and not breaking it up into whatever abstraction units your language provides (functions, classes, etc.) is a very bad idea. Maintaining your script, i. e. adding features and fixing bugs, will be a nightmare.

I strongly suggest you read the book Clean Code by Robert C. Martin. It uses Java for examples, but the ideas are applicable to any language. The one that is most relevant here is "Make your functions small. Then make them smaller."

Dima
The problem is not, that I'm not aware of functions/classes at all. I've created programs with functions/classes. When I created the script, I could not imagine of any possible structure, because the program does everything step by step and actually, I didn't care much about it.
Vincent
But you yourself have outlined the parts: initialization, argument parsing, and work. As soon as you realize that those are logical parts, you should refactor your code, and wrap them into functions. I am sure, if you look hard enough, you will see the logical parts in these functions too, especially in the "work" function. Once you do that, next time you need to make a change to your script, you will be able to easily see the structure, and focus on the relevant part.
Dima
+3  A: 

Most people would typically answer something like "a subroutine should do one thing" and "a subroutine should only take up one page in your editor". You can try to keep these things in mind when you refactor your code.

Try to identify parts of your code that can be split off into logical sections. You've started this process by spotting 'initialization', 'argument parsing', and 'work'. See if there are some sub-sections within that that can be pruned off into other subroutines.

Also, why do you not use any modules? One that springs to mind is Getopt::Long, which is a core module, so you won't have to install it manually. It will handle all of your argument parsing, and by using it you will probably avoid bugs and could shorten your code to make it more maintainable. By using standard modules like this, you not only (hopefully!) reduce the number of bugs in your code, you make it easier for other Perl programmers to understand.

CanSpice
I used few modules, POSIX and File::Basename. I didn't use Getopt::Long, because I have implemented my own argument parsing which works just fine.
Vincent
+7  A: 

You ask for advice on how to refactor your script, but you don't appear to understand why to refactor it. Without the why, the how isn't going to do you much good. And with the why, the how may fall out quite naturally.

If your script is working perfectly and needs no modification and all you'll ever do with it is run it, then you probably don't have a reason to refactor it - and I say that from the perspective of despising long routines. But...

If something's wrong with it

If you are trying to find a bug in your 1,000-line program, you have some hard work ahead of you. The problem could be anywhere. Break it up into smaller pieces so that you can verify the input and output at different stages - ideally, write tests for the smaller pieces. Fine-grained unit tests will tell you what isn't working, the nature of the error, and where the error exists.

If you need to modify it

If you need to change the script to - say - accommodate a new graphics format, or take advantage of multiple processors, or record its activities to a log - you will find it easier to extend if the program elements that need revision or extension are better isolated.

If you're trying to explain it to someone else, or show it off

You will find it much easier to convey the ideas in your script to another developer if the ideas are broken out into discrete methods.

So, there are some reasons why you might choose to refactor. If any of them apply, refactor accordingly; the how will drop out naturally. Extract Method may be your best friend.

Carl Manaster
Excellent explanation!
Dima
+1 Another reason to refactor that might apply to the OP: **it could be a great learning opportunity**.
FM
A: 

You could look at search.cpan.org, maybe some Perl module suits your needs. For example there is a CGI::Application

Alexander Farber