"Why another documentation system when there are already automatic system in existence?"
To answer that question let's first think of who are the target of the class documentation. At one hand you have the user who wants user level description and examples. On the other hand maintainers of the class also needs a further level of internal system documentation which is of little use for the end user.
For the maintainer of the class the code itself should contain necessary code level comments together with suitable architectural overviews. For the end user the documentation should be provided entirely external to the code. Current automatic system insists on keeping all documentation in the source itself from where it later can be extracted to produce documentation.
The problem with these system is that the code gets cluttered with a lot of user level documentation which makes the code difficult to navigate in.
On the other hand an automatic system has the advantage that it can extract class information automatically (like class hierarchies and function prototypes) which is always tedious and error prone to copy&paste manually.
The proposed system combines the two methods by first automatically extract all class information storing it in a database and then let the developer augment that database with suitable user level description of classes and methods.
Now, whenever the code is modified the automatic extraction is just re-run and the class hierarchy gets automatically adjusted. Existing description and examples in the DB are preserved.
The documentation can then be automatically generated from that DB. By applying different formatting modules different types of documents can of course be generated.
An overview of the proposed system is shown in Figure 1.
An additional (almost accidental) feature that has proven useful in practice is the fact that having all the information in a database makes it easy to generate static's on the state of documentation. For example, we can easily see how many percent of the public APIs that are documented. This is very useful for tracking the progress of documentation and making sure that the effort spend documenting is directed to the most needing classes.
Since the class Parser is a generic parser class it doesn't know anything about databases so the actual work is done by the subclass DBParser which extends Parser and provides appropriate factory functions to handle the interface to the DB. The way this works is that the Parser class provides "virtual" functions which can easily be overridden by the appropriate sub class. By "plugging" in to the Parser framework it is very easy to adapt it to specific needs in a very clean way without having to be intimate familiar with the inner workings of the Parser.
All database access is done through a DB server object which is responsible for all aspects of DB access. Class DBServer hence which provides functionality to access and query a MySQL DB in various ways. In addition to the server object each query is returned as an instance of class DBResult which is then used by a client to manipulate and extract information from the result of a query. The relationship between the classes involved with the parsing aspect of the DDDA system is illustrated in Figure 2. below.
Since all this functionality is implemented in a PHP script the script needs an entry point. To handle this each script has it's own driver object. This object is responsible for initialization and extracting possible script variables (such as arguments in a URL specification). By convention all script execution is kicked off by the predefined Run() method in the driver.
This consists of a number of forms to modify/edit data for classes and methods as well as an index page to navigate and chose the class/method to work on.
The interface is completely WEB based and starts with an overview of all stored classes and methods in the BD from where you drill down to the class/method you want to edit. In version 1.0 of DDDA this interface is fairly basic and some more creative use of JavaScript and DHTML is probably not a bad thing. However, due to time constrains, DDDA 1.0 mainly focus on functionality rather than a lot of "fancy" WEB programming. This is also a thing that very easily can be added as a front end cosmetic "thingy" later on.
Once the programmer/documenter has chosen the class/method to edit he is presented with a standard WEB-form with all the static information about the class/method. He can then just add suitable description and examples.
The overall class hierarchy for the augment subsystem is shown in Figure 3. below.
As was previously mentioned it was found that the ability to generate statistics is quite useful to direct attention to less than well documented areas. It has also proven as a very good way of actually keeping track of the documentation status in a very measurable well.
All statistical processing is centralized in the class DocStat. The static's is based on a point system where each class (and method) receives a certain number of points based on the level of documentation. The points system is weighted so that a class overview is considered much more important than a forgotten comment for a single method parameter. The actual points are than compared to the maximum achievable for that class (or method) to generated a percent figure.
The DB edit and layout enginge (class DBTableEdit and class FormLayout) automatically generates code to edit a specified table, row by row. It takes care of both generating the actual HTML as well as the necessary logic to handle the form submitting and DB handling. The layout of the form is specified by giving the specified row and column for each field that should be in the form together with the type for the field and some additional layout parameters. There are 8 compulsory and 2 optional parameters necessary to specify one input cell. The parameters are as follows
Parameter | Explanation | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
dbfield-name | The name of the database field that corresponds to this form field. Note that by convention the actual field in the DB has the name 'fld_' as prefix to this name. | ||||||||||||||||||||||
row | Which row in the form this field should appear in. | ||||||||||||||||||||||
col | Which column in the form this field should appear in. | ||||||||||||||||||||||
span | How many columns this field should span | ||||||||||||||||||||||
label-text | The text label to be shown close to this field in a way specified by the next parameter | ||||||||||||||||||||||
label-align | Specifies if the label should be shown above the field or to the left of the field. | ||||||||||||||||||||||
fld-align | Specifies if the field should be aligned to left or right in the cell | ||||||||||||||||||||||
fld-type |
What type of field should this be. Possible types are:
| ||||||||||||||||||||||
fld-arg1 | The first fieldtype specific argument. | ||||||||||||||||||||||
fld-arg2 | The second fieldtype specific argument. |
For reasons of brievity we don't give a full description of all the details on how to use this as a standalone system instead we just give an example. Study the following specification (which happens to be a slightly modified class editing form from the DDDA system)
$formSpec = array( array('name',1,1,3,'',LBLPOS_LEFT,FLDPOS_LEFT,FLDTYPE_NONDBTEXT), array('public',2,1,1,'',LBLPOS_LEFT,FLDPOS_LEFT,FLDTYPE_DROPDOWNCODE,$yn), array('file',2,2,1,'File:',LBLPOS_LEFT,FLDPOS_LEFT,FLDTYPE_STATICTEXT), array('linenbr',2,3,1,'#',LBLPOS_LEFT,FLDPOS_LEFT,FLDTYPE_STATICTEXT), array('ref1',4,1,1,'Ref1:',LBLPOS_TOP,FLDPOS_LEFT,FLDTYPE_DROPDOWN,$cl), array('ref2',4,2,1,'Ref2:',LBLPOS_TOP,FLDPOS_LEFT,FLDTYPE_DROPDOWN,$cl), array('ref3',4,3,1,'Ref3:',LBLPOS_TOP,FLDPOS_LEFT,FLDTYPE_DROPDOWN,$cl), array('ref4',4,4,1,'Ref4:',LBLPOS_TOP,FLDPOS_LEFT,FLDTYPE_DROPDOWN,$cl), array('desc',3,1,4,'',LBLPOS_LEFT,FLDPOS_LEFT,FLDTYPE_TEXTAREA,70,5), array('timestamp',1,4,1,'',LBLPOS_LEFT,FLDPOS_LEFT,FLDTYPE_TIMESTAMP)); |
when given as specification it will generate the form shown in Figure 4 below.
In version 1.0 of DDDA we supply a basic HTML formatter plug in which generates (surprise!) HTML in the form of a class reference.
In the future it is anticipated that 3:rd parties might supply PDF or RTF formatting plugins or even alternate HTML formatters.
The formatter plug in consist of a base class ClassFormatter which have a number of virtual methods which the actual plug in must implement in order to generate the output. These virtual methods will be automatically called by the framework with specific information according to the basic assumption of the layout of the code. These hooks will make it possible to generate very different layout should you not be happy with the supplied HTML formatter.
Since the report generator is responsible to generate a lot of cross references which potentially could lead to unnecessary SQL queries and performance problems the report generator makes use of a DB Cache (class DBCache) which pre fetches the class and method information which dramatically increases performance.
An example of this formatting style is given in Figure 6 below.
RectPatternCross | RectPattern |
DoPattern() RectPatternCross()& nbsp; SetDensity() SetOrder() SetPos() | RectPattern() SetBackground() SetDensity() SetPos() ShowFrame() Stroke() |
Some purists might argue
that storing both a foreign key and a foreign name is duplicate and that the
tables aren't normalized. However, this is by design to avoid table
lookups and slightly improve performance.
Each table has a primary key "fld_key" and a timestamp "fld_timestamp" to keep track of when the table row last was edited. We don't give detailed explanation of each field here but instead refer the interested reader to the system documentation. Most of the fields should be self-explanatory anyway.
When first started the user is presented with the DDDA main meny as shown below.
From this meny the user can choose to either create a new project or work on an existing project. The first alternative is used to get an overview of an existing project, the second to update the DB from the script files that makes up a project and the last alternative to modify or create a project.
From the above form the user may eiter modify an existing project or create a new one.
From this view the user may now choose to edit a specific class or method by clicking on its name. The corresponding forms are displyed below in figure 12
In terms of future functional enhancements for the next version the plans are to: