Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Why CGI::Application?

by sdbarker (Sexton)
on Jan 13, 2004 at 11:50 UTC ( [id://320933]=perlquestion: print w/replies, xml ) Need Help??

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

I'm not sure if I'm missing something or not, but I don't see the point behind CGI::Application. I've read the tutorial at perl.com, and I still find the point eluding me.

It seems like some of the biggest points are:

1) Code Reusability.
- Solved by making your code better in the first place, more modular.

2) Most CGI applications are big if/else blocks.
- Solved by the above as well. And isn't using C::A Just kinda like moving all of your if/else blocks into one spot, while adding yet another layer of abstraction to get to them?

3) Portability.
- Again, just code better.

What am I missing? Why add what seems like another layer of complexity and confusion, for no real benefit (no offense inteded to the author).

It seems as though all of the benefits of C::A are things that can be accomplished by simply adjusting your coding style; making more blocks of code into subroutines, etc. You'll still have the big block of C::A setup stuff at the top of your script; why not have an if/else that calls different subroutines.

-Scott

Replies are listed 'Best First'.
Re: Why CGI::Application?
by dragonchild (Archbishop) on Jan 13, 2004 at 13:10 UTC
    Being someone who just implemented his first CGI::Application code yesterday (replacing a current app), let me tell you what C::A does for you.
    1. You are now explicitly implementing portions of your website as a state machine. This aids documentation and maintainability by naming your if-else blocks.
    2. The state machine control-code is now done for you.
    3. You are more easily implementing MVC, with C::A as your Controller code.
    4. It is very nice to see the code for many related pages all in one place.
    5. All your code now easily shares a print() method. (I have mine in my C::A superclass.) This allows for things like:
      sub some_state { my $self = shift; # do some stuff here to populate %template_params return $self->print( $display_mode, $template_name, %template_params, ); }
    6. Handling redirects and save-type pages is done for you. For an excellent example of this, check out http://www.mail-archive.com/cgiapp@lists.erlbaum.net/msg00849.html.
    7. You can accidentally turn your cgi-scripts into Apache handlers. (Well, it's a little more complicated than that, but it definitely gets you 90% of the way there.)

    Also, you might be confusing something I was having issues with, at first. I originally thought I needed to implement my entire application as one monolithic C::A app. But, a friend of mine showed me what his company did. They have some 20 different C::A's that all work together, passing responsability off as necessary. They have one main C::A, which handles logging and the homepage. Then, every major subsystem (reports, user admin, preferences, etc) have their own C::A. If something is complicated, create another C::A inside that. His rule of thumb was 10-12 states, at most. More than that and you should look at breaking it up into two C::A's (if possible). Also, every one of your C::A's inherits from some abstract superclass that inherits from C::A, which implements things like how to connect to the DB, what CGI class to use, how to display, and other basic functionality.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

      I'm not sure how splitting into two or more C::A's would work (e.g. how would two C::A's interact?) - could you post a simple example of how to do it?
        Sure. I'll post a condensation of what I'm working on right now. The plan is this - you have a main C::A, where you handle logging in, the home page, and logging out. You also have a C::A that handles how reporting works. Remember - some of your users might not have the authority to run reports, so it's easier to just disallow the whole C::A than it is to disallow certain run-modes.

        Ok, so far so good. But, we don't have another C::A yet. I personally do my navigation through some header that I've TMPL_INCLUDE'd into all the relevant templates. (All of them, except login and logout.) The header basically has

        HOME => main.cgi?mode=home REPORTS => reports.cgi LOGOUT => main.cgi?mode=logout

        But, you wanted to see the other C::A. Here ya go:

        That's it. No handling of cookies, no handling of nothing. In fact, there's absolutely no way the cookies are NOT going to be handled. You can't forget to add it to the top. You can't forget to do standard processing. It's quite ... nice to be able to forget that you have it cause it just works.

        ------
        We are the carpenters and bricklayers of the Information Age.

        Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: Why CGI::Application?
by rob_au (Abbot) on Jan 13, 2004 at 12:00 UTC
    From the review which I wrote for CGI::Application on this site here ...

    Why use CGI::Application?

    The CGI::Application module implements this object-orientated framework within which to build your application by creating a super-class within which specific 'run-modes' can be defined. Each run-mode can be correlated to a particular stage of the HTML/CGI user interface. Furthermore, the CGI::Application module implements methods to address the CGI.pm and HTML::Template modules, facilitating powerful methods by which to build extensible and portable web applications - It is obvious that the module author, Jesse Erlbaum (jesse at vm dot com), has put a lot of work into the development and writing of this module.

    This module allows you to do away with ugly code through the combination of CGI.pm, HTML::Template and methods provided by CGI::Application to implement persistent variables across execution states.

    Additionally, and most importantly, by providing a framework in which CGI parameter parsing, template handling and session storage can be seamlessly incorporated, CGI::Application allows developers to focus on business logic rather than framework implementation details.

     

    perl -le "print unpack'N', pack'B32', '00000000000000000000001010101010'"

      The web page for C:A tells us that it is better than Mason because Mason creates lots of files.

      The author of that text hasn't used Mason very much. If you wanted with Mason you could put all your components in one file using the inline component block - or you could just use one component and wite a great big MVC framework if you wanted to.

      I agree 100% with the author of the original comment. The problem with a lightweight MVC framework like C:A is: a) It often adds an extra layer (to be learned and more code to load) for very little obvious benefit. E.g. to use JSON there is a JSON plugin, but this is not much more than a wrapper around the JSON module. In as much as it is more it provides a mechanism for intercepting the output in your C:A application with a hook. My problem with this is if I wanted this kind of functionality I'd rather code it myself than learn how someone else has done it.

      b) Because it is lightweight your application will end up as a hybrid beteen C:A and your own systems e.g. I've had to develop a little component system because it doesn't really do components, being stuck in this Web 1 way of thinking where the whole page is served each time. But this is messy. There are two ways out of this: either use a framework which really does cover everything, like PHP's Symfony (if that's your bag), or don't use a framework at all.

      The MVC model is fine if appropriate: but most developers should have the discipline to separate out model view and controller without being put into a strait-jacket.

      Justin
