Beautiful Code [171]
Useful for interactive web applications
I wanted Bio::Graphics to be suitable for the backend of an interactive web-based genome browser. In particular, I wanted end users to be able to click on the graphical renditions of features in order to bring up pull-down menus, link to other web pages, view tool tips, and so on. To accomplish this, Bio::Graphics had to be relatively fast so as to generate images in real time. It also had to keep track of the positions of each of its rendered features (and, if necessary, their subfeatures) in order to create an image map that could be passed back to the programmer.
Independence from graphic formats
I wanted Bio::Graphics to be useful for generating screen-quality, low-resolution images suitable for embedding in a web page, as well as for generating high-resolution, publication-quality images. To do this, the part of Bio::Graphics that handled the logic of the layout had to be separate from the part that generated graphics. Ideally, it should be able to output both pixmap and vector graphics formats.
Independence from database schemes
The bioinformatics community has designed many dozens of database formats for managing genome annotation data, ranging from simple flat files to sophisticated relational databases. For maximum utility, I wanted to avoid tying Bio::Graphics to any specific database scheme. It should be just as easy to invoke Bio::Graphics to render a genome region described by a flat file as to have it render a segment of a genome described in an Oracle database.
Growing Beautiful Code in BioPerl > The Bio::Graphics Design Process
12.2. The Bio::Graphics Design Process
I'm not enamored of formal design engineering; instead, I typically write out little snippets of pseudocode that describe how I want something to work (a "code story"), play a bit with input and output formats, do a bit of coding, and—if I'm not satisfied with how the system is fitting together—go back and rework the code story. For anything larger than a toy application, I implement little bits of the system and test them out in standalone programs before deciding whether to move forward with that part of the design. I keep my notes in a "stream of consciousness" text file, and commit code to my CVS repository often. I try to make all the code visually appealing and elegant. If it isn't elegant, something's wrong with the design, and I go back to the drawing board.
12.2.1. Designing How the Developer Interacts with the Module
My first design task was to figure out the flow of a typical Bio::Graphics application. I started with the code story shown in Example 12-1.
Example 12-1. Basic story for BioPerl::Graphics use (pseudocode)
1 use Bio::Graphics::Panel;
2 @first_set_of_features = get_features_somehow( );
3 @second_set_of_features = get_more_features_somehow( );
4 $panel_object = Bio::Graphics::Panel->new(panel_options...)
5 $panel_object->add_track(\@first_set_of_features,
track_options...);
6 $panel_object->add_track(\@second_set_of_features,
track_options...);
7 print $panel_object->png;
The code story starts out by bringing in the main Bio::Graphics object class, Bio::Graphics:: Panel (line 1). This object, I reasoned, would hold configuration options for the image as a whole, such as the dimensions of the resulting diagram and its scale (base pairs per pixel), and would be the main object that users interact with.
The code story continues with two calls to fetch arrays of sequence features (lines 2–3). In order to maintain