Observer Pattern in C

May 18th, 2008 Posted in Design Patterns | Comments

More interesting software systems are complex, and the implementation of complex software typically requires multiple developers. The introduction of additional developers increases software complexity, which requires the software design to provide for software components that are resilient against change. Functional behaviors or component dependencies, such as the need for one component to recognize that another component has been acted upon, are sometimes recognized. This is an opportunity for exercising good design.

When encountering a relationship where it is necessary for one component to know that an operation has been performed on another component, there may exist a temptation to simply couple one component with the other. This coupling can be implemented in C by the use of a global flag or a hard-coded function call from the “observed” component to the specific “listener” or “observer” component. There are at least two problems with these approaches.

Global variables, including global flags, are generally a bad idea. The use of a global flag to convey that an event has occurred in the observed component to an observer component raises concerns over the management of the global flag. In the simplified case of an observed component being observed by a single observer component, the responsibilities of setting and clearing the flag can be distributed between the observed and observer. The distribution of the responsibilities becomes problematic when there are potentially many observers. In a situation where the order of the observer components that inspect the flag is potentially random, a problem may arise where an observer component clears or causes the observed component to clear the flag before other observer components are able to inspect the flag and act on its value.

A hard-coded call from the observed component to a function that is provided by the listening component requires that the observed component is knowledgeable of the listening component’s interface. Though recognition of the observed component’s need of a mechanism to notify an observer component may have resulted through the design of an initial observer component, it is worthwhile to consider the possibility that there may be other software components that want to observe the observed component. Some observer components may be designed after the observed component has been implemented and finalized. A hard-coded function call from an observed component to specific observer components cannot support the addition of new observer components.

Recognizing during design that a software component needs to be observable is important. This allows the designer to employ the Observer Pattern as described in Design Patterns: Elements of Reusable Object-Oriented Software. The designer of an observable software component shall provide an interface for observing software components to subscribe to the observable software component’s notification mechanism.

An example of an observable component and two observer components are presented here in C. One observer component will act on the notification from the observable component immediately, while the other observer component will wait until one of its interface functions is called.

/* observed component */
typedef struct
{
  int listener_count;
  /* array of function pointers */
  void (*listener_list[10])(unsigned,unsigned);
} Button;

void button_Init( Button *pButton )
{
  pButton->listener_count = 0;
}

void button_RemoveClickListener( Button *pButton,
                                 void (*fp)(unsigned,unsigned) )
{
  unsigned i;
  void (*temp)(unsigned,unsigned);

  for( i = 0; i < pButton->listener_count; ++i )
  {
    if( pButton->listener_list[i] == fp )
    {
      pButton->listener_count--;
      pButton->listener_list[i] =
        pButton->listener_list[pButton->listener_count];
    }
  }
}

void button_AddClickListener( Button *pButton,
                              void (*fp)(unsigned,unsigned) )
{
  button_RemoveClickListener( pButton, fp );
  pButton->listener_list[ pButton->listener_count++ ] = fp;
}

void button_Click( Button *pButton, unsigned x, unsigned y )
{
  unsigned i;
  for( i = 0; i < pButton->listener_count; ++i )
  {
    pButton->listener_list[i](x,y);
  }
}

/* observer component 1 */
void observer_OnClick( unsigned x, unsigned y )
{
  printf( "observer_OnClick( 0x%X, 0x%X )\r\n", x, y );
}

/* observer component 2 */
bool observer2_isClickEventHandled = true;

void observer2_OnClick( unsigned x, unsigned y )
{
  observer2_isClickEventHandled = false;
}

void observer2_Action()
{
  if( observer2_isClickEventHandled )
  {
    printf( "observer2_Action(): no click event to handle\r\n" );
  }
  else
  {
    printf( "observer2_Action(): handling click event\r\n" );
  }
  observer2_isClickEventHandled = true;
}