Re: Why CGI::Application?
by derby (Abbot) on Jan 13, 2004 at 13:32 UTC
    It seems as though all of the benefits of C::A are things that can be accomplished by simply adjusting your coding style; making more blocks of code into subroutines, etc.

    Sure that will work.

    Hey but wait, darnit, I want to use CGI::Simple instead of CGI ... better write that hook.

    Hey but wait, darnit, I want to do some post-processing after the HTML is sent to the client ... better write that hook.

    Hey but wait, darnit, I need to get into the process after reading the HTTP stream but before I do my real app stuff ... better write that hook.

    Hey but wait, darnit, I need a hook after generating content but before sending the headers ... better write that hook.

    Hey but wait, darnit, I need a hook to modify the headers ...

    Hey but wait, darnit, I need a hook to override what step is being executed ...

    Hey but wait ...

    CGI::Application gives all this to me and it's been developed, reviewed and used by a slew of talented and qualified people. You see the authors have given you a framework that makes the easy things easy and the hard things possible. Sure you could do that yourself, but you could also write CGI.pm yourself or for that matter your own interpreter.

    To me, CGI::Application did not add a layer of complexity and confusion but actually cleared up a lot of issues when trying to build MVC apps. I always knew templates were the VIEW and application specific modules were the MODEL ... it was that damn CONTROLLER that became a big hairy beast ... well CGI::Application really cleaned up my thought process when it came to MVC. So sure I could have spent weeks, months, years creating my own Application framework ... one that's easy to use for the straightforward cases but also allows me to hook in and change things on the fly or I could spend 15 minutes downloading CGI::Application.

    So I say well done Jesse (and all the contributors).

    -derby

