Dear monks,

Often when writing code, i try to encapsulate the code in a class, library, package (depending on the language used) so that it can be reused if necessary.

Doing so i often find myself thinking about the same issues over and over again :

  • How much functionality should the library encapsulate ?
    Is it better to make ALL the functions that are related to a common goal available to the application programmer OR should i mask these behind 1 or 2 method calls ? The former will allow for greater flexibility (maybe unnecessary) , the latter will greatly simplify its usage. Or should i do both and really complicate things ?
  • Who is responsible for error handling and error resolving ?
    Should the library trap any foreseeable error and deal with it OR should this be left to the application programmer ?

    If there is a standard to writing libraries as to what you should expose and what not then i'ld like to hear about it...

    Jorg

    "Do or do not, there is no try" -- Yoda

  • Replies are listed 'Best First'.
    Re: How to write library code
    by footpad (Abbot) on May 17, 2001 at 03:23 UTC

      Hard and fast rules are tough, given the number of ways we use libraries, packages, or whatever you want to call them. I think the best advice is to a) Don't Repeat Yourself, b) Add just enough to do the job; no more and c) design orthogonally. For more such advice (and more well written explanations, pick up a copy of The Pragmatic Programmer.

      How much functionality should the library encapsulate ?

      As much as is needed for the basic operations, no more. Going beyond that increases the amount of testing, risks sidetracking you on none-core issues, and can (in certain cases) confuse your intended audience. In turn, these prevent your library from being re-used...hindering the very laziness that led you to create the library in the first place.

      Remember, you'll be using this over time. You don't need to build in every bit of functionality up front. Let it evolve as it needs to.

      Is it better to make ALL the functions that are related to a common goal available to the application programmer OR should i mask these behind 1 or 2 method calls ?

      I like to keep the core library as basic and streamlined as possible, providing "wrapper" functions in a separate file and/or subclass. I find this provides me the convenience of the quick access while allowing more control when needed.

      Or should i do both and really complicate things ?

      No; see above...unless you're independently wealthy, not planning on releasing it soon, or really don't want to re-use it. :-)

      Who is responsible for error handling and error resolving ?

      Depends on the interface. I've had good luck making the core routines provide return values indicating success/failure and leaving the presentation of the errors to the wrapper classes/calling code.

      Should the library trap any foreseeable error and deal with it OR should this be left to the application programmer ?

      Depends on how critical the error is to the library and how serious an error it is. If it's a reasonably silly error (mistyped filename, for example), I return failure using an error code. If the system is out of resources or some other catastrophic failure, I'll probably generate the error myself. Keep in mind that most languages provide different levels of error-generation. For example, Perl offers the lovely Carp module, which (thanks to Tilly) I've been playing with recently.

      Be very careful with fatal error handling in your libraries. To illustrate, I wrote a package not too long ago that made file handling a lot easier in a certain context, except I got carried away and over-engineered the error handling, localizing it to the core subroutines. If a file wasn't found, I called die().

      A few days later, I called my routine from a bit of code that didn't really care that the file didn't exist. However, because the file didn't exist, the error handler stopped the program cold, forcing me to either re-work the package or to add a handler to detect that error and recover from it "gracefully." I chose the former and it saved a chunk of code.

      Your mileage will vary, or course, based on the library and problem(s) it solves. As with other code, though, I've found the LAW (Least Amount of Work) principle helpful.

      --f

    Re: How to write library code
    by japhy (Canon) on May 17, 2001 at 02:37 UTC
      Most code I write has an API with a rather simplistic look, which covers the inner working of the code. I keep the API functions simple code-wise, too, if I can, so that a person can read them and get a good idea of what's going on.

      As far as error handling, always use Carp -- it lets the user know where in HIS code the error started, and can even give a stack backtrace to show what propagated the error. Also, consider having function return false and setting some package error variable.

      japhy -- Perl and Regex Hacker

    Re: How to write library code
    by cacharbe (Curate) on May 17, 2001 at 04:34 UTC
      I think this totally depends on your target audience.

      For the most part, I work with the Black Box Theory(tm). I explain the interface and little else. My reasoning is multitiered.

      One, I rarely want the programmers working under me to go 'spelunking' in my code. Not because I don't have faith in my code or my coworkers, but being the one whose name is stamped all over it, I'd prefer if 'streamlining' my code was team effort with me on the team.

      I document my code religiously (more for my own benefit really - I'm forgetful in my advanced years) so it _should_ be easy enough to change it. *sigh* Getting of topic...

      Two, when you work in a project environment with more than one coder, you agree to certain functionality and code to it. I usually add a little more than is asked for, but too much. A little above expectations and you're a hero, too much, and you have too much free time. It's a fine line.

      I try to code modules (objects, whatever) for maximum reusability, which usually means KISS.

      Just my US$0.02