Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw

O-O design, aggregation of objects

by wanna_code_perl (Pilgrim)
on Nov 08, 2008 at 03:40 UTC ( #722346=perlquestion: print w/replies, xml ) Need Help??
wanna_code_perl has asked for the wisdom of the Perl Monks concerning the following question:

Hello fellow monks,

I am hitting an embarrassingly basic stumbling block, getting confused between doing things the O-O way, and the "Perl" way. (Which, to my mind, can sometimes be two overlapping and sometimes conflicting goals!) In the end, I want something that is elegant, functional, and reusable.

I think what I'm really looking for here is a general Perl design pattern. For the purposes of this discussion, though, consider a "User" object in the system that has attributes "username", "real_name", and "email_address". There are also methods set_password, and check_password. (Implementation detail: Passwords are stored one-way encrypted, so these methods are necessary to do the crypt steps). As you might imagine, Users are stored in an SQL database. The above, I think is fine so far, yes?

Now, here is where I'm stumbling:

Who creates users? If I call User->new(), should that actually create a database entry?

Where does the search() function go? (For example, if I want to find all users with a particular email address). That doesn't seem like it should be a method of User to me. Should I have some kind of aggregation class like a UserSearch class?

When do I commit the User back to the database? Do I do this automatically whenever an attribute is updated, or through an explicit $user->write()? Does SQL code even belong in the User class? Or should the User instance be somehow passed to another specialized class that will do the actual storage functions?

Finally, can you point me to any good existing implementations of something similar?

Again, the User class is just an example. That being said, I want as much code re-use as possible, so if--for example--some of the DB and search mechanisms are better off put into a more generic class or library, suggestions there would be useful, as well.

A lot of questions, to be sure! Thanks for reading.

Replies are listed 'Best First'.
Re: O-O design, aggregation of objects
by GrandFather (Sage) on Nov 08, 2008 at 04:15 UTC

    Don't reinvent wheels. There are a pile of wrapper modules for handling database management from Perl. Probably the closest to the level you want is Class::DBIx.

    That of course doesn't answer the bigger question. I'd suggest that User->new () doesn't create a user without being told to, but you can pass a bunch of parameters to it among which may be -create => 1, -user => 'Wibble' and so on.

    Rather than providing a bunch of getter/setter members you could provide a single setter and getter that takes a parameter specifying the property to set/get. Tk uses this technique for getting and setting options using configure and cget.

    Perl reduces RSI - it saves typing
Re: O-O design, aggregation of objects
by ig (Vicar) on Nov 08, 2008 at 08:13 UTC

    I too would look for existing modules. LDAP databases (including AD) are commonly used to keep user information and you can find interfaces to them, relational databases or flat files for this purpose. If you search CPAN for user authentication database you will find several existing modules and you can see what best fits your needs.You might also look at what existing application do for user authentication and record keeping.

    My inclination would be a user object without database interface, only holding the parameters of a user, and a user collection object with a database interface for persistence. The user collection object would have the search function, returning sets of matching users, and a function for committing a user to the datbase, whether new of changed. But I'm no expert (just opionated) and I would be easily swayed by any well done module.

Re: O-O design, aggregation of objects
by mpeever (Friar) on Nov 08, 2008 at 03:55 UTC
    If I call User->new(), should that actually create a database entry?

    I'm interested to see what feedback you get. But I assure you, DB writes on object creation is a bad idea. It will lead to a ton of spurious of DB writes, and possibly race conditions. In the very least, creating the objects from the DB will be interesting, as de-serializing those objects from the DB will trigger DB writes...

      ...except that you can instantiate an object without calling ->new, so the infinite loops you mention are easily avoided.

      I'd still say "no" to save-immediately-on-create because it's likely to result in a number of spurious database records being created. (I don't know about the OP, but I sometimes instantiate temporary objects which have no reason to be stored persistently.)

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://722346]
Approved by GrandFather
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (7)
As of 2018-03-21 07:40 GMT
Find Nodes?
    Voting Booth?
    When I think of a mole I think of:

    Results (264 votes). Check out past polls.