Heron-Centric: Ruminations of a Language Designer OOP Case Study: The Bank Account Class (Part 2) by Christopher Diggins November 16, 2004
Summary
My previous blog entry on the bank account class, sparked some lively and interesting discussion. It also revealed two very distinct approach to object oriented programming, which I label the bottom-up approach and the top-down approach.
Advertisement
I have identified two very distinct approaches to object oriented programming, which I label the bottom-up approach and the top-down approach. I will revisit the bank account examples from an earlier post OOP Case Study: The Bank Account Class, while attempting to explain the different techniques and to show how they compliment each other.
The original problem was stated as:
represent a bank account class in code
There are two ways to interpret this, as simply as possible or as realistically as possible. Each interpretation embodies a separate design approach, which are I hope to show, compatible with each other .
The Top-Down Approach
Since the bank account example lacks sufficient contextual information we can fill in the blanks use some basic assumptions we know about bank accounts in financial institutions:
any modification to the account should done in a thread-safe manner
any modifcation to the account should be recorded as a transaction
the balance should be accesible at any given date or time
The following is an example high-level representation of what an account could be which satisfies the above requirements:
class Account {
ApplyTransaction(Transaction);
TransactionHistory GetTransactionHistory();
GetBalanceAsOf(Date);
}
Following the top-down approach, we would then continue by specifying the sub-elements (i.e. Transaction and TransactionHistory) and fill in the implementation details.
The Bottom-Up Approach
The other approach, is that we instead try to construct a class which is as general as possible, but is still useful. Making as few assumptions about the bank account as possible, one specification could be:
it has a balance which can be viewed and modified
In the absence of further information, it can be argued that the simplest thing that can possibly work (TSTTCPW) is the correct answer, so I propose:
int balance;
Nothing is much simpler than an int! The bottom-up approach would be to then
specify more sophisticated classes that are composed-of or inherited-from the low-level classes as more specifications are included. For instance consider the new specification:
account viewing and updating must be possible in a thread safe manner
class Account {
Lock();
Unlock();
int GetBalance();
SetBalance(int);
fields
int balance;
}
This is arguably the simplest class which satisfies the previous requirements, and reuses the previous definition. Introducing yet another requirement:
any modifcation to the account should be recorded as a transaction
would imply a transactional account:
class TransactionalAccount {
int GetBalance();
ApplyTransaction(Transaction);
fields
Account account;
}
By now I think it should be obvious where I am going with this. Starting at the bottom and introducing new layers of abstraction I can eventually reach the same design as was proposed by the top-down approach.
Summary: Combining the Two Approaches
The the top-down approach, which is more common, is to start with the full set of specifications, design an interface, and then provide the implementation afterwards. The danger of this approach is that it often doesn't go deep enough into the so-called
"implementation details". This can lead to designs that are too brittle because the objects are overloaded with responsibility and concerns aren't properly delegated into separate classes. OOP is useful at lower levels of abstraction including implementation details. The other big danger of the top-down approach is that we can make premature assumptions about a system, based on the language used to describe it.
The bottom-up approach implies starting with classes which represent the system as generally as possible and then using them to build more sophisticated and precise classes which eventually satisfy the problem. A bottom-up approach has its own pitfalls of course, such as the fact that it can be tempting to try and fit high-level classes to correspond with the limitations of the low-level classes, and the fact that programmers sometimes don't implement solutions with the appropriate level of abstraction.
Clearly both the top-down and bottom-up approaches have their value and place in software development. It is important in any discussion of OOP techniques to be aware of both approaches, as they each can give useful and important insights into the design and implementation of software, which are just two sides of the same coin.
Talk Back!
Have an opinion?
Readers have already posted
14
comments
about this weblog entry. Why not
add yours?
RSS Feed
If you'd like to be notified whenever Christopher Diggins adds a new entry to his weblog, subscribe to his RSS feed.
Christopher Diggins is a software developer and freelance writer. Christopher loves programming, but is eternally frustrated by the shortcomings of modern programming languages. As would any reasonable person in his shoes, he decided to quit his day job to write his own ( www.heron-language.com ). Christopher is the co-author of the C++ Cookbook from O'Reilly. Christopher can be reached through his home page at www.cdiggins.com.