Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Object-Orienting A Procedural Script

by Cody Pendant (Prior)
on Dec 08, 2002 at 20:18 UTC ( #218391=perlquestion: print w/ replies, xml ) Need Help??
Cody Pendant has asked for the wisdom of the Perl Monks concerning the following question:

I've voluteered to write a small script for a web community.

The details are pretty meaningless, but it's a small SQL database containing Quotes of the Day kind of thing.

All that's needed is to connect to an SQL DB, and edit, save, add and delete quotes via a web front end.

It would normally take me a couple of hours to fix the whole thing up, but the person I'm writing it for likes the code to be object-oriented.

I don't need details of exactly the code I'd use, but I have to admit I still don't really get the OO philosophy.

Here's what I'd probably do for a script like that:

  • create a script
  • feed it a "mode" via the form/query string every time like "if($mode eq 'edit'){ open the db, get record x, populate the fields }" or "if($mode eq 'save'){ open the db, put the field contents into record x}" and so on, the default mode being "none of the above" or start-up mode.
  • create the right forms and HTML code for each "mode".

What's the OO way to approach a simple task like that? I need to make everything into a function, essentially, and then call the functions as methods of the objects? So what are my objects?

As you can see, I've got a mental block about this -- I really see the whole thing as procedures, so I'm hoping my fellow monks can help me translate that into Objects with Methods.
--

($_='jjjuuusssttt annootthheer pppeeerrrlll haaaccckkeer')=~y/a-z//s;print;

Comment on Object-Orienting A Procedural Script
Download Code
Re: Object-Orienting A Procedural Script
by FamousLongAgo (Friar) on Dec 08, 2002 at 20:32 UTC
    If it's a small script, could you post the code? This might help avoid our falling off into the Land of Excessive Generality, and maybe demistify object-oriented programming for you a bit ( as opposed to an abstract discussion ).

Re: Object-Orienting A Procedural Script
by LTjake (Prior) on Dec 08, 2002 at 20:33 UTC
    Sounds like a perfect time to get familar with CGI::Application. It uses the concept of modes (run modes as they call them).

    here's a tutorial (redantigua.com) and another (perl.com).

    --
    "I don't intend for this to take on a political tone. I'm just here for the drugs." --Nancy Reagan
Re: Object-Orienting A Procedural Script
by pfaut (Priest) on Dec 08, 2002 at 20:38 UTC

    Break it up into pieces.

    • You can write one module that controls access to the database. This should have add, delete, update, and list methods.
    • The quotes themselves could be objects with methods to provide the quote itself, its author, etc.
    • The web interface could be modularized depending on how you intend to implement it and what webserver and application framework you're working with.

    Doing the database as a module allows you to easily substitute another implementation that saves to text files, a different database, db files, or whatever.

    Doing the quotes as an object allows you to write a command line utility that accesses the quotes.

      As with many such questions, the Camel book deals with what Object Oriented analysis and design is all about, but it doesn't always do so in a way that makes sense the first time you read it (for me, the Camel book always made more sense on the third re-read of a chapter).

      To answer your question about design (and using pfaut's response as a starting point), you need to change the way you think about your application.

      With procedural scripts, you tend to focus on verbs -- the user submits a form with values, this causes an update of a database, and a confirmation to be displayed back to the user.

      The OO approach is very different, since you are focusing on the nouns ('things' as I believe the Camel book refers to them) -- a quote is submitted by the user, this quote is written out as a row in the database... Uh, that example isn't sounding quite to coherent now that I've written it out, but the idea is there -- you focus on the data, not the process.

      So in your case, the key piece of data being handled by the script/database is the quote. This is the starting point for your application -- what are the attributes of the quote? Obviously, there's some pithy phrase, say "Who are you who are so wise in the ways of science?" But there's also an author (say, "Sir Bedevere"). Probably also a date for the quote (We'll use "1066"). And maybe some kind of additional attribution (e.g. "From The Search for the Holy Grail").

      Now you have some idea of the attributes of your quote object (using a concrete example is always, IMO, the easiest way to get started with an OO project), but you have to do a good deal more work before you can really say that your new class is ready. For instance, how long can the quote be? Anything between 0 and 250 (i.e. varchar), or longer (i.e. text)? Is the date required? How about the additional quote attribution?

      Once you have defined your object from the standpoint of its attributes (the data itself), you can now take a stab at defining an abstract class with methods to access that data (since the whole point of OO is not to manipulate the data directly from your script. There are as many ways to define a class as there are Perl programmers, but I've always liked some of the Java standards since they are easy for others to understand. In your case, you'll want something like this (this is pseudo code):

      sub getQuote { my $self = shift; return $self->{quote}; } sub setQuote { my $self = shift; my $quote = shift; unless (length($quote) < 255) { $self->{invalid} = 1 $self->{invalid_message} = "Quote is too long"; } } sub isValid { my $self = shift; return ! $self->{invalid}; }

      Here you can see some of how OO works -- I have getter and setter methods (the getQuote and setQuote) that assign and return arbitrary values. In Java these would be typed and I could only assign or retrieve a String value and not, say, an integer or a hash. I also have an 'is' method that returns a boolean value.

      The other thing that you may have noticed is that I don't throw any kind of error at the user of the object if they try to assign an invalid String using the setQuote method (in this case, a string longer than 255 characters, the length of the varchar field in a MySQL database). Instead, a flag is set that indicates whether or not the object is 'valid'. So, now one part of your application can set all of the attributes (using the incoming form data) without worrying about whether or not it's valid, because your object will figure that out for you.

      Java, just to see another way to do this, would probably throw an exception, which the user of the object could catch (basically a trap whereby a signal doesn't cause the program to abort), or allow to propagate all the way up through the program stack (to the point where it does cause the program to abort.

      From there, your program would then test the valid flag using the isValid method, and depending on the answer, it would either proceed to adding the new quote to the database, or printing the form back to the user and adding in the "invalid_message" to the page to tell the user why their quote wasn't accepted.

      What's really cool about OO programming, is that your Quote class doesn't just have to be used for users adding new quotes to the database, you can also use it for retrieving quotes -- the get_quote.cgi script would simply do a database lookup, instantiate the object using the right methods, and then pass it off to your printing subroutines.

      By creating this (and other) objects for use as part of your script, you are starting to isolate points of change -- another developer could come along and use the Quote object in another part of the site without having to know anything (well, theoretically at least) about what constitutes a valid quote (e.g. less than 255 characters). If you decided to change your validation (everyone wants to submit quotes longer than 255 characters, so I'm going to change the column-type to text) you don't have to change any of your processing logic, you would only change the one line of the Quote object.

      To take another example, again as suggested by pfaut, you could also create a Saver class that offers a single method save. And Saver is extended with two subclasses Saver::Database and Saver::File. Maybe to start off with it's easier to just save to a file -- your Saver::File's save method just writes out a new line to a specified file, end of story. But two months from now you switch to a database version, well the Saver::Database's save method opens and database connection, inserts a row, and returns. But none of this requires any significant changes to any of the code that interacts with the Saver class since any scripts are still just calling object->save() without caring where it's being saved to.

      This is why OO is a very powerful approach for application design (and especially for large applications where there are more than one or two developers working on the project) -- you use modules/classes/objects to represent logical groupings of data and then you can define the ways that others can interact with that data (i.e. I'm not going to give you a way to reset the valid flag in the Quote object) which (theoreticallt at least) protects them from the changes that you make, and you from the changes that they make.

      HTH

Re: Object-Orienting A Procedural Script
by Cody Pendant (Prior) on Dec 08, 2002 at 20:43 UTC
    Wow, thanks for all your help already.

    I can't post the code because there is no code. I could long ago have written something, but the "just writing something" approach is what I want to get away from.

    Thanks particularly to pfaut, that's exactly the kind of thing I wanted.
    --

    ($_='jjjuuusssttt annootthheer pppeeerrrlll haaaccckkeer')=~y/a-z//s;print;
Re: Object-Orienting A Procedural Script
by mbadolato (Hermit) on Dec 09, 2002 at 00:10 UTC
    but the person I'm writing it for likes the code to be object-oriented.

    My personal feeling is that's not their decision to make. OO is not the be-all, end-all. Using OO for the sake of it when it is not warranted is silly.

    The technical details of the implementation are up to you as the programmer. Use the right tool. If OO makes sense for the script, use it. Do what is simplest, and most maintainable, and makes sense for the application.

    I get into this at work all the time, where management wants to dictate a piece of the technology, where they are not knowledgeable. It needs to be left up to us, the programmers, to make the proper technical design decisions (within reason of course, that doesn't mean telling the company to switch from Linux to FreeBSD just because prefer it or whatever... there needs to be merit.)

Re: Object-Orienting A Procedural Script
by demerphq (Chancellor) on Dec 09, 2002 at 01:00 UTC
    Well it seems like you've gotten some good replies and some good analysis. So i wont add to that. What i will try to do however is help you break your mental block. (And OO fanatics and the like should take a deep breath when reading this. I intend to paint with broad strokes...)

    In simplest terms OO is about strongly binding a set of information and a set of methods of manipulating that information into a single entity, essentially abstracting it all away into a black box that knows how to do something useful when properly prodded.

    Now at this level OO is mostly useful for "sweeping the crumbs under the carpet". Lets say we are writing something that does something useful. Whatever :-). Along the way we decide that we want the output to be printed out in a certain way, perhaps wrapped adn maybe indented or something. And to keep track of the output we need a lot of "utility variables". You know things like the left position, and the right position, length on the current line, da de da... So after a while all this utility stuff becomes a pain. It clutters up your real code, its anoying to maintain etc. Putting as much as possible into subroutines helps, but if theres a lot of variables involved it alone wont help much. So sometimes its easiest just to grab all those variables, and the subs and turn them into a class. It knows how to create and initialize itself, it knows how to do whatever it is that its supposed to, all transparently from the point of view of the real program that you were writing. So now you have two advantages, first off if you ever need to have a pretty printer there is one available, in a box, for you to use. Second, if you decide, perhaps because you're now using it more places than one and you need extra functionality or efficiency, to completely rewrite the class all your other code will benfit, without having to be changed at all. (Assuming you maintain interface compatibility.) Eventually you might even upload it to CPAN. You never know.

    Theres a lot more to OO than this. Some of the ideas get pretty deep and im not the one to tell you about them, but the above is at least a simple way that you can benefit from OO more or less imediately. Use it to conceptually group related code and variables into single objects that are then asked to do their thing.

    A last word, people like merlyn and others have taken the time to write a number of excellent tutorials and documents on OO (the perl way :-) that are distributed with every perl (afaik, definately the AS ones) they are: perlboot perltoot perltootc perlobj perltie perlbot. And they probably should be read more or less in that order.

    HTH

    --- demerphq
    my friends call me, usually because I'm late....

Re: Object-Orienting A Procedural Script
by Cody Pendant (Prior) on Dec 09, 2002 at 04:10 UTC
    Again, thank you very much, all of you, for your input. Thanks jreades in particular for such a lengthy answer.

    To answer mbadolato, should it be object-oriented just because the project manager wants it that way?

    It is a community project on which many people have worked and many more people will work in the future, so that's one argument in favour.

    More to the point, I'll never have a better reason to attack a project like this: something I simultaneously know how to do off the top of my head and am completely baffled by, when looked at in OO terms.

    I'm a lot less baffled now.
    --

    ($_='jjjuuusssttt annootthheer pppeeerrrlll haaaccckkeer')=~y/a-z//s;print;

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://218391]
Approved by gjb
Front-paged by BrowserUk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (7)
As of 2014-08-29 20:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (288 votes), past polls