Re: Why CGI::Application?
by jeffa (Bishop) on Jan 13, 2004 at 17:03 UTC

    Maybe if you understood where C::A came from, you might understand why we use it.

    In the beginning there was the very large if elsif ... else structure of blocks.

    It worked, and it was good ... but not for long.

    Then came the dispatch table of subroutine references:

    my %dispatch = map {$_ => eval {\&$_}} qw(login logout view_list etc); my $command = $q->param('cm'); # validate $command and possibly set login as default value # now call the correct subroutine to handle this "page" $dispatch{$command}->($q); sub login { my $q = shift; ... } ...
    and this was much better. But it became tedious to type the same stuff over and over again.

    Then came CGI::Application which handles this and so much more. It is not easy to get the hang of, however. For what it is worth, i didn't get it the first time i tried and i could code a dispatch table solution in my sleep! :)

    One last comment about one of your comments: "It seems as though all of the benefits of C::A are things that can be accomplished by simply adjusting your coding style; making more blocks of code into subroutines, etc."

    Do not mistake what you have just said with being against C::A. Instead, C::A force you to abstract more than the if-elsif-else brute force solution. But, as my uncle says ... brute force is still good. It's easier to understand how to write. But, i say it turns into spaghetti eventually.

    In the end, i think it's all about where you put stuff. Energy cannot be created or destroyed, and whereas code can be condensed and refactored, you still end up with code and i think the best decisions are the ones that make your code easier to maintain and easier to extend in the future. It's all about how quickly you want to solve the problem and how much the future matters to the project.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      In the end, i think it's all about where you put stuff. Energy cannot be created or destroyed, and whereas code can be condensed and refactored, you still end up with code and i think the best decisions are the ones that make your code easier to maintain and easier to extend in the future. It's all about how quickly you want to solve the problem and how much the future matters to the project.
      Well said, rarely on a project do you have more time then you need, and never should you be unconcerned about the future state of your code.
