Never ever break the encapsulation
In the systems theory containment a.k.a. the "poached egg" model is one of the most useful constructs dealing with large and complex system structures. In the software industry the value of containment or encapsulation is well understood, and its supported by programming language constructs such as subroutines, functions, modules, packages, objects (class) and even agents.
Agents, modules and packages addresses most often the larger scale needs for encapsulation, while objects, subroutines and functions are most often associated with the more fine granular aspects of the matter. Over the years I have discovered that objects seams to be one of the hardest encapsulation constructs for developers to get right. It's not seldom you find a class with one single 3000 line main method, or a class with only set and get methods for its primitive attributes. These examples illustrates basically that the developers has never understood object oriented thinking, and the power of objects as modeling constructs.
An object encapsulates state and behavior related to its state, and designing with objects boils down to two simple tasks: allocation and delegation of responsibility to the different objects. Lets say we have three objects, customer, order and item. The customer object is the natural placeholder of the credit limit and credit validation rules. The order object knows about its associated customer, and its addItem(item) operation delegates the actual credit check by calling customer.validateCredit(item.price()). If the post condition for the method fails, an exception is thrown and the purchase operation is aborted. This approach of organizing your code is in line with the principles of the Domain Model pattern described in Martin Fowler's book, Patterns of Enterprise Application Architecture.
A less experienced object oriented developer might decide to wrap all the business rules into an object very often referred to as order-manager or order-service. In these designs order, customer and item are treated as records and all logic is factored out of the objects and tied together in one single method. This design is in line with the Transactional script pattern, a pattern this is more an anti-pattern than a pattern. It breaks the encapsulation and results in non maintainable code. To illustrate the problem lets extend our small system with more functionality. The customers are classified as gold, silver and basic members, and different discounts are given on that basis. Extend functionality further and add discount rules that not only is derived from member status, but from how many children the customer got and so on. Think about what happens with the maintainability of your code. What initially started out as a 50 line script method has become 2000 lines inter tangled unmaintainable code.
Refactoring your objects, extending them with new methods and maintaining a consistent allocation of responsibility would have made things simple. The customer object could have been extended with a discount method, and the the order objects close() operation would have obtained the correct discount without knowing anything about membership levels or any other discount rules associated with the customer object.
So in the end, never break the encapsulation.
By Einar Landre
This work is licensed under a Creative Commons Attribution 3
Back to 97 Things Every Software Architect Should Know home page