in reply to Re: Best practices passing database handles, cgi objects, etc.
in thread Best practices passing database handles, cgi objects, etc.

Fantastic! A technique to avoid using global variables, but while still keeping all the problems associated with global variables!

The problem with using global variables is not an irrational fear of the our keyword. The problem is that it introduces global state. This means that if you write an app that, say, operates a blog, and has a database handle as part of its global state, it becomes very difficult to reuse any of that code when you want to write an app that manages multiple blogs (across multiple databases). All your functions are picking up the same database handle from some global place, so you can't tell one function that it needs to copy an article from blog A, and another function that the same article needs to be pasted into blog B.

Global state makes testing very difficult. If function do_something isn't passed a copy of $dbh as an argument, but instead picks it up from global state, then it becomes difficult to test do_something by passing it test/dummy database handles.

So the enemy is not global variables. The enemy is global state. Global variables are a manifestation of global state, but so are the techniques you suggest above.

use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

Replies are listed 'Best First'.
Re^3: Best practices passing database handles, cgi objects, etc.
by Anonymous Monk on Feb 18, 2014 at 15:23 UTC
    Sigh.

    What is wrong with keeping a CGI object and a CGI::Session object as global state/variables/whatever? They are request-dependent. They need to be overridden at the start of each request. Are you planning to serve HTTP requests in a non-serial manner or something?

    The database handle: There's usually one per process. One FCGI-ish process usually handles a single web site. What is the problem storing a handle globally in such a case? Certainly, if you plan to connect to multiple databases in your program you don't use that design, but you have to concoct pretty elaborate scenarios to get to a point where this single-handle thing falls down.

    And before you say 'unit testing', you can override those functions, can't you?

      What's wrong? It hard-codes the assumption that one request equals one process, and thus makes it doubly hard to move on to a solution where multiple requests can be served from a single process.

      Whatsmore, it limits your objects and functions to only being used in CGI scripts. Some of these objects may be generically useful, for example, useful in cron jobs that perform various routine maintenance related to the website.

      Even if you ignore all that, there are valid reasons to make sure that sessions are passed around from function to function. For example, you may wish to allow the admin user, once they're logged in, to take over any other user's session - to help diagnose website problems for example. Doing that sort of thing is much easier if the session is not a singleton.

      use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
Re^3: Best practices passing database handles, cgi objects, etc.
by Anonymous Monk on Feb 18, 2014 at 13:19 UTC
    I fail to see how your OO approach is any better; all it does is wrap some global variables inside a class.

    Also, it's silly to store multiple blogs (with identical schemas, I presume?) across multiple databases.

      I fail to see how your OO approach is any better; all it does is wrap some global variables inside a class.

      That is how its better, its called encapsulation

      You can have $foo and $bar both be of type Classname, with both being able to ->dance and ->sign

      Its better in the same way subroutines are better than not subroutines ( goto )

      Its also why  Main(@ARGV); sub Main { } is better than  MAIN: { } because you can only  goto MAIN , its a label, its not a subroutine, you can't call it

      Its better in that its : testable/mockable, reusable, not fragile Action at a distance (computer programming)

      http://programmers.stackexchange.com/questions/148108/why-is-global-state-so-evil

      You cannot have more than one instance of global state -- its global

      Also, it's silly to store multiple blogs (with identical schemas, I presume?) across multiple databases.

      So is everything you wrote :)

      Because classes can have multiple instances.

      (And the blogs may be operated by different people and organizations and be installed on entirely different servers. There may be slight variations in the schemas because of different versions of the blog engine being installed.)

      use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name