Below we discuss ramifications of physical coupling on the Event model along with concrete examples of some design choices.
Since the Event model will evolve over time as new data types
and algorithms are developed, we would like changes to the Event
model to not cause clients (classes which use the Event
class) to require recompilation unnecessarily. In a poorly physically
designed Event model, adding a new data type to be stored or a
making tiny change in a low level class (e.g. Jet)
could cause all clients of the Event class
to require recompilation, which would slow development and testing
to a crawl. Changes to the Event Model that can cause clients
to require recompilation include:
Event class interface and/or implementation
(if the Event class header file is changed).
In addition, even if compile-time coupling is kept low, the Event model could cause large link-time coupling so that using or testing a low level class could require linking with a significant number of classes in the Event Model (and with other classes, perhaps not normally thought of as part of the "Event Model"). This is the situation we had in Run I, in which testing involved linking the entire system, rather than small units. In C++, link-time coupling occurs when some part of the Event model uses the interface or implementation of a class, rather than knowing about the class in name only (see below for a definitions of terms, taken from "Large Scale C++ Software Design" by John Lakos. For more information on physical coupling, read this book).
Any change in the Event class's interface or implementation as
contained in Event.h, causes all clients of
Event to require recompilation.
Event.h:
// Version 1: Event contains Tracks and Vertices only
// Version 2: added PreshowerHits data and accessor function
// Version 3: added getTracksInVertex accessor
class Event {
public:
Tracks* getTracks() const; // V1
Vertices* getVertices() const; // V1
PreshowerHits* getPreshowerHits() const; // new in V2 (all clients of Event class must be recompiled)
Tracks* getTracksInVertex() const; // new in V3 (1 day later...recompile again)
private:
Tracks* _tracks;
Vertices* _vertices;
PreshowerHits* _psHits; // new in V2
}
One way to insulate clients from this sort of change is to add
layers between the Event class and the data it contains
and provide accessors only to the sublayers rather than the data
itself. This layered approach can be use at several different
levels create a highly modular and decoupled Event Model.
Another solution is for the Event class to contain
a pointer to a generic data type which is "cast" to
the correct type (at least, one hopes it is cast to the correct
type!). In this way clients of the event are insulated from the
specific types of data held by the Event class and
conceivably only one accessor is ever needed.
If Event.h needs headers (like Tracks.h)
for the data it holds, any change in those headers will cause
all clients of the Event class to require
recompilation. Also, if either the header file for Event
or implementation file (Event.cc) needs headers,
all clients of Event must be linked with the
object file (like Tracks.o), even if the client never
uses the class.
class Event {
public:
// Changing the definition of Tracks does not cause the Event class
// or its clients to require recompilation. However, it could cause a link-
// time dependency if a member function of Event (1) uses the Tracks class
// interface or (2) returns a Track by value (not pointer or reference)
Tracks* getTracks1(); // Neither ptr nor ref force inclusion of Tracks.h.
Tracks& getTracks2(); // Neither causes a link dependency: Event.c doesn't need Tracks.h
Tracks getTracks3(); // Doesn't require Tracks.h.
// Link dependency from return by value in Event.c
float getATrackPt(); // Causes link dependency due to Event.c needing Track.h
float getATrackZ() // Inline function requires Track.h: Compile & link dependency
{return _trks1->track(1)->z();}
private:
// In member data, pointers and references do not cause compile-time and
// link-time coupling, but containing by value typically does.
Tracks* _trks1; // Doesn't require Tracks.h
Tracks& _trks2; // Doesn't require Tracks.h
Tracks _trks3; // Requires Tracks.h
RefCntPtr<Tracks> _trks4 // Requires Tracks.h due to template instantiation
VertexList _vert; // Requires Vertex.h (which requires Tracks.h)
}
Member functions of the Event class can return objects
by value, pointer or reference, without causing a compile-time
dependency, but returning an object by value (like Tracks)
requires that the Event link with the component object
file (Tracks.o). Inline functions typically expose
implementation detail in the header file thus causing compile
and link dependency.
Member data contained by pointer or reference causes no compile or link dependency, but containing by value causes both a compile and link dependency. In addition, containing by value can cause a cascade of dependencies to many other classes.
In short, the smallest change in the Event class
interface or attributes can cause all clients (classes, functions,
etc.) that use the event interface to require recompilation. This
is called a compile-time dependency or coupling. Thus adding a
list of muon clusters to the event would provoke recompilation
of all reconstruction code and analysis code that used the Event
class.
Another aspect is that any client that uses any part of the Event
interface may require all classes contained in the event to link.
This is called link-time dependency. A variation of this is that
any client that uses a class (e.g. Jet) independent
of the event may still require all classes within the event to
link if the class uses the Event in name (not the
interface). A severe variation is the cyclic link-time
dependency, in which one class (or a small set of classes) cannot
be tested without linking in all the others in the cycle.
Back to Run II Event Model/Algorithm Considerations
Back to Run II Event Data Model Home Page
Back to Back to DØ Home Page
This page is kept by Marc Paterno (paterno@fnal.gov) and Brent May (bjmay@fnal.gov)
Last updated 4 April 1997.