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

I want to build myself a web application in an object oriented manner.

I know how to build it without object orientation, but am very new to OO, so am unsure whether it should be all OO or only some, and how the objects should be related (or not!). I suppose my question is, "How should I architect it for OO?"

Here is the background:
-----------------------
The application has these basic requirements:

-security
(user validation, session tracking/validation, etc.)
(examined/used once per page hit)

-state
(persistence: session info, cached data)
(examined/used several-many times per page hit)

-control
(something has to be in control of program flow---it may be a single sript, 'main.cgi', or it may be several '<page>.cgi' scripts, depending on how the architecture works out)
(the big cheese, controls everything)

-backend
(methods to store and retrieve information in a database---I'm using DBI, DBD::mysql, mysql)
(examined/used one to several times per page hit)

-common page elements
(elements common to all pages{head, header, nav bars, footer}, generates html, determined in part by variables from the page-specific module(passed in this case)/object(passed or stored, not sure yet), as well as by data stored in the state object)
(used a few to several times per page hit)

-page-specific elements
(elements specific to a single page{the actual 'content'}, generates html from data retrieved from backend or from cached data in the state object)
(used once per page hit)

My current design calls for about 35 actual pages (all dynamic).
The pages fit into several categories or "main pages", such as:
"things related to the home page" (such as 'the home page', 'contact us' and 'about us'),
"things related to the help page" (such as 'the help page', 'support FAQ', 'support search', etc.), and so on.

This leads me to want to limit the number of "url" pages to just the "main pages": 'home', 'help', 'signup', etc., and to have the "sub pages" be specified in the urls by an "action" parameter: 'the home page', 'contact us', 'about us' actions for the "home" page, for example.

Some of my thoughts:
--------------------
For the pages, I can see a heirarchy like page::<main_page>::<sub_page> which seems perfect for object orientation. Therefore, I assume they should be object'ified'.

I can also see that I want a 'state' object so I can easily access its data as needed.

Since I'll be using CGI.pm, I'll also have a $cgi object, and a $dbh object for the database handle. I realize that these two are sort of 'helper' objects that my program will use as needed, and the same is true for my state object.

It is not as clear to me whether the security module should be an object since it will only be used once and not store any data. As an object, it would only have methods, so I suppose it would be a 'helper' class.

My architectural quandary:
--------------------------
In a non-object oriented approach, I understand how I could have either:
-a single program with modules for security, state, common_page_elements, <main_page>, <sub_page>, utilities (such as logging), etc.,
-or-
-one program per 'main page' with a specific module to handle the <sub_page> for each and a set of common modules for security, state, common_page_elements, etc.

When I try to grok this in OO terms, I can't quite figure out how to handle the second approach, "one program per main page". Specifically, if I want to have a 'sub_page' object inheriting from the '<main_page>' class, which in turn inherits from the 'page' class (and possibly inheriting from some generic base class), I don't understand how to have the 'main page' script handle both the program flow (I suppose I could have a 'control' module or object common to all the main pages) 'and' be an object itself!
Oh! I just had a thought (and yes, it was painful, but less so than previous thoughts!)...

..., what about this:
-<main_page>.pl is implemented as a "shell" that uses a control flow module/object (or perhaps a method in the 'page' class) 'and' <main_page>.pm contains the OO stuff to make a page::<main_page>::<sub_page> object (or, perhaps 'sub_page' becomes just a method of <main_page>? I had forgotten that a class is implemented in a package, which I generally associate with a module. Am I on the right track here or barking at the moon?

My request:
-----------
Any thoughts or suggestions on this? Particularly on which portions of the application you would use as classes/objects or not and how you would or would not relate the various classes to each other?

Any insights will be greatly appreciated by this OO newbie!

"Peace, love, and Perl...well, okay, mostly just Perl!" --me

Apprentice

Replies are listed 'Best First'.
•Re: Object oriented architecture question
by merlyn (Sage) on Mar 28, 2002 at 22:11 UTC
    I want to build myself a web application in an object oriented manner.
    Ahh yes. Why must we all do this, once? This is certainly in the list of "things reinvented by Perl programmers as a rite of passage", just like templating systems, CGI form parsers, command-line argument decoders, generic object attribute systems, object persistence, deep-copying algorithms, and the like.

    In case that's not clear... Please Look At The CPAN before you reinvent the wheel. Study prior art. If you don't like what you see, discuss it with the author or talk to us about it. But Please Don't Reinvent The Wheel needlessly.

    -- Randal L. Schwartz, Perl hacker

      Ahh yes. Why must we all do this, once? This is certainly in the list of "things reinvented by Perl programmers as a rite of passage", just like templating systems, CGI form parsers, command-line argument decoders, generic object attribute systems, object persistence, deep-copying algorithms, and the like. ... Please Don't Reinvent The Wheel needlessly.

      You're a Perl trainer and I think you should know better. Re-inventing wheels is a great way to learn a language. Besides, if no-one reinvented wheels, we would never get better modules. It's not always good to worship a module and never reconsider its entire design.

      CGI form parsers are a great way of learning how split works, and how hashes work.

      Building a simple templating system is a great introduction into the world of substitutions.

      Parsing @ARGV manually can really improve your splice skills.

      Home brew object attribute systems and object persistence creations are to many a good way of OO self-education.

      Deep-copying alghorithms teach how to use recursion, and/or how to avoid it.


      I think that stopping people from re-inventing the wheel stops people from learning.

      U28geW91IGNhbiBhbGwgcm90MTMgY
      W5kIHBhY2soKS4gQnV0IGRvIHlvdS
      ByZWNvZ25pc2UgQmFzZTY0IHdoZW4
      geW91IHNlZSBpdD8gIC0tIEp1ZXJk
      

        You're a Perl trainer and I think you should know better. Re-inventing wheels is a great way to learn a language. Besides, if no-one reinvented wheels, we would never get better modules. It's not always good to worship a module and never reconsider its entire design.
        You misquote me. I have no problem with people reinventing wheels once they've studied prior art. It's the people that don't even take time to see what the similar solutions are that waste both their time, and ours. Both during the creation, then maintaining variants of the same crappy code, instead of collaborating to build something much better on top of the prior discoveries.

        -- Randal L. Schwartz, Perl hacker

Re: Object oriented architecture question
by mAsterdam (Sexton) on Mar 29, 2002 at 01:44 UTC
    Hi there, apprentice (still?).

    Though I am just a bit late :-), I think I have a piece of sensible advice to help people with this often seen general approach. Here goes:

    No need to write everything down if your goals are not to ambitious, but if they are: write down the key-findings.

    1. Step one. Ask yourself: what should this application do. What specific value would somebody (conciously or without even noticing your contribution) get from using it. The requirements you state are non-functional: they describe the environment in which it should do its job, they describe structural aspect, but... what is the substance. In other words: you seem to know the big picture (and not yet the details, but the other posts allready give usefull hints on those) of what you are going to apply, but what are you going to apply all of this to. What should it - your application - do. Discuss this whith somebody who is supposed to be a candidate user.
    2. Step two. Detail the result from step one and ask yourself: Which duties, responsabilities are necesary to make this happen. From this you can get a rough idea which objects you are going to need.
    3. Step three. Work out several scenario's of how people are going to use your application. Confront this with the findings of the earlier steps.
    You can do this in your mind only or write it down too, but the point is: do it in your mind at least. Now you are ready to start designing your application and maybe hack a simplistic version - to find out what you may have missed in the above steps.

    HTH,

                Danny

Re: Object oriented architecture question
by perrin (Chancellor) on Mar 29, 2002 at 00:13 UTC
    First, take a look at the existing solutions. That will at least show you how other people thought about it.

    As for how to break up your application into classes, there are many ways. You can make multiple programs that subclass from one base class, or you can make a dispatcher (like CGI::Application). You may have to experiment a little.

Re: Object oriented architecture question
by fmogavero (Monk) on Mar 29, 2002 at 14:30 UTC
    Apprentice,

    The one thing that I would like to contribute is to keep in mind what an object is, as you design this.

    Generally, objects have two attributes to them:

  • They contain data
  • They do things
  • Desingning in OO is much simpler for me when I keep those two facts in mind.

    I hope that I have helped.

    fmogavero