SDSS Science Archive, Standards & Guidelines
The Science Archive will be programmed entirely in C++, except for the
Graphical User Interface which will initially be written in Tcl/Tk
The official documentation will be written in
HTML, and converted into other formats as needed. We will use
the survey standard revision levels for supporting the following
software: Tcl/Tk, Perl, Shell Scripts, and SDSSTools. Initially,
however, we require both Perl5, Tcl/Tk v8.0, and HTML as outlined
below. The following Standards and Guidelines are designed to enhance
portability and readability, as well as simplify the development
process.
Table Of Contents
Programming Guidelines
Documentation Guidelines
Preamble
The purpose of this style guide is not to force each of the
programmers to adopt a style such that all the Science Archive code
appears to have been written by one person. Rather, each programmer
is encouraged to find his own best style and use it consistently. The
rules and guidelines below were reached by consensus to avoid
differences in style that would be outright confusing, and to
introduce some conventions that should improve the readers'
comprehension of all code, regardless of author.
sx Prefix
The sx prefix is mandatory for global type names and functions inside
the SX package. For helper packages that may be used outside of the SX
by others it is optional (example: HTM index). SX_ may be used
as a prefix for preprocessor macros, but is not required. The sx
prefix should not be used in any other context.
Capitalization
Preprocessor macros should be entirely capitalized, with component
words separated by underscore. Exceptions to this rule should be made
only with good reason. Macros can interact with the rest of the code
in surprising ways, and so it is important to highlight them.
Capitalize the first letter following the sx prefix for all
global type names and functions. An exception to this rule is made
when the _t suffix is used to indicate that the symbol is a type name.
Other symbols, such as variables and enumerators, should not begin
with a capital.
After the first component word in any symbol, capitalize the first
letter of each remaining component word. Do not use the underscore to
separate component words, except as indicated above.
Underscore as Prefix and Suffix
All non-const class data members (public and private) and all
non-const global variables are suffixed with underscore. All function
arguments passed as variable parameters (non-const pointer or
reference) are prefixed with underscore. Do not use a leading or
trailing underscore in any other context. The purpose of this
convention is to highlight when assignment to a symbol will affect an
object of non-local scope.
A function argument passed as a non-const reference may not be a true
variable parameter; in such cases the prefixed underscore is not
appropriate and should not be used. This may occur in cases where the
compiler will not permit a const reference for technical reasons. For
instance, a class may change its state during use in ways that are not
intended to be perceptible to the user, but because it does change its
state during use it cannot be passed as const.
Prefix Code Letters
All global variables and enumerators are prefixed with the letter g,
which must precede any other prefix codes. This is the only
mandatory prefix code other than the sx prefix. Other codes are
optional and usage will vary according to the individual style of the
programmer. Prefix code letters are never capitalized and may be
combined in any order (provided that g, if present, is first). In
variable parameter names the leading underscore precedes all prefix
codes (note that prefix code g may not be used in function argument
names). Unlike the sx prefix, prefix codes do count as the
non-capitalized first letters of a non-type symbol. Programmers
should not feel free to invent new prefix codes without first adding
them to this guide, with consent from the rest of the team. The valid
prefix codes are:
PREFIX
g |
Global (mandatory) |
n |
Number of |
p |
Pointer to |
v |
Vector of |
m |
Matrix of |
|
Examples
gDBName |
Global DB name |
gnGalaxies |
Global number of galaxies |
pMember |
Pointer to member |
vFlux |
Vector of fluxes |
pvNames |
Pointer to vector of names |
mMeanValue |
Matrix of mean values |
Combining these codes is a good way to generate very obscure names;
instead, consider using ordinary words to convey the desired meaning.
The current set of allowed prefixes intentionally excludes vowels to preclude
forming words using prefix combinations.
The following data-types have been predefined to increase portability
and for compatibility with Objectivity that defines most of these
datatypes, too.
Data Type |
Comments |
bool/char/int8 |
boolean/byte type (true/false) |
int16 |
16 bit signed integer |
uint16 |
16 bit unsigned integer |
int32 |
32 bit signed integer |
uint32 |
32 bit unsigned integer |
int64 |
64 bit integer |
float32 |
single precision float |
float64 |
double precision float |
char[n] |
string (array of n bytes) |
Tools.h++
Note The Use of RW Tools is NOT RECOMMENDED. RW was
chosen to be used in SX because of many portability issues, especially
to Windows NT. However, these very portability issues turned out to be
a pain rather than an advantage. Do not use RW where you can do without.
The only recommended use of RW is in two categories: Threads++ for
multithreading and Net++ for socket communications. In these cases,
portability to NT justifies their usage.
Do not use RW vector, list, etc. classes. Use the homemade ValVec and
PtrVec templates instead.
General Information
Rogue Wave Tools.h++ classes are grouped into four categories:
Utility Classes, Template based classes, Smalltalk like classes, and
Generic Collection classes.
To use the Smalltalk like classes, the new class must inherit from
RWCollectable. The derived objects are then collected through their
pointers to this common base class. The generic collection classes
mimic templates through the use of preprocessor macros. This can make
debugging difficult. As a result, unless absolutely necessary, the
utility and template based classes are the recommended subsets of the
tools.h++ library.
Template Types
Template collections take three forms within the tools.h++ library:
Intrusive Lists (Isv), Value-Based (Val), and
Pointer-Based (Ptr).
Intrusive Lists:
- List Members supply Link Semantics through Inheritance.
- Actual Object is placed into Collection.
- Optimal in Runtime Efficiency, Compact.
- Object can exist in only one Collection.
Value-Based Collections:
- List Members separate from Link Semantics.
- Distinct copy of Object placed into Collection.
- Collections can become Large.
- Object can exist on Multiple Lists.
Pointer-Based Collections:
- List Members separate from List.
- Address of Object placed into Collection.
- Compact Representation.
- Efficiency suffers due to Pointer Aliasing.
- Object can exist on Multiple Lists.
Types of Template Collections
- Singly Linked Lists (Iterator)
- Doubly Linked Lists (Iterator)
- Hash Dictionary (Iterator)
- Hash Set
- Hash Table (Iterator)
- Ordered Vector
- Sorted Vector
- Vector
- Queue
- Stack
- Virtual Array
Utility Classes
- RWBench
- Automate Benchmarking Process
- RWDate
- Represent Date
- RWTime
- Represent Time
- RWTimer
- Measure elapsed CPU Time.
- RWCString
- Single Byte Character String
- RWCSubString
- Address subsection of RWCString
- RWCTokenizer
- Tokenize RWCString
- RWCRegexp
- Regular Expression For use with RWCString
- RWBitVec
- Bit Vector, "Flag"
Net.h++
General Overview
Rogue Wave net.h++ classes provide a layered, modular, open interface
to network communications. At the lowest level, the modular framework
consists of wrapping the communication system calls in resource
classes. These resource classes are then used in a more abstract
portal layer, where the actual type of interprocess communication is
unknown. The portal layer supports both formatted and unformatted I/O
stream interfaces. Unfortunately, the only supplied communication
service provided is Berkeley Sockets. However, the open design easily
allows for the inclusion of additional services, such as pipes and
FIFOs.
Overview of Architecture
- RWPortal
- This class serves as an interface class to the
communications channel.
- RWPortalImpl
- This class provides the implementation to the
communications channel.
To add communications channels, first wrap low level system
functionality in a class (RWSocket). Then create the interface by
inheriting from the Portal and the wrapped classes (RWSocketPortal),
and the define the implementation by inheriting from the portal
implementation (RWSockPortalImpl). The actual implementations can
then be interfaced to using the base class interface provided by
RWPortal.
Communication Methods
- Raw Communication through low level system calls using
recv and send.
- Formatted stream based I/O using
RWPortal(O/I)Stream.
- Format independent stream based I/O using
RWPortalStreambuf and a stream class inheriting from
RWv(i/o)stream.
General Design
Push Policy Up & Implementation Down.
- Policy
- The policy refers to the appearance of an interface,
allowable exceptions, inheritance hierarchies, and class design.
- Implementation
- The implementation refers to algorithmic choices,
communication protocols, and class implementation.
Const Design
As a general rule, use const wherever possible. Also strive to
ensure that const satisfies both the language required bitwise
constness, but also logical constness.
- Use a const reference parameter in place of value
parameter, except for built-in data types which often involve extra
overhead when passed as a reference parameter.
- Return objects by const reference rather than as
value, except when an object must be created, in which case the object
must be returned using value semantics.
- Pointer parameters should always be passed by value.
Class Design
There are two golden rules:
- Use an existing class rather than write a new one.
- If you can't use an existing class, then see rule number 1.
Additional rules:
- Don't use Patterns.
- Avoid multiple inheritance and templates
Constructors/Destructors
When writing constructor functions, use initialization rather than
assignment. Initialization is required for const data members,
and is generally more efficient. Destructors should be declared
virtual for any possible base classes.
Operator Overloading
Overload operators cautiously, do not redefine operators in a
nonintuitive fashion. Be sure to check for assignment to *this.
Class Interface
The public interface to the class should be solely through the
provided member functions. Do not allow any friend functions, use
global functions that then use member accessor/mutator
functions. Also, beware of public virtual functions as they can be
overridden in a derived class, circumventing functionality that might
be required for correct behavior. Do not place any data members in the
public interface. Explicitly disallow the use of undesired, implicitly
generated (by the compiler) member functions, by declaring the
function as private, and never providing a definition.
Source code and revision history shall be kept under CVS
management. The CVS is hosted at Fermilab.
Default Class Declaration File
Note the embedded HTML that is used by cxx2html
to
produce class documentation.
//# Filename: sxCode.h
//#
//# A Brief Description of this Files Contents.
//#
//# Author: Ani R. Thakar
//#
//# Date: October 13, 1999
//#
//#
//#
//# (c) Copyright The Johns Hopkins University 1999
//# All Rights Reserved
//#
//# The software and information contained herein are proprietary to The
//# Johns Hopkins University, Copyright 1999. This software is furnished
//# pursuant to a written license agreement and may be used, copied,
//# transmitted, and stored only in accordance with the terms of such
//# license and with the inclusion of the above copyright notice. This
//# software and information or any other copies thereof may not be
//# provided or otherwise made available to any other person.
//#
//#
//# Modification History:
//#
#!defined (SX_DEFAULT)
#define SX_DEFAULT
Include Files
Static Variables
// Forward Declarations
Forward Declarations
//
// <SUMMARY>A Short Summary of this Class</SUMMARY>
//
// Now Provide a more detailed description of this class.
// Remember that this description becomes the documented description
// of the class.
//
// If you wish to use code or pseudo-code to explain an algorithmic
// detail enclose the code comment fragment as below.
//
// <SRCBLOCK>
// sxMatrix<sxFloat64> galacticToEquatorial ;
// </SRCBLOCK>
//
Class Declaration
// When commenting the Member Functions/Constructors, be sure to place your
// comment before the code being commented.
//
// If the same comment code applies to more than one function, use the
// group comment structure.
//
// General Group Comments
// <GROUP>
// Specific Comment related to Function One
void functionOne(void) ;
// Specific Comment related to Function Two
void functionTwo(void) ;
// <GROUP>
//
Inline Function Definitions
#endif DEFAULT_H
Default Class Implementation File
//# Filename: sxDefault.cpp
//#
//# A Brief Description of this Files Contents.
//#
//# Author: Peter Z. Kunszt
//#
//# Date: October 13, 1999
//#
//#
//#
//# (c) Copyright The Johns Hopkins University 1999
//# All Rights Reserved
//#
//# The software and information contained herein are proprietary to The
//# Johns Hopkins University, Copyright 1999. This software is furnished
//# pursuant to a written license agreement and may be used, copied,
//# transmitted, and stored only in accordance with the terms of such
//# license and with the inclusion of the above copyright notice. This
//# software and information or any other copies thereof may not be
//# provided or otherwise made available to any other person.
//#
//#
//# Modification History:
//#
Default Makefile
The makefiles used for the SDSS Science Archive are implemented using
perl. We have a proprietary script, sxmake and sxMakeFilter, that take
care of compiling the code.
Avoid Templates wherever possible.
General Information
Template Functions and Classes are useful methods for constructing
container classes that are easily designed and implemented, while
maintaining static type checking and run-time efficiency.
Objectivity v5.1 supports the use of templates. Additionally, the
Rogue Wave Tools.h++ template based classes are used within the
Science Archive Software, while Rogue Wave Net.h++ uses templates
within its implementation.
Template Examples
- RWTBitVec<43>
- Create a bit vector that is 43 bits long.
- RWTPtrOrderedVector<sxFloat64>
- Create a Pointer Based Ordered Vector of doubles.
- RWTValSlist<RWDate>
- Create a Value Based Singly Linked List of Dates.
- RWTIsvDlistIterator<RWCString>
- Create an iterator for traversing an Intrusive doubly
linked list of strings.
- RWStack<sxInt32, RWTValOrderedVector<sxInt32>>
- Create a stack of integers using a Value Based Ordered Vector.
General Information
The Exception Handling Mechanism provides a powerful method for
handling errors while attempting to maintain the state of the
process. One of the main concerns, however, is with resource
acquisition/exhaustion. Essentially, the problem is controlling
resource leaks, which can arise when a resource is allocated, and an
exception arises before it can be initialized. For example, when opening
a socket connection, if the connection process throws an exception,
the socket resources will not be released as the throw will circumvent
any error detection code that follows.
The optimal solution to this problem is to wrap all resource
allocations in a class with a destructor that properly releases the
acquired resources. Thus to acquire a resource, one constructs an
appropriate object. When the object's destructor is called, the
resource is released to the system. Formally, this technique is
referred to as "Resource Acquisition is Initialization". Within the
SDSS Science Archive System, it is an error to allow exceptions to
produce resource leaks.
One should not take the idea of using exceptions for error handling
too far. It is generally recognized that it is extremely hard to
recover from unexpected errors, and that the exception mechanism adds
its own layer of subtle issues. There will be certain natural control
boundaries in any program, where arbitrary exceptions may be caught
and handled reliably. There will also be situations in many programs,
where a specific exception can be handled reliably. For the most
part, however, exceptions should be treated as a better way to report
an unusual or unexpected error.
Guidelines
prototyping
-
The language provides a syntax for specifying what exceptions a
function may throw as part of its interface. If a function does not
specify its exception interface it is assumed to be capable of
throwing arbitrary exceptions. However, if a function does specify
any exceptions that it may throw, it is assumed to throw no others.
The consequence of a function throwing an exception not specified in
its prototype is (by default) termination of the application via the
unexpected() function. In practice the only way for a programmer to
avoid this highly undesirable outcome is to wrap all function
definitions in a handler for arbitrary exceptions. Further, the lack
of compiler support for function-try blocks restricts the programmer's
use of initializers in constructors. We conclude that specifying the
exception interface of a function as part of its prototype places too
great a burden on the programmer, at least given the current state of
the C++ library and other third-party products. Science Archive
functions should not prototype their exceptions unless there is a very
good reason to do so, and the programmer really has gone that extra
length to avoid needless termination of the application.
throwing
-
There is no clear rule for when to throw an exception versus when to
return an error code of some sort. Generally, exceptions should be
reserved for problems that are not supposed to happen. A reasonable
rule-of-thumb is: if most programmers, when calling your function, are
unlikely to bother checking that it succeeded, then specify no return
value (void) and throw exceptions. However, if there is a very real
expectation that your function will be unable to perform its nominal
task, then failure should be indicated through the formal
interface.
There is also a nebulous category of functions which do have ordinary
modes of failure, but for which returning an error code would simply
be inconvenient. Typically such functions return a type that has no
natural invalid value. The error code must then be passed as a
variable argument, which may be viewed as a pedantic encumbrance upon
the function's interface. There is value in creating an ergonomic
interface, and the choice between exceptions and error codes should be
decided on the basis of how the function is used.
We recommend the use of exceptions in constructors when an object is
rendered unusable by an error. Otherwise, more traditional techniques
are probably appropriate. Destructors should never throw exceptions,
and should be written to avoid the possibility of indirectly raising
an exception. This is important because destructors get called as an
exception propagates up the call stack, and raising an exception while
another exception is being handled causes the application to abort.
Science Archive functions should throw exceptions derived from class
sxException. This class is itself derived from
std::exception, the base of all exceptions from the Standard
C++ Library. A small kit of basic general-purpose Science Archive
exceptions is provided by the sxGeneral package. See sxException.h.
Programmers should feel free to derive their own exceptions when
greater specificity is required.
catching
-
All Science Archive applications are required to enclose the body of
main() in a handler for objects of type exception and at least
print the exception's message. Whenever an exception is caught, the
programmer should assume that it contains a message of diagnostic
value. By the same token, exceptions should always be constructed
with as useful a message as can be provided conveniently. If a
handler rethrows an exception, it should not also print the message.
All library functions should avoid printing to stderr, even when it
seems like a good idea (or else add a verbose switch to the
interface). Exceptions provide a mechanism for preserving the text of
a useful diagnostic while delegating responsibility for output to the
application.
int main()
{
try { ... }
catch (exception &x) {
cerr << "EXCEPTION " << x.what() << endl;
return 1;
}
}
General Information
In order to reduce the work involved in porting and maintaining the
Science Archive Software, certain guidelines must be followed.
When implementing a class, test code must also be written that tests
all non-virtual constructors, destructors, and member functions. This
test code will be checked into the cvs repository along with the
actual module source code. Any time that a CVS checked in code is
modified, as with a bug fix, the modifications must be clearly
commented in the modification section of the files header comment
section. The Total Coverage Analysis log should be considered part of
the module and checked into the repository. In addition,
decladebug
, a DEC C++ version of dbx
, will
be used for all traditional run-time debugging.
Insight
Insure++ is a source code level commercial debugger/test package. At
compile time, insure++ provides lint-like error checking, retaining
extra information for run time debugging. At run time, additional
errors are caught and the retained information is provided to reduce
the guesswork involved in identifying errors. During the execution of
a program, a log is maintained of the actual lines of code that were
executed. This provides a coverage analysis that aids in reducing
hidden bugs and untested code. An additional tool, inuse, monitors
memory allocation/deallocation while a process is executing to
identify memory leaks.
insure++ is automatically used when the debug tag is used with make.
An HTML document is composed of a single <html>
... </html> element, which is composed of a head, <head>
... </head>, element and a body, <body> ... </body>
element.
As new additions (eg. math notation) to the HTML language
become standardized, these features will be included in the acceptable
html elements section after review. All standard element attributes
(eg ALIGN = CENTER) are by default included within the required
HTML constructs.
Html Head Elements
- <ISINDEX>
- Indicates this document describes a searchable database.
- <TITLE> ... </TITLE>
- The Title For the current document.
- <BASE HREF = "URL">
- Provides an absolute URL to which all relative URL's are appended.
Html Body Elements
- <BGCOLOR>
- Specify Background Color.
- <TEXT>
- Specify Text Color.
- <LINK>
- Specify the Link Color.
- <VLINK>
- Specify the Visited Link Color.
- <ALINK>
- Specify the Active Link Color.
-
Text Elements
-
- <BR>
- Indicate Line Break.
- <P>
- Indicate Paragraph End.
- <PRE> ... </PRE>
- Display Pre-formatted Text. Embedded HTML will be
recognized.
- <XMP> ... </XMP>
- Display Pre-formatted Text. Embedded HTML will be
not recognized.
- <BLOCKQUOTE> ... <BLOCKQUOTE>
- Display quoted text.
-
Hyper-Links
-
- <A NAME = "ANCHOR">
- Define a named anchor within a document.
- <A HREF = "#ANCHOR">
- Define a link to a named anchor within the document.
- <A HREF = "URL">
- Define a link to another document/resource.
- <A HREF = "URL#NAME">
- Define a link to a named anchor in another document.
-
Headers
<H#></H#>
- # is a number from one to six, with one being the most
prominent. The header numbering should be strictly followed to
simplify the document conversion process.
-
Logical Styles
-
- <EM> ... </EM>
- Emphasis.
- <STRONG> ... </STRONG>
- Strong Emphasis.
- <CODE> ... </CODE>
- Display an HTML Element.
- <CITE> ... </CITE>
- Display a citation.
-
Physical Styles
-
- <B> ... </B>
- Boldface.
- <I> ... </I>
- Italics.
- <U> ... </U>
- Underline
- <SUB> ... </SUB>
- Subscript
- <SUP> ... </SUP>
- Superscript
-
List Types
-
-
Definition List
-
- <DL>
- Begin Definition List.
- <DT>
- Term to be Defined.
- <DD>
- Definition.
- </DL>
- End Definition List.
-
Unordered List
-
- <UL>
- Begin Unordered List
- <LI>
- List Item.
- </UL>
- End Unordered List.
-
Ordered List
-
- <OL>
- Begin Ordered List.
- <LI>
- List Item
- </OL>
- End Ordered List.
-
Tables
-
- <TABLE> ... </TABLE>
- Begin/End a Table.
- <TR> ... </TR>
- Begin/End a new Table Row.
- <TH> ... </TH>
- Table Header.
- <TD> ... </TD>
- Table Data.
-
Keywords
-
- &keyword
- Represent Keyword: &, <, >
Default html Implementation File
<!--DOCTYPE HTML PUBLIC -->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Peter Kunszt">
<title>Title of this document</title>
<base href="http://www.sdss.jhu.edu/">
<!--
Author: Peter Z. Kunszt
Created: October 16, 1999
Notes: Comments are appreciated.
-->
<!-- Changed by: Ani R. Thakar, 17-Oct-1995 -->
</head>
<body text="#111111" bgcolor="#FFFFFF" link="#333399" vlink="#663366" alink="#CC0000">
<h1>
<img src = "images/sx/sxlogo1.gif">
<font color="#7700EE">Title of this Documnet</font></h1>
<img src="images/bars/rule.gif" >
<h2> Section Title</h2>
<p>
Your Text comes here
<h2> Section Title</h2>
<h3> Subsection Title</h3>
<img SRC="images/bars/rule.gif" >
<h6>
©
<A HREF = "copyright.html">
Copyright
</A>
The Johns Hopkins University 1999, All Rights Reserved.<br>
<a href="mailto:kunszt@pha.jhu.edu">Peter Z. Kunszt</a>,
<a href="mailto:thakar@pha.jhu.edu">Ani R. Thakar</a>,
<br>
Last Modified: October 14, 1999.
</h6>
</body>
</html>
When formal documentation is required, the html documentation will be
converted into Latex, or Postscript as needed.
HTML To Latex
htmlatex.pl -> Perl script.
HTML To Postscript
- html2ps -> Perl script.
- Netscape Print Postscript to File.
References
Keffer, Thomas, C++ Design, Implementation, and Style Guide,
Rogue Wave Technical Report 94-02.
Meyer, Bertrand, Object-Oriented Software Construction,
Prentice Hall International
Stroustrup, Bjarne, The C++ Programming Language,
2nd ed., Adison-Wesley.
©
Copyright
The Johns Hopkins University 1999, All Rights Reserved.
Peter Z. Kunszt,
Ani R. Thakar,
Initial Document: Robert J. Brunner, 1995
Last Modified: October 16, 1999 [PK]