Re: Why CGI::Application?
by stevecomrie (Beadle) on Jan 13, 2004 at 16:30 UTC
    I've been a long time contributor and user of C::A and have written numerous articles & tutorials on using it that are posted on the C::A wiki (linked to in a previous post)

    If this is what you consider a big block of C::A setup stuff, then maybe you're right.

    sub setup { # grab arguments my $self = shift; # set startup run-modes $self->run_modes ( # my site run modes 'generate' => 'generate_statistics', 'overview' => 'display_default_overview', ); }
    But considering all I had to do to start building a new application was create my Application.pm file, inherit from my C::A Super Class module, and fill it with that bit code, I'd have to disagree with you.

    By inheriting from my own Super Class built on C::A, those 3 quick steps give me access to cgi query params, session management, login authorization, conf file access, template file access, database connection & querying, logic to define which users have access to which "if/else" or "run-mode" blocks, MIME headers, cookie access, error handling and numerous other features.

    What you're missing is that I can now concentrate on building the actual application logic at hand instead of worrying about where to store session information, connecting to the database, setting a cookie properly, loading an HTML::Template or T::T file, etc.

    By relying on a Super Class module you can build stand-alone application and large groups of applications that all use the same code base, thus you save yourself time, energy and headaches.

    Furthermore, by relying on compartmentalized code for basic operations you are safe to change those compartments at the Super Class level and know that all your applications will continue to run as they did before.

    Sure it's all something you could roll on your own or build as you go. Yes it's something that you could acomplish on your own by making your code better and more modular in the first place.

    All C::A is is a framework for building better applications faster. Maybe it's not the be-all-end-all of frameworks for build CGI app's but it's one of the best ones available right now, and it's supported by a large group of programmers like my self that try very hard to make sure it makes the easy things easy and the difficult things possible.

    I mean, after all .. we could all be programming in binary, why add another layer of complexity and confusion like PERL to the equation.
Re: Why CGI::Application?
by Willard B. Trophy (Hermit) on Jan 13, 2004 at 15:01 UTC
    The biggest win about CGI::Application for me is that I can develop locally under good old slow CGI on my dev box, and know that it will run under mod_perl on the production server with no changes.

    With mod_perl and Apache::DBI (connection cacheing) I can get application response times so good I didn't think they were possible. The server load is way down too.

    If that were all, it would be enough, but you also get HTML::Template for free, and lots of handy prebuilt solution modules that might just do exactly what you want.

    --
    bowling trophy thieves, die!

Re: Why CGI::Application?
by perrin (Chancellor) on Jan 13, 2004 at 16:31 UTC
    You're right, it doesn't do all that much ultimately. If you already understand the issues that its dealing with, you don't really need it. However, it can be useful if you have a team of people sharing code, since it ensures that everyone's CGI apps will be built with the same structure.
      ++ Perrin. I concur. C:A doesn't really do all that much, but the structure it offers is much much much much better then coding a spaghetti mess of ifs to run a webapp. So C:A provides a structure which does a great deal, even if the code itself is simple and small.

      Once upon a time I wrote my own wrapper for building CGI apps, then later discovered I was heading down the very same path as C:A (only not as well.)

      I'll use the space here to recommend Mason. It works very nicely with mod_perl and it is both powerful and easy. (And AMZN uses it on their core site, so that's a powerful endorsement.)

      An example: deep inside a web page, within Mason, I can detect the user wanted the report in Excel, vs. HTML. Cool. Clear the buffer, send the right content type header, pump out the Excel data, and then turn off Mason processing -- didn't have to worry if I had sent headers or page content already, runmodes, etc.

      And the Mason notion of components makes me feel like I am playing with Legos -- snap snap a new web page. Nope, move that function off this page to that page, sure. Snap, snap. Easy.

      Could just be the "honeymoon" infatuation with a new (for me) technology, but I'm currently a strong advocate of H:M.

      rkg

        I'm curious, never having used Mason, how it's easier to use than HTML::Template + Excel::Template + PDF::Template ... They all use the same data structure and, assuming you have one function that all printing goes through, you do the dispatch there. Or, am I missing something?

        ------
        We are the carpenters and bricklayers of the Information Age.

        Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

        I concur. C:A doesn't really do all that much, but the structure it offers is much much much much better then coding a spaghetti mess of ifs to run a webapp.

        C::A may provide a way of avoiding spaghetti. So does thinking before touching the keyboard. A big if or switch or anything else does not automatically mean spaghetti. Spaghetti is a symptom of bad programming practices, and I don't care what modules you use, a bad programmer will always write nasty code.

        Now that's just super complicating it. Mason has it's place, but this is not it.
Re: Why CGI::Application?
by zby (Vicar) on Jan 13, 2004 at 14:09 UTC
    I have just recently started to explore C::A as well. Here is a CGI::Application wiki by the way.

    The question that intrigues me is why there is another dispatch mechanism build using the run_modes method. Why the object dispatch is not enough? In what circumstances another redirection layer is needed?

    Update: run_modes not run_mode.

    Update: For security reasons there should be a list of methods that can be called from the web. That's unevitable, at least untill perl has public and private methods.

      If I'm following your question correctly, the payoff of the run_modes method is so you can have multiple mappings of modes to methods. It's odd, but not unheard of, to have two differently named modes invoke the same method (think AUTOLOAD).

      -derby

        Ah - I'd rather do:
        sub mode1{ my $self = shift; return $self->mode2(); }
        Is it so common place that the shorcut justifies the overhead of the additional run mode hash?
