Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery

Re^2: Perl to protect database field name info

by ptum (Priest)
on Feb 13, 2007 at 14:22 UTC ( #599695=note: print w/replies, xml ) Need Help??

in reply to Re: Perl to protect database field name info
in thread Perl to protect database field name info

I agree with this. I'm in the middle of writing an internal web application using CGI::Application and I succumbed to the temptation of mapping my database tables directly to user functions 'to save time'. It worked OK at first, while I was still in the simple prototype stage, but I am starting to feel the pain now, as my customers happily suggest changes. Because I don't have a very thick layer of abstraction between my user's domain and the database domain, I am finding it very painful to make changes that affect the structure of my database tables, and those modifications create ripples which threaten to destroy my application.

Besides, you pretty much have to agree with someone who can correctly spell 'abrogate' and use it effectively in a sentence.

  • Comment on Re^2: Perl to protect database field name info

Replies are listed 'Best First'.
Re^3: Perl to protect database field name info
by punch_card_don (Curate) on Feb 13, 2007 at 14:45 UTC
    OK, then could someone please write something more concrete on this infamous abstraction?!?!

    I mean, just how abstract can you get in receiving "first_name = bob", cleaning it, and writing it to users.fname?


    Forget that fear of gravity,
    Get a little savagery in your life.
      In your case where you have a firstname field that is going to be stored completely within the firstname column, the abstraction doesn't make any sense. And, if you never get any more complicated than that, then the abstraction layer I'm talking about is counter-productive. Seeing as about 50% of all programmers never work on applications that need this kind of abstraction, 50% of all programmers would be ill-served in using it.

      Let's say, however, that you're in the other 50% - the one that does need the abstraction. But, you don't understand why. The reason why is very simple - because your requirements will change. When requirements change, you will receive requirements that are from the user's perspective and within the user's domain of understanding. If you have designed your application correctly, you will be able to change the user-visible form WITHOUT touching the underlying database tables. This is not possible if your database table is used to generate your form.

      For example, let's say that your company is so successful that you expand into Indonesia. Your application was a big part of that success, so you're leading the charge. And you run into someone without a first-name (many Indonesians only have one name instead of the two that we have in the US or Europe). Now, because your database table generates your form, you cannot abstract away the lack of a firstname within your code - your users have to do it for you.

      Rule #1: Users will always make mistakes. Your application should make it hard for them to make common mistakes. It should never require the user to account for your mistakes.

      Let's say that you've managed to account for the issues in Indonesia. Now, you're moving along and your application is being sold to the Australian aborigines. You recently had space issues, so you contracted all those VARCHAR(255)'s down to MAX(colname) + 10. In the case of firstname, that was 43, rounded up to 50. Whoops! Aborigines can have extremely long firstnames. Now, while this would require a database change anyways to account for them, instead of having constraints in the application as well as the database, the users see the database error.

      Rule #2: Users should always be presented with useful errors that they understand. You should never present a user with an error from anywhere other than the immediate layer that they are interacting with. An error from the database is good only if the user is knowingly interacting with the database. Otherwise, you should be providing the error they see.

      Rule #3: Processing should stop as soon as possible. Errors should be detected as soon as possible and handled as close to the source as possible. So, if there is a length problem with a field, that length should be encoded in the user interface. If the UI is a web browser, the length should be checked in Javascript, Perl, and the database.

      Let's talk about #3 some more. Once you have separated out what's acceptable for the UI from what's acceptable for the database, you have some really neat possibilities. For example, you can have different restrictions based on different requirements, all going to the same database. So, if firstnames can only be 30 characters in Finland, but they have to be 45 characters in Denmark, you can easily handle that. Alternately, your database can now be used for an application you write and a completely separate application that your friend writes. Both of these situations are very common in large businesses. (I have maintained more of these than I can count.)

      Does this help or would you like more discussion on the topic? It might help if you looked up MVC on the wikipedia.

      My criteria for good software:
      1. Does it work?
      2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
        OK, we're getting to the nub of the matter. Sometimes, some fields are best abstracted, either so that the user interface can be optimized for users, or in case the use of the site changes.

        That sounds very reasonable.

        Thanks for the discussion.

        Forget that fear of gravity,
        Get a little savagery in your life.

      I'll take a stab at it, although you might want to take what I say with several pinches of salt, since I haven't done very well at this lately.

      Suppose I have a simple web application that gathers information about a customer -- their name, address, billing preferences, etc. Suppose I also want to store that information in a relational database. I think what dragonchild is saying is that how you gather that information from the user ought to be the way that best fits their domain -- that is, you might gather some or all of that information in a way that is user-friendly to them, whether squeezing it all on a single screen so that they don't have to keep hitting 'submit' all the time, or maybe you will slowly gather the information from them, snippets at a time, so as not to annoy your user. However you do this, it ought not to be constrained by your database structure or how you implement it on the back end -- in fact, you ought to 'abstract' the two domains (maybe by building classes that reflect the user's domain but which 'save' themselves to the database whenever they have enough information to do so). To make use of your example, it may not make sense for the user to separate his first and last name just because your database has a field for fname -- he may prefer to enter his full name in and let your application figure it out.

      One way to think of it is as though two people (maybe they don't like each other very well) are writing the application -- one is a front-end developer and the other works on the database side. Your class modules will provide an API for the front-end, and another for the back-end, so that either can change independently of the other, and not break anything. So you might have a Customer class, which has methods for setting its private data elements (like name) and which knows how to save itself to one or more database tables. If the front-end guy decides to accept the customer's name in four fields (first, middle, last, suffix) your class just needs a method that can handle all four of those arguments and make sense of them. Similarly, if the back-end guy decides to munge all four fields into a single database field and moves that field to another table while he's at it, your class needs to know how to save the customer name, but the front-end guy shouldn't have to worry about it.

      I fear I may not be doing a very good job at describing this concept, and I suspect it is something of which I have an imperfect understanding. Can anyone help me out with this?

      Update: This thread: Design help: OO Perl and db tables dealt with some of the issues you raise, a month ago or so.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://599695]
[Corion]: Hurr - use lib glob '/opt/perl/foo*'; - I'm not really sure if that is sane ;-D

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (14)
As of 2017-01-19 15:31 GMT
Find Nodes?
    Voting Booth?
    Do you watch meteor showers?

    Results (170 votes). Check out past polls.