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

I have been developing a Win32 application for about a year now. It consists of a server portion (waiting for incoming connections), as well as a client portion. Since both client and server share routines, I decided to make a module to house the routines that would be used by both. The server code is pretty straight forward. It can be found at http://people.we.mediaone.net/tessai/projects/rpc/rpc.pl.txt. The client code is also available http://people.we.mediaone.net/tessai/projects/rpc/rpc8.pl.txt. Lastly, the module is called Student.pm and is at http://people.we.mediaone.net/tessai/projects/rpc/Student.pm.

I have not written any documentation for this module yet, since I'm the only one using it. This application is for use with my servers (WinNT) here at the office, but may be useful for anyone that is working in an educational environment that utilizes SIS (Student Information System).

The server sits on a port and waits for connections. When a client connects, it sends the server a small amount of information (Room number, Track, Birthdate). The server then searches a text file of SIS data (acquired from the school SIS computer system), and returns a list of likely candidates (students that match the information provided by the client). The client is supplied with a window containing the possible students. The student is then allowed to click which student he/she is. The client then contacts the server again with the student information. The server checks to see if the student has already created an account, searching a second log file of previously made student accounts (if the student has an account, the client will be sent a warning... this is not implemented yet). If the student does not have an account, a username (usr_create sub), password (Birthday), and home directory are created (usr_home_dir sub). Next, the user will be created with all of the information given. The home directory will have permissions given by $staff_perms, $admin_perms, and $student_perms.

From what I can see, the only things left to implement in my application are the adding of the user to the domain and the warning/logging mechanism. Is there anything else I should think about implementing? I don't think that any of the data (with maybe the one editbox in the client portion of the app) is tainted, but I could be wrong. I have not tested it with "format c:" or anything like that, but I tried to make sure that I untainted (if tainted at all) the data as best as I could (of course, I'm always open to suggestions).

The Win32::NetAdmin::UserAdd() will take care of adding the user. However, I'm somewhat stuck on how to implement the logging mechanism. I've been thinking (as is shown in the module) of just flushing a CSV line of data to a text file. Another solution, I suppose, would be to come up with some sort of database and use Win32::ODBC (I'm still learning how to use databases and the like) to do the logging.

NOTE: The RPC.pm module is from Advanced Perl Programming (the Panther book), which uses MSG.pm (same book) and FreezeThaw.pm (from CPAN).<br
Thanks for any help,

Theodore Charles III
Network Administrator
Los Angeles Senior High
4650 W. Olympic Blvd.
Los Angeles, CA 90019
323-937-3210 ext. 224
email->secon_kun@hotmail.com

Replies are listed 'Best First'.
Re (tilly) 1: Suggestions? (style, module use, etc.)
by tilly (Archbishop) on Jan 07, 2002 at 21:47 UTC
    Without seeing the application, I cannot make style suggestions. I would, however, suggest that you give some thought to how administrators can go about correcting mistakes. (Documentation of manual proceedures may be sufficient.)

    As for logging techniques, I would just open a file with autoflushing turned on (see the example in select to turn off buffering on a single handle) and write to that.

      The application (client, server, and module) are all available on my personal Mediaone webpage. The client is here. The server is here. Lastly, the module is here. I'm trying to make the module more general, to handle different datasets and such, since the info file I'm using may not be the same one I'm using a year from now. So, I was looking for possible ideas to expand the usage of my module so that it would be more general (and possibly even make it to CPAN for it's small niche). The SIS system is a very strange beast, and I'm trying to make this code very portable (so that others may use it, even though they have a different info file).

      This "info file" I'm talking about is a flat text file (comma delimited) that has data about a student. Most of the time it includes the name, homeroom, track, homeroom number, homeroom teacher, and student number (some sequential number from 1-9999). The data can be arranged any way the programmer wants. Since I really do not know HOW the data will be stored in that flat text file, I'd like to be able to handle any orientation of data (I know I'll still have to analyze the file to see how the data is arranged, but I would like to be able to handle any case just by passing a different set of parameters to my subs.) I'm still somewhat new to application development, so I'm trying to incorporate scalability into my code. That way, should I get a new info file with differently arranged data, I won't have to touch my module. I can just send it a different set of parameters (to tell the sub how the data is arranged) and go from there.

      It may just be that I'm trying to do more than I need to with this module idea, but I think making the subs I'm using modular would make things easier for others in my situation. Again, any suggestions would be helpful.

      Theodore Charles III
      Network Administrator
      Los Angeles Senior High
      4650 W. Olympic Blvd.
      Los Angeles, CA 90019
      323-937-3210 ext. 224
      email->secon_kun@hotmail.com
        Sorry, I don't have time to address this in detail any time soon. Just a few specific criticisms on points you may be missing:
        1. OO modules generally should not use Exporter. The correct class that calls are to be dispatched to should be decided by the syntax of the method call.
        2. No strict.pm. I can tell from your variable usage that you have the good habits it is meant to encourage. However it is a lexically scoped declaration and needs to be in a module for you to get the typo checks. (I list this after Exporter because I like putting Exporter related stuff before I use strict.
        3. Your constructor is designed to be called as a function. This is probably connected to your exporting it. But that isn't good. You are overwriting the generic function name new() in other namespaces. Here is a much better constructor:
          sub new { my ($class, %self) = @_; return bless \%self, $class; }
        4. You are using full tabs for indents. It is important that indents be 2-4 spaces. You might be solving this by using custom tabstops. This helps you, but custom tabstops that differ between people cause their own potential problems (try programming in Python to find out what). I prefer using explicit spaces. (Easy with any decent programming editor.)
        5. You have a lot of Student::get_attr() calls which are bad for two reasons. The first is that you are in package Student, if you meant to write them as function calls they are better written as get_attr(). The second is that they are actually all method calls. To move from doing OO lipservice to taking advantage of what OO does, it is important to switch syntax to $obj->get_attr(...), it isn't just that the syntax is "right", it is that you now do a method dispatch on type without scattering the assumption about type in your code.
        6. You localize $_ unnecessarily. Having been bitten by something like this before, I sympathize with paranoia. But just in case you didn't know, Dominus's tutorial Coping with Scoping mentions the autolocalization in loops.
        7. You have certain code which you write again and again. If you find yourself doing that (or cutting and pasting), that is a sign that you really wanted a function. For instance you write the same 5 lines over and over again for a random letter. Don't. Write a 5-line function and call it.
        8. On a related note, you don't appear to have yet made the jump from, "this is how I will accomplish a certain kind of task" to saying, "I am going to factor that out by writing an interface to accomplishing this task". That is how you should handle your logging issue. Write an interface to sending log messages, and then call that interface. Decide later whether that goes to a file, STDERR, or whatever.
        OK, I know that is a lot to digest, but I am going to give you one more item. It isn't Perl specific, but Code Complete is an excellent book which I think would be an excellent next step for you. It is mainly about procedural programming, yes, but the things it teaches are generally applicable, and will give you enough foundation in the principles of good procedural design to see what problems OO addresses.