/* system */
int main()
{
  Button button;

  /* system initialization */
  button_Init( &button );
  button_AddClickListener( &button, observer_OnClick );
  button_AddClickListener( &button, observer2_OnClick );

  /* system operation */
  observer2_Action();

  /* more system operation */
  button_Click( &button, 1,3);

  /* and more system operation */
  observer2_Action();
  observer2_Action();
}

The Button component in the example code is observable. The Button component provides an interface that allows observer software components to add themselves as the Button component’s observers. To be a compatible observer in this example, a software component must provide a function that returns void and takes only two unsigned integers as parameters. The overall software system will be responsible for associating the observing components with the observed components, or the observing components can register themselves with the observed components during the observing components’ initialization routines.

Some software development shops may consider function pointers taboo. Instead of passing a function pointer to the registration function (”button_AddClickListener” in the example), a pointer to a flag variable that resides within an observing software component can be used. In this way, each software component is able to have its own copy of the notification, which it can manage in a way that is solely dependent on its implementation. This mechanism is more robust to change and the effects of other software components as it overcomes the problems of using a global flag or hard-coded function call to implement a method that allows a component to notify other components of an event.

Observer Pattern in C
Comments »
 

The Necessity of Securing Backups

April 26th, 2008 Posted in Security | Comments

Another case of lost backups has recently been featured on the pages of Slashdot. Let’s just hope that the “proprietary compression and encoding tools” place the strength of their cipher on a key, rather than a proprietor’s secret cipher algorithm. The article seems to suggest that third-party security consultants were unable to decipher the data because of proprietary software. A reasonable person should wonder if these consultants may have been able to decipher the data, if they had access to the backup system’s proprietary technical information. A better test of the backup’s security provides such information to third-party consultants. Since people who have had exposure to the proprietary technical information are potential adversaries to the data’s security, the provision of the technical information strengthens the testing of the data’s security.

Not that strong ciphers are unbreakable, rather, all that is needed for success is some combination of computing power and time.

The Necessity of Securing Backups
Comments »
 

Gym? I Hardly Know Him

April 10th, 2008 Posted in Personal Development | 1 Comment

24HourFitnessIf the definition of “computer specialist” can be stretched to include software engineers, then software engineering qualifies for Heather Boerner’s list of America’s Surprisingly Unhealthy Jobs. Though Boerner states that computer specialist jobs are associated with issues of ergonomics and her article appears to equate unhealthiness merely with injury, it is worth considering a sedentary work environment as a source of other health issues.

I have been developing software for more than full-time over the past two years. My day typically consists of working in front of a computer with some breaks for personal upkeep, which includes things like eating and sleeping. Unfortunately, physical activity was not included in my upkeep. It can be said that I’ve consumed a lot of calories or energy units without actually using them, and my body has been storing them daily in its own way.

I was looking to join a gym at the start of the year. The prices at that time were very high. The gym that is most convenient to me was charging and continues to charge above 50USD per month. That’s about 600USD per year, with some of it due at initiation. People can debate the value of my health and assign it a worth greater than 600USD per year, but I really could not make such a big financial commitment. The expense was just not financially feasible. So, I fished for a deal. I monitored the 24 Hour Fitness site on Mondays for the deals that they make available for only four hours, and I snapped up a deal for a year of membership at 200USD. That’s just about 17USD per month and is about the same amount that I would have paid at initiation for the club’s normal membership pricing.

I go to the gym every other day on average over the week. My workouts are fairly consistent. As it is early in my membership, I may decide to vary my routine at a later time. The current goal is to raise my heart rate and keep it high for a set period of time, and maybe burn some calories. I want to be able to eat what pleases me, but with some exercise, I hope to be able to slow the rate that my body stores the unused energy that I consume.

Gym? I Hardly Know Him
1 Comment »
 

Trade Secret Protection

March 14th, 2008 Posted in Legal | 1 Comment

