Data Driven Software Design

Due to the importance of object oriented design in software engineering, most developers believe that objects are the holy grail of software systems. However, despite the usefulness of interfaces provided by objects, I believe that there is something even more basic that we should look for when designing a system.

To see this, we may first take a look at how object oriented languages make us think about design.

The grand idea of OO is that behavior of individual objects and their interactions with other objects is the most important aspect of the system. Therefore, a lot of time is spent in finding the right interfaces and the best class hierarchy to represent these behaviors and relationships.

While this is a sensible way of start investigating a system, OO may lead you into wrong decisions down the line. This usually happens in the implementation phase, because it causes developers to stop thinking of software in terms of data and start thinking just about behavior and object interaction.

Deficiencies of Code Behavior

The problem with using behavior instead of data during the implementation of a system is that (outside the helm of high level interfaces) behavior is transitory, while data usually is not.

In other words consider the following example: a system determines how to go from point A to point B. The necessary steps for this transition can change a lot. But the information I have at the beginning of the process will not change. Similarly, the end point will be defined by the data, not by the path used by the system to reach that point.

So, looking exclusively at behavior in a system is the same as prioritizing the way things currently work, instead of the desired results. The moment you create an object that provides operations x, y, and z, you specify behavior. If you create a class hierarchy it gets even worse, since it has the combined behavior of a set of classes. Changing the parent class now requires similar changes to dozens of files.

However, unless this is a high level interface to a subsystem, I shouldn’t care what the behavior of the object is. I should only care about the input and output data that is defined as part of my programming contract.

Looking at this from the point of view of functional programming, one see why it is so appealing compared to object oriented programming: what I described above is exactly the functional view, where the only thing that matters is the transformation of input into output.

By the way, this also explains why UNIX systems are so pervasive, even though its implementation is in terms of simple imperative code. High level interfaces are defined by top level commands: the input (parameters) and outputs (what they’re supposed to return). This is the interface. The internals of a UNIX command, though, are just procedural C code operating on the data provided. It is quick (and sometimes dirty) but always does the job.

This approach of software development is not very difficult to adapt, even with object oriented languages, once a good design is in place.

This could be done in C++, for example, by writing OO interfaces only for the major subsystems. This would be the equivalent of a creating set of UNIX commands that cooperate to perform well defined tasks. The internals of such classes would be defined by the available data, without the need of encapsulation provided by objects unless necessary for clear reuse cases (for example, logging subsystems, UI subsystems, etc.)

Summary

Object oriented programming makes us think in terms of responsability and state of objects. However, when we want to implement concrete functionality, data is more important than behavior because data is a better representation of what needs to be done. While behavior can change based on how the system interacts with the environment, properties of the suplied data are immutable.

Clearly, there are situations when behavior is more important than data, but object oriented systems try to see this as the only possibility. I think that programmers should start to use the right abstraction when necessary, instead of holding only one tool for all jobs. Therefore, we should start to think more about when it makes sense to view data as the main aspect of a system. We will end up seeing a lot of places where this makes systems more robust and easier to implement.

Further Reading

Pearls of Functional Algorithm Design is a very solid book explaining how to design algorithms in a functional style

The Functional Approach to Programming is another book that explain the nuts and bolts of writing functional code.

Similar Posts:

About the Author

Carlos Oliveira holds a PhD in Systems Engineering and Optimization from University of Florida. He works as a software engineer, with more than 10 years of experience in developing high performance, commercial and scientific applications in C++, Java, and Objective-C. His most Recent Book is Practical C++ Financial Programming.

Post a Comment