Re: Why CGI::Application?
by weierophinney (Pilgrim) on May 07, 2004 at 00:29 UTC
    Like perl, CGI::Application makes the impossible things possible. It also abstracts CGI applications in such a way that you can focus on the actual programming at hand rather than how you're going to display things.

    Let's say I have a simple application that should do the following:

    • Display a paginated list of my data
    • Allow me to search my data, and return the results in a paginated list
    • All paginated lists of data, filtered by a search or not, should be sortable by column
    • Allow me to view a single record at a time
    • Allow me to edit any given record
    • Allow me to delete any given record
    • Allow me to add new records
    How do I go about doing this? In a traditional if-then-else way, this gets pretty hairy very fast. Even with dispatch tables, keeping track of all the parameters can be a bear. Then, on top of it all, there's the display issues. And, if you think about it, you're going to need sessions to keep track of the sorting and filtering (particularly if you want to return to the previously viewed list after an edit or record view).

    How do I tie it all together?

    What CGI::Application does is allow me to focus on the issue at hand: how do I retrieve my content? how do I determine what content to retrieve? Now, I can focus on one aspect at a time - one method per action, and calling related methods when necessary. I leave my display issues to templates, and simply assign the data I pull to the templates. I have session handling kept in a single superclass, along with my database connections. All I have to do is get my content; the rest is taken care of.

    The CGI::App framework is setup in such a way that code reuse becomes not only easy, but the only way to effectively program. It enforces consistency, because you could be inheriting from any given module in order to extend it for further applications; because they all share the same framework, you don't have to worry about collisions in terminology when you mix and match.

    On top of that, it allows you to setup an easy inheritance framework such that you can have multiple application modules inheriting from the same parent so that the same look and feel are inherited; this means that all of your site's applications can easily share the same look and feel, as well as have a common underlying structure.

    And, if you want to, you can port your entire application to another site simply by changing the parameters you pass to it through the instatiation script -- new data stores, different group of templates, etc. Your reusability now extends not just to the current site, but to many sites.

    Sure, you can "adjust your coding style" so that code is more reusable; what CGI::Application does is give you a ready-made, rigorously tested, framework for reusable code. Personally, I've had enough of hand-made frameworks; I want something that not only I can understand, but many other people can understand and have used.

Re: Why CGI::Application?
by DrHyde (Prior) on Jan 13, 2004 at 13:24 UTC
    I tried to use it recently for a big app at work. All the *real* work is packaged up in modules, but for the webby front-end I thought CGI::Application would help. It didn't. All it did was irritate me, so before I got too far, I threw it away, and turned my code into one really big if ... elsif ... elsif ... else. It works. It makes sense.

    And it's only big because each block consists of stitching together a big data structure by calling a load of object methods (and these are BIG structures, for complex pages) which is then passed to TT. There's not all that many statements in there.

      All it did was irritate me

      How? Did it make your eyes water? Your scalp itch? A burning sensation in an area not discussed amongst mixed company?

      Look, I'm not much into promoting or even believing in any silver bullet theories but I must say CGI::Application has been a boon to my development. As another poster stated, it started me thinking about my webapps as state machines and that has been a good thing. Maybe your apps don't need that, if you have a simple CGI that does one thing only - then probably not. But once you get into a multi-step, multi-form, webapp, CGI::Application is definetly a plus.

      If you have the time or inclination, please write up what irritated you. Give us examples of how your approach is better ... are you sure it wasn't the small learing curve for CGI::Application that just got in the way of you delivering the product.

      -derby

        As another poster stated, it started me thinking about my webapps as state machines and that has been a good thing.

        It most certainly is a good thing!

        Maybe your apps don't need that, if you have a simple CGI that does one thing only - then probably not. But once you get into a multi-step, multi-form, webapp, CGI::Application is definetly a plus.

        CGI::Application makes it no easier to write multi-form applications as far as I can tell. All my form submissions have an action=foo parameter. The various foos have sensible names and simply make the big if ... elsif ... else block call the appropriately named subroutine. This is exactly the same as CGI::Application's "run modes"

        If you have the time or inclination, please write up what irritated you.

        It irritates me because it provides nothing useful, while wrapping itself up in grandiose language about how it will make the web application world a better place.

        Give us examples of how your approach is better ...

        I can't give you the code, but I consider it to be better because it has fewer dependencies while requiring me to do just as much work, and because it's one less thing for someone else to have to learn before maintaining my code.

        are you sure it wasn't the small learing curve for CGI::Application that just got in the way of you delivering the product.

        What learning curve? CGI::Application is far simpler than some of the other modules I'm using.

        I should write this up as a review for cpanratings.

