Saturday, July 6, 2013

Design Properties

I recently encountered an object design rule of thumb to "make any expensive operation a method." Setting aside the rather elastic notion of what "expensive" means, let's examine the implications of the rule itself. Hiding beneath the surface of this seemingly sensible rubric lies a subtle permutation of that pernicious development pitfall, premature optimization. To see why, we'll need to examine some of the metaphors and assumptions used by object based languages and designs.

Object Assumptions

Informally, objects in an object based language provide mechanisms for modeling concepts within the system in terms of data with attached operations or actions, known as methods. Objects are said to be encapsulated, the idea being that the object is organized conceptually into an external interface that wraps an object's implementation details. Think of a cell: the cell membrane forms the external interface that exposes external interaction points but also encapsulates the internal machinery that makes the cell function.

http://upload.wikimedia.org/wikipedia/commons/thumb/4/48/Animal_cell_structure_en.svg/500px-Animal_cell_structure_en.svg.png

Diagrammatic overview of a typical animal cell. The cell membrane forms the boundary between the cell and the external world and houses the cell's signaling interface.

Returning to a software environment, consider a generic hypothetical list object:

fib = [1, 1, 2, 3, 5, 8, 13]

The object's data consists of the elements it contains, while its methods will provide useful operations over that data like sorting, searching, and counting.

A key assumption in object systems is that the internal details of the implementation of the object are abstracted away from its interface; client code that uses an object is concerned with what an object does and not with how it does it. Returning to the list example, we might implement a list using one of any number of techniques—a memory array, linked list data structure, or something more exotic—but the client code using a list object can query and manipulate a list through its exposed data and methods in blissful ignorance of these details.

Properties

What are properties, and how do they fit into this? Suppose we wanted to know the length of a list object:

https://lh6.googleusercontent.com/-V35szybzoao/UH87Z7WPAKI/AAAAAAAAAts/KaLs2czn5d4/s288/20121006-183927.JPG
> log(fib.length)
7

How would we model and implement this length attribute? Clearly length is a bit of data, namely a number representing the count of the items in the list. On the other hand, length is derived: it is a secondary characteristic of the primary data in a list object, its elements. Should we represent length as a data field or as a method?

fib.length or fib.count()???

Languages like Python, C#, and some dialects of JavaScript offer an alternative modeling technique: properties. A property presents an attribute externally as a data member while providing internal mechanisms (in method form) for customizing the implementation of attribute access and update. Properties serve two main object design needs:

  • exposing a data member to the outside world while retaining control within the object over how it is used (e.g. by denying write access)
  • presenting as data derived attributes whose value is computed from the object's primary data or some other source

Properties provide a way for object designers to communicate the data nature of an attribute while retaining control within the object over how that data is used.

Conclusion

So what then of the opening rubric? If properties are first and foremost a design tool, then categorically eschewing them for "expensive" operations prematurely subordinates design considerations to performance ones. Yes, performance considerations in a real-world system will shape and reshape object and system design, but such reshaping must be recognized as compromise, a secondary consideration to the prime goal of designing good systems.

No comments:

Post a Comment