The Artima Developer Community
Sponsored Link

Guideline 1
Interface Design by Bill Venners
Appreciate the significance of the object


Interface Design | Contents | Previous | Next

Objects are for people, not for computers. The point of objects is not to help computers run software, but to help people develop software. Computers are just as happy running assembly language programs as object-oriented programs. But people are happier writing object-oriented programs. OK, if not always happier, then hopefully at least more productive. The main aim of advances in software technology, from machine language to assembly to procedural languages to object-oriented languages, has been to help programmers do their jobs. In particular, objects help programmers manage complexity and change in their software.

Managing Complexity

Moore's law says that computer hardware doubles in capability and halves in price every 18 months. For programmers, this is good news and bad news. The good news is that programmers get ever more blazing machines to work with. The bad news is that as hardware becomes cheaper and more powerful, software becomes larger and more complex. One of the main ways objects assist programmers is in helping them manage the increasing complexity of software.

A well-designed object is understandable. Large software systems are difficult to understand. If a system is composed of individual object pieces, however, each object can embody an amount of complexity that can be fully grasped. Programmers can then understand the behavior of the system as a whole in terms of the behavior of its object pieces and the interactions between them.

Every object you design, therefore, should encapsulate an amount of complexity that can be readily grasped by human programmers. During an object-oriented design, you divide the requirements of a system into areas of responsibility. You assign each area of responsibility to a class of object, and give each class a name. For each named class, you devise a bundle of services (each service offered by a method) through which the instances of that class fulfill their responsibilities. By giving each object a focused area of responsibility that encompasses a reasonable level of complexity, you help programmers who use your objects deal with the overall complexity of their systems.

Understanding is further helped by the tendency for many classes to be named after relevant objects or concepts from the problem domain, such as Account, Matrix, or StampDispenser. To the extent that classes model familiar real-world objects and concepts from the problem domain, programmers may find it easier to understand and use instances of those classes. Moreover, programmers may also find it easier to comprehend object-oriented systems because the organization of object-oriented systems is somewhat similar to the organization of human endeavors. If you have some goal, you can hire people to help you achieve that goal. Each person agrees to play some role, perform some job, and you organize and direct their individual efforts to help you achieve your overall goal. Similarly, to accomplish some goal in a system, you enlist the help of objects, each of which is expected to fulfill the obligations delineated in their contract. By organizing and directing the services provided by the objects, you can achieve your overall goal for the system.

In addition to being understandable, an object is also discussable. Every class of object has a name. To the programmers working on a system, an object's class name comes to mean the object's area of responsibility and the set of services through which the object fulfills its responsibility. As the members of a development team discover, name, and define objects during an object-oriented design, a vocabulary develops. This vocabulary, made up of class names and their meanings, facilitates communication among the programmers working on the system. The more effectively programmers are able to communicate about their system, the more effective they will be at taming its complexity.

Lastly, objects are debuggable. When you organize your system with objects, you tend to encapsulate code that manipulates particular data inside the object that contains the data. This keeps code that operates on particular data from being replicated and spread throughout the system. If a bug is detected that causes certain data to become corrupt, programmers need only look in one place to find the bug: the code that defines the object's methods. Once that bug is fixed in the object's code, you know it is fixed everywhere, because the object's code is the only code that can manipulate the data. This process of encapsulating code with data in objects, combined with a strong separation of interface and implementation, helps programmers build objects that are thoroughly debugged and, therefore, reliable and robust. I have found in my own development experiences that achieving a robust system requires constructing the system out of robust parts. Therefore, objects help programmers build systems that, despite their overall complexity, are robust because their systems are constructed out of robust object parts.

Managing Change

Besides complexity, the other fundamental reality of software development that programmers must wrestle with is change. If a software project doesn't fail initially, the resulting codebase tends to have a long life. With each new release comes new requirements. Existing code is tweaked and enhanced to fix bugs and add functionality. Objects, in addition to helping programmers manage complexity, help programmers manage change.

One of the main ideals in the object-oriented approach to programming is a strong separation of object interface from object implementation. The primary enemy of change in a software system is coupling, the interdependencies between the various parts of a system. The aim of keeping interface and implementation separate is to help programmers minimize coupling in their systems. At a keynote address I saw Bill Joy give in Washington, D.C., Joy described coupling by saying, "You slap your hand on this table in Washington and a building falls down in San Francisco." In other words, you make a small, seemingly innocuous change in one part of your system, and you inadvertently cause a disaster in a remote and unrelated part of your system. In an object-oriented system, object interfaces are the point of coupling between the different parts of a system. Because object interfaces are the only point of coupling between the parts, many kinds of changes can be made to object implementations without breaking the expectations of client code. When you slap the implementation of a Table object in Washington, all the buildings in San Francisco continue to stand tall.

Another way objects help programmers deal with change is that, because of polymorphism and dynamic binding, programmers can treat objects as replaceable modules. Polymorphism and dynamic binding enable you to unplug one implementation of an object interface and plug in a different implementation of that interface. This makes it easy to change a system by defining a new subclass of some superclass, instantiating the subclass, and passing the resulting object to existing code that knows only of the superclass.

Lastly, objects help programmers manage change because object contracts can be very abstract. An object's contract, the human language description of what the object promises to do for you when you invoke its instance methods, is usually couched in terms of behavior. Instance data is kept private and, as a result, the structure of the instance data does not form part of the object's contract. Contracts expressed in terms of behavior can be more abstract than contracts expressed in terms of data, simply because you can be more vague when you describe behavior than when you describe data. The more abstract a contract is, the more ways you have to fulfill the obligations outlined in that contract. The high level of abstraction at which object contracts can be expressed gives more options to programmers who need to change an implementation, or plug in a new implementation, of an interface. The higher the level of abstraction in the contract, the more freedom programmers have in making implementation changes that are compatible with the expectations of client code.

The significance of the object, therefore, is that they are for people, not for computers. The reason objects exist is to help human programmers do their jobs. This is important to keep in mind when designing APIs, because if objects are for people, then object interfaces are for people too. (After all, API means Application Programmer Interface) When you design an API, you are designing for the benefit of human programmers.

Sponsored Links

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use