Re: Why CGI::Application?
by Anonymous Monk on Jan 14, 2004 at 09:32 UTC
    Thanks a ton for all of the answers, everybody. I'll definitely take another look at this, and see what I can come up with.

    Don't take this as an invitation to stop giving feedback, though. :-P

    -Scott
Re: Why CGI::Application?
by schweini (Friar) on Jan 18, 2004 at 02:02 UTC
    hey! cool! finally a discussion about C::A with a lot of good arguments (mod_perl reusability, etc.)
    but a lot of monks pointed out that the if/elsif constructs (that i use a lot) are inherently flawed, and i'd just like to take advantage and ask why?
    assuming one doesn't use any advanced features of C::A, does one actually gain a lot by using it? is calling a sub noticably faster than letting the perl interpreter run through all the conditions? why exactly does C::A increase code mainainabilty?

    to explain my situation: i bundle up anything related in seperate .pl files, which all do global start-up scripts (for session-handling, db-connections, etc.), and all 'interesting' and reusable subs are inside various modules that get used where appropiate.
    i'm just wondering whether i'd gain a lot by switching to C::A (which, AFAIK, wouldn't be tooooo hard), because of the tons of positive comments about it...
      A few answers. Let's say you have a reasonably complex application. Let's say you have, oh, 100 unique pages. That's right about middle-sized (in my experience). Let's say they're broken up in 4-7 different functional areas, with some overlap (searching functionality, etc), but each has different needs (different shared functions, validators, etc).

      Now, there's a number of different architectures one can do. I'm going to assume you're using templates and an RDBMS (like MySQL or Oracle). I'm also going to assume you're using intelligent developer practices, such as design, documentation, and testing.

      1. Monolithic: One script. Period.
        I hope I don't have to tell you why this is bad. Maintenance, performance ... it all suffers.
      2. Communist: One script is one unique page. They all live in the same cgi-bin directory.
        I don't know about you, but I'm going to run out of ways to name my scripts. Also, I'm going to want a way of saying "This script and that script are related" in the filename.
      3. Clannish: One script is one unique page. Each functional area has its own sub-directory.
        So, now we have a "Reports" and a "Preferences" and a "Admin" area. Each script is still named uniquely, but they're now named relative to their directory.

        (In all the "One script, One page" options, you also have the fact that you have a bunch of other files running around, attempting to link everything together. This is the shared code, from "How do I get a $dbh" to "How do I print" to "How do I log an error". This is maintained separately.)

      4. Socialist: One script is one functional area.
        Now, you're developing similarly to C::A. Except, you're doing everything C::A does for you. By hand. In multiple places. Most likely with if-elsif-else. You probably have a bunch of objects you create to do the heavy lifting. They either inherit or delegate to other objects which answer the shared code questions.
      5. CGI::Application: One script is the entry point to one functional area. C::A does the heavy lifting.
        Now, you're cooking with gas! You have one class that has your app-wide stuff. Each functional area has one class which contains the uniqueness of that area. Each page view has a run-mode, as well as each page action. You don't worry about how stuff is connected - you just play with the TinkerToys(tm).

      I would consider that an evolutionary scale. C::A does a lot of the heavy lifting for you. It also is self-documenting. In other words, you don't have to think about (and potentially mess up) some of the nitty-gritty details. To me, that's a "Good Thing"(tm).

      ------
      We are the carpenters and bricklayers of the Information Age.

      Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (3)
As of 2024-04-24 19:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found