Getting things done
The main question when it comes to OOD is: what does this do? Objects are all about doing things. They have some data to do this things, but that’s it. I’ve seen so many codes where objects are nothing more than data containers. That’s not OOP. You may be using an OOP language, but you’re not doing OOP. Now i don’t intend to upset you. I used to code like that. That’s one of the reasons I’m sharing this with you. Objects do things. They must have a reason to exist. A role to fulfill.
If you paid attention to the previous post, i defined a VirtualPet in terms of what it does. It sleeps, play and eat. I didn’t start with stuff like name or age. Sure those can be used to identify a particular object, but what’s so good about identifying a useless object?
When designing a database you start with data. When designing an object model you start with behavior. There seems to be a lot of people who don’t know or don’t understand this subtle difference, thus leading to a lot of hard to maintain code. They heard of design patterns and try to apply those to their pseudo-oop code often resulting in unnecessary complexity. I’ve been through this myself, wondering what was so great of these so called patterns. Have you?
Finding the right guy for the job
A great deal of a developer’s life is understanding things/learning concepts. This is because very often objects represent real life concepts. Even more, the same concept can have a different meaning in a different context. A home phone number can be some optional data in a customer relationship management system but can be a crucial piece in a delivery pizza system ;).
Creating a flexible OOP system it’s a lot about identifying the key concepts related to a given domain and the responsibilities related to them in a given context.
So let’s do a little exercise.
Let’s say we’re making a banking system. We’re assigned the following case (mind my bad English, I’m not a native speaker):
Cashing a check.
The bank receives a check from a customer.
The customer can ask for either get the cash or deposit it to another account.
Deposit to an account
The customer deposit an amount to a certain account.
The data oriented approach
So here we have it. Let’s think about it for a second would ya? where do we start ? What are the main concepts here? let’s see, there has to be a customer, right? i mean the customer always starts everything, brings the check, deposit the money, we should have one, right? right? It must have a name, an address maybe, surely an account number! It may look something like:
Validating the model
ok, what’s next? well the next thing is asking yourself: what does this do? What does customer do? what’s it’s Raison d’être? go ahead take your time. Think about it.
So imagine I’m the same room with the author of the previous design, here’s how this conversation would go (probably):
-so what does customer do?
-well obviously every account has an owner. That would be the customer.
-Yeah but what does it do?
-Mmm... what does it do you say? (frowning eyes as if thinking hard) that would be... to help finding an account.
-You could always use the account number
-Yeah, but not everyone knows it. Heck i don't even know my zip code!
-OK, i got your point. So the customer helps finding the right account.
-That's right.
-But then, wouldn't make sense to add the customer as an account attribute?
-I don’t think that’s a good idea.
-why not?
-because they’re different things. Different concepts.
-So you’re saying that every time I want to find an account, first I have to fetch the customer object?
-Yeah…
-and then I guess I would call a method called GetAccount()
-not necessarily. You just have to transverse to the CustomerAccount property
-so the customer doesn’t do anything. It’s just a place holder.
-it does! it let’s you access the account!
-…
The meaning of “do”
As you can see from our fictional discussion, the problem lies with the meaning of probably one of the most used words. To help us understand what “do” means in this context let me rephrase the question: what’s this object’s mission? What does a mailman do? what’s his mission? that would be to deliver mail. He doesn’t let you search his bag for your mail. And you don’t care if he uses a bike or an elephant as long as you get your mail. So “do” in this sense defines the object’s ultimate purpose. In OOP slang we call this the object responsibility.
Ok, now that we state what we mean with the question. Let’s get back to our little exercise. What was that again? Ah! What does customer do? the short answer is: nothing. I won’t go into the long answer .
Let’s continue with the check object. What does check do? from what we read earlier it gets money from an account. We’ll come back to it later.
Ok, next is the account object. What does account do? Mmm… could we say that it maintains a balance? does that make sense to you?
So far we have the following:
Object |
what does it do? |
customer |
nothing |
check |
get money from an account |
account |
maintains a balance |
The lens we see through
The “what does this do?” kind of analysis is not new. It is implicit in Kent Beck CRC cards technique as well as in TDD. The important thing here it’s that we have objects that do things. Now let’s get dirty
The first thing that comes to mind is the customer object. It really does nothing. Any object that does nothing in the model, just make it harder to understand, so let’s get rid of that Customer… (I mean the object, not that pricky, close minded guy from your last project! I bet you’re thinking about him/her now )
Woah! no customer object? but this is a banking model we’re doing here! there has to be a customer object!
Well you see, an object model shows up just what’s important to a specific context. That means it highlights what’s important to a specific use case. Maybe the following example will make this clear.
I got 2 maps here. You could say that both are models of the world. The difference lies in what they’re trying to convey. The first one shows the time zones. The second one put emphasis on the terrain.
So you see, an object model it’s just like a map. You don’t show the reality in full detail, just the stuff relevant to the matter at hand. We call this process of identifying the important objects and relevant actions, the abstraction process. And the resulting objects are called abstractions, since they represent the important stuff on the domain. Ok, now that I’ve made my point, I hope you understand that Customer is not relevant to this model. At least at this point.
Digging deeper
Now that we have objects, and responsibilities assigned to them, let’s find out how they carry them out. I’ll start with the “deposit to account” use case since it seems the simpler one (I always try the simpler use cases first). This case tell me that the account object has a deposit operation that adds an amount to it’s current balance. Easy peasy.
Object |
what does it do? |
How does it do it? |
account |
maintains a balance |
deposit(amount) |
Now on to the “cashing a check” use case. So we have a cash method in the check object and it needs an account to withdraw from. But the account object doesn’t have a way to withdraw from itself so we have to create one.
Object |
what does it do? |
How does it do it? |
check |
get money from an account |
cash() |
account |
maintains a balance |
deposit(amount)
withdraw(amount) |
The customer can also cash the check to another account. This effectively is a transfer operation. Where should we put this? Who has this responsibility? to answer that question we got to understand the effects of this operation. What’s going to happen after the operation is completed? if all goes well one account will have it’s balance decreased while another will have it increased. And who’s responsible for maintaining a balance? the account itself! it’s not an AccountService object or a TransferOperation object but the account who’s solely responsible. So let’s create a transfer method in the account object and a cashToAccount method in the check object.
Object |
what does it do? |
How does it do it? |
check |
get money from an account |
cash()
cashToAccount( account) |
account |
maintains a balance |
deposit(amount)
withdraw(amount)
transfer(amount,account) |
So there you have it. Both cases with just 2 simple classes. I’m sure you have a pretty clear idea of how to code this now. It may be something similar to :
class Account
{
decimal _currentBalance = 0;
public bool Deposit(decimal amount)
{
//biz rules
_currentBalance += amount;
return true;
}
public bool Withdraw(decimal amount)
{
//biz rules
_currentBalance -= amount;
return true;
}
public bool Transfer(decimal amount, Account toAccount)
{ //biz rules
toAccount.Deposit(amount);
this.Withdraw(amount);
return true;
}
}
class Check
{
decimal _amount = 0;
Account _originAccount;
public Check(decimal amount, Account account)
{
_amount = amount;
_originAccount = account;
}
public bool Cash()
{
//biz rules
return _originAccount.Withdraw(_amount);
}
public bool CashToAccount(Account account)
{
//biz rules
return _originAccount.Transfer(amount: _amount, toAccount: account);
}
}
Homework : Go back to any of your past projects and identify at least 2 use cases, their main concepts and if there are objects representing each one. Then find what their responsibilities are and, if they are not clear, define them. Last but not least, identify the operations needed to carry on the object’s responsibilities. Compare and write your comment below. Let me know if this changes would simplify the current code or not.
See you in the next post.