According to Classen’s A Practical Guide to Software Licensing for Licensees and Licensors, the following phrase may be helpful in marking an item as subject to contractual proprietary information clauses and agreements:

Proprietary and Confidential, © Copyright [Company Name] all rights reserved. (Classen 141)

Trade Secret Protection
1 Comment »
 

Data Hiding in C

March 2nd, 2008 Posted in C++, Software Engineering | Comments

Object-oriented programming languages are described as supporting encapsulation, polymorphism, and data hiding. They provide powerful features that allow software components to be designed and implemented for change.

Observing the mechanisms in an object-oriented programming language can potentially lead to a parallel implementation in a procedural language. This allows some object-oriented design knowledge that has been refined through study and experience to be implemented in procedural languages such as C.

A Circle type is a typical classroom example of a user-defined data type. Getting an area or circumference are common operations performed on instances of a Circle type. In C++, a Circle type may be defined as follows:

class Circle
{
  double radius;

  public:
    Circle()
    {
      // not using init list here to make parallelism
      // with example C code more easily seen
      this->radius = 0;
    }

    void setRadius( double r )
    {
       this->radius = r;
    }

    double getRadius()
    {
       return this->radius;
    }

    double getCircumference()
    {
       return 2 * PI * this->radius;
    }

    double getArea()
    {
       return PI * pow( this->radius, 2 );
    }
};

Member functions, which are functions that are called to operate on objects, in object-oriented languages tend to have a reference or pointer, which may be implicit or explicit, to the object on which the function operates. The use of a struct and functions that accept a pointer to the struct instances provides similar behavior in C. C code that mimics the example C++ code is presented here:

typedef struct
{
   double radius;
} Circle;

void circle_construct( Circle *c )
{
  c->radius = 0;
}

void circle_setRadius( Circle *c, unsigned r )
{
  c->radius = r;
}

double circle_getRadius( Circle *c )
{
  return c->radius;
}

double circle_getCircumference( Circle *c )
{
  return 2 * PI * this->radius;
}

double circle_getArea( Circle *c )
{
  return PI * pow( this->radius, 2 );
}

An association between the functions and the data, which is accomplished through encapsulation in the C++ code, is made in the C code through a coding convention. The convention here directs the form of the function signature to be as follows:

returnType typeName_operationName( params )

Data hiding is accomplished by another coding convention. Instead of dependents on Circle objects operating directly on the Circle objects’ fields, the dependents shall only call functions that manipulate the object on behalf of the dependents.

Code that is dependent on Circle objects as implemented in C is presented below:

Circle c;

circle_init( &c );
circle_setRadius( &c, 3 );
printf( "%f", circle_getRadius( &c ) ); /* "3.0" */
printf( "%f", circle_getCircumference( &c ) ); /* "18.85" */
printf( "%f", circle_getArea( &c ) ); /* "28.27" */

circle_setRadius( &c, 4 );
printf( "%f", circle_getRadius( &c ) ); /* "4.0"  */
printf( "%f", circle_getCircumference( &c ) ); /* "25.13" */
printf( "%f", circle_getArea( &c ) ); /* "50.26" */

The above code is more insulated from change than code that accesses the Circle fields directly. A field for the circle’s color and functions that operate on that field can be introduced, for example, and the above code has a good chance of not requiring modification while having its behavior remain unchanged. Ignoring the possibility of floating-point approximation errors, as another example, the internal representation of the Circle type can be overhauled completely by changing the radius field into a field containing the circumference of a circle and modifying the associated functions appropriately, and a necessity of change in the above code remains unlikely. The ability to change the representation of a data type without modification to dependent code evidences this technique’s effectiveness in making code resilient to change.

Parallels to the idioms and adages of languages like C++ can be implemented in C. By mimicking the natural mechanisms of object-oriented languages. the benefits of those features can be introduced in procedural languages where such mechanisms are neither directly supported nor idiomatic.

Data Hiding in C
Comments »