I'm confused and hoping someone can help me with some basics. I'm trying to figure out what type of business objects I should create (EditableRoot, EditableChild etc.).
I'm confused because it seems like I want both an EditableRoot and an EditableChild for the same DB table. For example, I have an Invoice table (there's also an InvoiceItem table). It seemed to make sense to have Invoice as an EditableRoot, but sometimes I may want to work with a collection of Invoices - reporting, lookups etc. I can see where tables like Customer, StockItems etc. would be the same.
As far as I can tell right now, to work with collections, you need to use BusinessListBase, so that would make pretty much every object a child. I have the feeling I'm going down the wrong road.
Any help is much appreciated, thanks,
Mike
As soon as you say "sometimes I may want to..." you are almost certainly describing a different use case.
Sure, you have an "Enter an Invoice" use case. But then you have a "Find an Invoice" use case where you need a list of invoice data, and a "Report Invoice Data" use case where you need something a bit different.
You are suffering from the single most common OO design anti-pattern: data-centric thinking.
Instead, you need to remember, as I discuss in Chapter 6, that every object has exactly one, simple, clear, responsibility. It is therefore impossible for Invoice to be responsible for "entering valid invoice data" and also for "displaying a subset of invoice data for selection" or for "displaying a subset of invoice data for reporting". All of these are different responsibilities and thus require different objects (classes).
Hi,
There is one thing confuses me still and I haven't really found an answer yet.
Ok, lets say I have and MDI-Environment and I display a collection od read-only InvoiceInfo-objects for selection. At the same time I save an editible Invoice-object. How do synchronize the read-only collection without reloading the whole collection? It's even worse when I create a new Invoice?
I understand that this problemwill be solved with the new collection of editible Root-Objects in CSLA 2.1 but what would you do with CSLA 2.0?
Luzius
From: Luzius [mailto:cslanet@lhotka.net]
Sent: Tuesday, July 11, 2006 4:29 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Wrapping my head around basic conceptsHi,
There is one thing which confuses me still and I haven't really found an answer yet.
Ok, lets say I have and MDI-Environment and I display a collection od read-only InvoiceInfo-objects for selection. At the same time I save an editible Invoice-object. How do synchronize the read-only collection without reloading the whole collection? It's even worse when I create a new Invoice?
I understand that this problemwill be solved with the new collection of editible Root-Objects in CSLA 2.1 but what would you do with CSLA 2.0?
Luzius
One possible solution is to share the BO between your forms/grids/controls. With this design there is no need in an observer/events/etc. But:
1. make sure that this is what your users/BA are comfortable with (which is often true: normally people are confused if different views show different state of the same BO/entity); and generally, ogject sharing may not be an option with your requirements.
2. Take into account that if you go this way your objects would need to support greater sets of behaviours than they would otherwise; that would make the objects more data-centric.
I am using this approach in my current project, and I am reasonably happy with it.
I unfortunately don't have time right now to get really involved in this thread... but I thought I'd offer this tidbit.
I find a useful "litmus test" to be to think in the context of an object-oriented database. I've found this tends to be more useful in the particular discussion regarding whether a business object is just an abstraction of a database table such that there is basically a 1-to-1 relationship between business objects and tables. But in general when you consider that your business layer needs to work exactly the same if you replaced SQL with an OODB or even XML files it is sometimes very illuminating.
Thanks for the replies. Makes sense now why I was confused. I'm coming from using a commercial business object framework - in that framework there's exactly one business object for each table. Guess I was trying to make CSLA work the way that one did.
I appreciate the information,
Mike
I'm confused and hoping someone can help me with some basics. I'm trying to figure out what type of business objects I should create (EditableRoot, EditableChild etc.).
I'm confused because it seems like I want both an EditableRoot and an EditableChild for the same DB table. For example, I have an Invoice table (there's also an InvoiceItem table). It seemed to make sense to have Invoice as an EditableRoot, but sometimes I may want to work with a collection of Invoices - reporting, lookups etc. I can see where tables like Customer, StockItems etc. would be the same.
As far as I can tell right now, to work with collections, you need to use BusinessListBase, so that would make pretty much every object a child. I have the feeling I'm going down the wrong road.
Any help is much appreciated, thanks,
Mike
>> You probably are going to have far more classes in your application than you thought, eh?
Yeah, no doubt about that. Not that that's a big deal with snippets and what not like you say. Part of me is a little worried about duplicating code and having to maintain that, but we'll see how that goes.
Right now I don't see the advantage, for example, in having two classes - one for editing data and one for displaying that same data. I mean one *could* just use one class, but use them differently. Since these classes will be in the same assembly, I don't think there's any way to enforce how another developer decides to use my classes anyway. Plus, there would be less code to maintain.
Not that I'm going to break best practices right now, but it is in the back of my mind.
Regards,
Mike
Yes, this is something that is very difficult.
Part of this problem is the whole "objects are defined by their behavior, not their data" mantra.
I guess it is correct but there is a cognitive problem with it.
With data it is easier for me, and I would assume most others as well, to conceptualize how one set of data subsumes another. Data by it's very nature is concrete and lends itself to this recognition.
Behavior by its very nature is amorphous. It is action. And how can one action subsume another (and I am NOT talking about inheritance). Can it? It hurts the brain to even think about it.
This is phenomenon is well understood in OOP circles but not talked about enough in my opinion. Or rather it is talked about but not directly. I believe it is the main reason the whole agile/extreme programming methodologies arose because of this very thing.
It is why you also have some still railing against OOP/OOD. Because it doesn't make sense to them. Truth be told it doesn't make sense to anybody if you want to sit down and actually define what you are doing. Kinda like trying to define what morals are or what pornography is.
But back to your statement. Editable objects do, in many cases, satisfy a bunch of different use cases.
Xal Said: "Now that you know this, you realize that you want a list of Invoices (ReadOnlyCollection) that contains read only InvoiceInfo items (ReadOnlyChild). You also want an Invoice object (EditableRoot) that contains and editable list (EditableChildCollection) of LineItems (EditableChild)."
It could very well be that LineItem not only holds the same data as InvoiceInfo but also has the behavior needed to satisfy InvoiceInfo requirements.
It becomes even more confusing when you start saying things like "performs fast" and "doesn't need to save, update." Well LineItem may be able to save or update, but that doesn’t mean it has to.
Use cases are not really a lot of help in many cases. Even though a use case may say "Can Display needed information" it does not always say "cannot update or save information."
And that is the question. If your use case can be satisfied by another object but that object provides more behavior than required do you use it?
Hello pelinville,
That was a great post. Gives me something to chew on. You summed it up nicely with "If your use case can be satisfied by another object but that object provides more behavior than required do you use it?".
That's exactly what I'm wondering, but couldn't say it succintly. Right now I've got read-only classes and editable classes and they both have fetch type methods. Since I'll have to maintain these when things change, I'm thinking it might be better to have the read-only class wrap the editable class and limit the funcationality. That way I don't have two methods in two classes that do the same thing.
But that also bugs me. One time I hired this guy who I guess knows more about OOP than me. I got a little flustered one time when he wrapped the System.IO.File class in his own class that only exposed the methods he needed. It satisfied his use case, but I thought it was stupid for a couple reasons. He had to write this limiting code, it increased the surface area of our app, and he'd have to modify two classes if he needed another method. Why not just use the class directly?
In a way it's nice to look at a class and know what it's supposed to do. I really have no idea of the best approach, and it smells like this will come with experience. I image this is one of those deals where there's no definitive answer, and you do what you think is best given your requirement.
Regards,
Mike
But that also bugs me. One time I hired this guy who I guess knows more about OOP than me. I got a little flustered one time when he wrapped the System.IO.File class in his own class that only exposed the methods he needed. It satisfied his use case, but I thought it was stupid for a couple reasons. He had to write this limiting code, it increased the surface area of our app, and he'd have to modify two classes if he needed another method. Why not just use the class directly?
I understand your frustration.
Let me say first I am what Rocky would call a "mort". Secondly I must add that my formal training is in Cognitive Psychology so I could very well be reading way to much into the word "behavior". Combine those two statements and you could easily disregard anything I have to say.
But...
I have created classes that effectively limited another class. When I did this it was because I found the original class confusing and wanted to simplify. I didn't do it for any specific use case but, instead, because I am lazy and forgetful. Maybe that is what he was doing. (I think that is the idea behind the "My" namespace in VB.NET and it is absolutely wonderful.)
If he did do it simply because of a use case I would say that is taking it to far.
I am going to post about what you are concerned about. There is a problem with having read only and editable and reporting and foo squared classes. I think that the problem is not only a maintenance one which is there even with code snippets and codegen. It is a problem with the statement "Objects are defined by behavior and not data" itself. Don't misunderstand, I think it is basically correct. However it does not capture the essence of class necessity as well a theorem could.
(I have a sneaky feeling that part of it is part OOP elitism, part overcoming legacy thinking and part of it is simple confusion of what behavior is.)
And that is the question. If your use case can be satisfied by another object but that object provides more behavior than required do you use it?
>> You probably are going to have far more classes in your application than you thought, eh?
Yeah, no doubt about that. Not that that's a big deal with snippets and what not like you say. Part of me is a little worried about duplicating code and having to maintain that, but we'll see how that goes.
"Objects are defined by behavior, not data"
Now maybe I am just dense but this statement confuses me just as often as it helps me.
Rocky wrote "Sure, you have an "Enter an Invoice" use case. But then you have a "Find an Invoice" use case where you need a list of invoice data, and a "Report Invoice Data" use case where you need something a bit different."
Now I am not trying to pick on anybody but this really throws me. I have seen this type of statement many times in this forum. On it's surface it appears rather elementary but when thinking about it is not so clear. Not only in the posts but also when I am designing my own cases.
Example:
I have a Object called Student and it has a set of responsibilities. But a Student has tons of data. It takes about 15 objects plus 15 fields. Of course as far as the object is concerned all this is just "stuff" and any of it can be added or removed without consequence to the class/object.
There is another object, StudentCollection, that is responsible for controlling a list of students based on user needs. The user may want to act on students in a particular grade, or in a class or all students taught by a Teacher etc. (There are other objects such as ScoreCalculator that uses StudentCollection to do it's job).
Another requirement of the application is to display the student data in a grid so that an administrator or secretary can see in a glance the relative information of the desired student.
Now Student has all the data needed but much of it, as mentioned, is contained in classes. Student has an Address object but that is really just data. It has an Enrollment collection but that is just data. That Enrollment collection has a behavior that knows what the last enrollment was. Every Enrollment object knows the Grade enrolled in and the Grade holds a collection of GradingScale (data). But one of the Grades behavior is to know the default grading Scale.
And on and on.
So the student summary must, in part, show the Address fields, the enrollment fields and the grade fields plus the fields that the Student has.
The use case is something to the effect of "Display this data based on one or more of the following: grade enrolled, zip code living or date enrolled".
StudentCollection can already do all of what is asked and Student has all the data…. BUT!!!!
Student cannot display it's information "easily". Meaning you cannot bind the Collection to a grid and have all that information displayed to the user. At best the grid is smart enough to know that one of the data elements is another object so will allow drill down. It satisfies the use case but does not satisfy the user. At worse, and as is with most the grids I know, it simply shows the .ToString method of the object that contains the data field of the parent object.
To overcome this I created a new class that exposes all the contained objects fields as properties. I did a supper fancy join to get all the fields and created one of those read only classes. And this bothers me to no end.
I am NOT doing this to satisfy a use case. I am doing it to satisfy some other "computer thing". The control cannot be configured to display the fields of child objects. And please remember these sub objects are nothing but data as far as the Student object is concerned.
With all this said the problem I run into is that Objects ARE, at least in part, defined by their data. It can not be denied and to do so is simple folly.
My new class StudentSummary has no special responsibilities beyond Student. Both Student and StudentSummary has to expose it's data to a consumer. I will not change one character of Student.vb to satisfy StudentSummary.vb.
Well Maybe there is subtle behavior here? The user in this case is the particular windows component to be used. And it has a use case of "Display Student data like".
This causes the use cases to explode because how many components are available? And if using anything like the MVC you can't even consider the components, can you?
If you do, then StudentSummary class would be a part of the Controller (or is it view?) and take a Student in the constructor and display the data in a certain format . But that has huge performance and implementation implications. Remember a Student has about 15 objects/classes (data).
Which brings me to another point. Pure OOP/OOD is not concerned with performance or scalability. It expects the data to just be there. Now I don't think it should be concerned because OOP is not really a technology. It is a state of mind that technology tries to implement.
But that also confuses the statement in question. Because while we shouldn't be concerned with the data when designing a class it cannot be ignored because said data could make the application unusable.
Ted Newards "Effective Enterprise Java" covers all these issues and I follow his advice. This advice often boils down to "whatever works the best".
So…
We don't really get paid enough, do we? But I still think we need a sticky to justify and expand the statement "objects are defined by behavior, not data".
I have a Object called Student and it has a set of responsibilities. But a Student has tons of data. It takes about 15 objects plus 15 fields. Of course as far as the object is concerned all this is just "stuff" and any of it can be added or removed without consequence to the class/object.
[...]
With all this said the problem I run into is that Objects ARE, at least in part, defined by their data. It can not be denied and to do so is simple folly.
I respectfully disagree. The object is _defined_ by its responsibility and behaviors. In order to accomplish that responsibility and to implement those behaviors it requires a set of data.
The data follows the behavior, not the other way around. Well, technically the data follows the _responsibility_, because the object must have the data required to fulfill its responsibility. (though the object might not _directly_ have the data or behaviors, because it may collaborate with other objects at times)
In any case, I always use this litmus test: if I were doing this with a DataSet/RecordSet/ResultSet/whatever, would I really load this particular set of data to accomplish the given task?
Even in a data-centric world no sane developer loads all the data for a Student just to display a handful of fields in a search results window. No, they create a new DataSet/DataTable that only has that small subset of the data.
Only the most idealistic and naïve OO developer would do anything different. Building a Student object that loads all the data for editing and then reusing that same object to display search results is a prime example. (I certainly fit this description a decade ago, and my guess is that almost every OO developer HAS fit this description at one point or another! I don't think I've every met anyone who didn't try this at least once.)
You can resolve this issue by either turning to the data-centric side, which is quicker and more seductive, but not more powerful. Design your objects around the data they contain, and control that data just like you would if you were using a DataSet for design.
Or you can turn to the responsibility/behavioral OOD side, which _does_ require changing the way you think about software design, but ultimately (imo) really is more powerful. Yes, objects have data, but only in service to behavior. And behavior only exists to support responsibility.
Rocky
Rocky,
Those of us living in the Csla world have an added mental hurdle to jump over in the issue of behavior vs data and the related question of responsibility.
Every Csla object begins with data in instance variables, deals in and "mother hens" the data thru Property acessors, applies rules that are mostly data-centric, and fetches and saves the data. In other words, out of the box, 99% of a Csla object's functionality is like a intelligent suitcase full of data. And auto-generation methodologies neatly put a wrapper on this, since they all work with data tables. That is not a problem, of course - in fact Csla performs that indispensable function beautifully. It does, however, tend to make us see the world as being composed of nothing but Csla objects.
Three areas of responsibilty are always mentioned when talking about Csla objects. 1. Add new or update/delete existing data 2. Provide ReadOnly access to data, 3. Provide a list of "information items" in the data store. Of these, the second and third may or may not be limited to single tables, and it doesn't matter much because they are merely the front ends for a Sql query and I don't think that any of us have much problem grasping the use case or the behavior of these.
It is the first one, the Editable object, which causes the greatest difficulty in our understanding of behavior vs data, and unfortunately in these discussions is probably the hardest to dissect out in order to make the point. For one thing, the primary advertised responsibilty of an Editable Csla object pretty much has to do with DataTable(s), and by "definition" that reponsibilty is to fetch the data, guard it with its life, and when I modify it, save the changes back to the database. The trouble is that practically all of the custom code that gives an object its added "behavior" gets added to this type of object, hence the perennial question "why can't I reuse it" or "how can I reuse it" etc. Perhaps, it would help if there was a bit more discussion of OO kind of ways of how and why of this.
For example, talking about the Switchable object, it recently dawned on me that I can derive a switchable (Root) object by merely subclassing an existing child object and by removing the MarkAsChild call out of the child Constructor and making the child Constructor Protected and providing a Save method in the root. Similarly, I suppose what you are saying is that if there is functionality that we are stuffing into an Editable object, functionality that would be of use to other objects, it can be separated into a separate Class so it can be shared.
Jav
First I want to say that I am not trying to pick a fight or cause a ruckus. I am genuinely confused at times and I think some of this confusion is cause by two things.*
RockfordLhotka:Though we're playing semantic games to some degree, stating that an object has a "set of" responsibilities is not good.
I respectfully disagree. The object is _defined_ by its responsibility and behaviors. In order to accomplish that responsibility and to implement those behaviors it requires a set of data.
The data follows the behavior, not the other way around. Well, technically the data follows the _responsibility_, because the object must have the data required to fulfill its responsibility. (though the object might not _directly_ have the data or behaviors, because it may collaborate with other objects at times)
Yes, that is usually what gets me. It is like the nature vs. nurture debate. They cannot be separated. But depending on what you are trying to do you must assume one is first/dominate and go from there.
I think this is true with the Data vs. Behavior thing. You cannot separate them but you must give one prominence depending on what the goals are.
It would be beneficial for those first attempting this approach if this was actually declared in more concrete terms.
RockfordLhotka:An object should have exactly one responsibility, and then should have behaviors that support that responsibility. If some of those behaviors are required by other objects, then those behaviors should be normalized into a separate class that has its own responsibility, and the other (original) objects should collaborate with this new object.
Collaboration is a very important part of this overall view on OOD.
The term "responsibility", I believe, needs to be defined. Well, you just defined it. But maybe this (and other) definitions should be stickied someplace or a forum section created for common definitions.
I say this mainly because one of my favorite books "Object Thinking" by David West says multiple times that responsibilities should be limited but at any rate kept to less than seven.
Maybe David West was refering to "Behavior" when he was speaking of responsibility? I am not sure.
But Robert Martin defines it as you do in the "Single Responsibility Principle" and it has nothing to do with what a class does but how a class can change. Martin modified/expanded/limited/changed the cohesion term which was define by DeMarco (I think) and somebody else. And who knows how the SRP has been interpreted by others.
But when I read the definition of cohesion for the first time I did not envision the SRP. I have read in many places, however, where people use cohesion and SRP interchangeably. And I don't really think they are interchangeable. I think they simply have the same goals.
And beyond that it has to be pointed out that defining a responsibility is tricky to say the least. I don't see the "how to" discussed very much.
And the term "objects are defined by their behavior, and not data" does not even mention responsibility. Shouldn't it be "Objects are defined by their responsibility, not behavior or data?"
Then "Behavior is demonstrated in an object if it's responsibility requires it." I put it this way because said behavior may actually be implemented in another class and can be reused in many place. Behavior is now a thing.
Then "Data in an object is only present because it's behavior requires it."
RockfordLhotka:
In any case, I always use this litmus test: if I were doing this with a DataSet/RecordSet/ResultSet/whatever, would I really load this particular set of data to accomplish the given task?
I take a lazy way. If the SQL can't fit into the top half of the screen in Visual Studio I start thinking something is wrong.
RockfordLhotka:Even in a data-centric world no sane developer loads all the data for a Student just to display a handful of fields in a search results window. No, they create a new DataSet/DataTable that only has that small subset of the data.
Only the most idealistic and naïve OO developer would do anything different. Building a Student object that loads all the data for editing and then reusing that same object to display search results is a prime example. (I certainly fit this description a decade ago, and my guess is that almost every OO developer HAS fit this description at one point or another! I don't think I've every met anyone who didn't try this at least once.)
You can resolve this issue by either turning to the data-centric side, which is quicker and more seductive, but not more powerful. Design your objects around the data they contain, and control that data just like you would if you were using a DataSet for design.
Or you can turn to the responsibility/behavioral OOD side, which _does_ require changing the way you think about software design, but ultimately (imo) really is more powerful. Yes, objects have data, but only in service to behavior. And behavior only exists to support responsibility.
This the problem with current technology that frustrates me. Like I said the Student object has behavior and I think this behavior demands all the data needed. But it is some other part in the system which comes up short**.
In an ideal world the idealistic and naïve could actually be such. And I think it will get there one day. Many things we take for granted today used to be "naïve thinking". Creating a basic Windows Form with a couple of lines of code for example.
But even if I had the magic bullet (or the requirements of the application) allowed me to load all the Student data in one go I still would be stymied because of what I mentioned before. Data binding does not really handle arbitrary reference types all that well. (You can't define the display member to be "Address.Line1" for example. I find this kinda silly but that is the way it is.)
So this part of my frustration is rather juvenile and doesn't add to the discussion. But I hope that this negative, but hopeful, energy will be picked up, somehow, by the Einstein's of the world to be solved.
I do have many other questions but they are more specific than this thread allows. And it is quite possible that they would be out of place in this forum. (Which is why I have not asked them. Most of this place seems to be devoted to specific technical issues.)
As Jav said, it would be very helpful if we could discuss how we can take the basics discussed in the books and expand it to real world issues.
*And I often question whether this forum is the place to confess my confusion. But I figure since the first .NET BO book was the
**But this problem is caused by the current persisting mechanisms for applications built today. RDBMS's being a primary one. A thing that has, unfortunately, become used for all kinds of things that it isn't really designed for. For example OOP/OOD.
I seriously doubt that David West is suggesting an object can have up to 7 responsibilities. Take a look at Rocky’s blog. He certainly doesn’t think David West was suggesting using 7 responsibilities in a class. http://www.lhotka.net/WeBlog/WhatIGotOutOfObjectThinking.aspx
The single-responsibility principle is a very well-known and
fundamental OOP principle. An object
should only have one responsibility. In other
words, it should only have one reason to change. If it has more than one reason to change, it
has more than one responsibly and thus breaks the single-responsibility principle. A responsibility is a “reason to change”. It is anything a class does or
knows. Behaviors simply describe the responsibility .
Perhaps the statement “Objects are defined by
behavior not data.” can be replaced with the statement “Objects are not defined by data. They are defined by
behavior that describes a single responsibility. ”.
Pelinville, I knew this discussion
sounded familiar. Were you
SerratedBobcat in the old forum?
The definition of a responsibility for CRC cards is a little different than in the single responsibility principle. A responsibility in CRC cards is anything a class knows or does. This includes data and behavior. The definition of responsibility in the single-responsibility principle is a reason to change.
From: malloc1024 [mailto:cslanet@lhotka.net]
Sent: Monday, June 12, 2006 1:57 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Wrapping my head around basic conceptsThe definition of a responsibility for CRC cards is a little different than in the single responsibility principle. A responsibility in CRC cards is anything a class knows or does. This includes data and behavior. The definition or responsibility in the single-responsibility principle is a reason to change.
Rocky,
Do you have other books to recommend in addition to Object Thinking and Object Technology? I've read both those books (as well as yours) to try to get on the right path to understanding OOP/OOD. Unfortunately, I don't still feel like I "get it" regardless of how many times I repeat the mantra "objects are defined by behavior not data". Any recommendations and/or pointers appreciated.
Thanks...
-Rahul
From: rahulbpatel [mailto:cslanet@lhotka.net]
Sent: Monday, June 19, 2006 9:10 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Wrapping my head around basic conceptsRocky,
Do you have other books to recommend in addition to Object Thinking and Object Technology? I've read both those books (as well as yours) to try to get on the right path to understanding OOP/OOD. Unfortunately, I don't still feel like I "get it" regardless of how many times I repeat the mantra "objects are defined by behavior not data". Any recommendations and/or pointers appreciated.
Thanks...
-Rahul
I realize that I missed this thread by a few months, but it just so happens that I was looking for information on this topic yesterday, and this is an interesting topic, so I'd like to chime in.
I think the discord for many developers comes from what Rocky referred to as a "naive and ideological" way of thinking. According to this mindset, object-oriented design and programming means that there should be a one-to-one correspondence between objects in your code and objects in the real world, and thus also between classes in your code and types of objects in the real world. According to this way of thinking, there should not be a Customer class and a CustomerInfo class, much less additional Customer classes for every other type of responsibility Customer entitiy might have. A customer is a customer, and should be represented by a single customer class. The real world, of course, dictates that if you're displaying a list of customers with 5 columns, you don't want to pull back all 80 columns for each one, any more than you want to bring back a million rows if the user only views 20 at a time. The idealist might say, "let me adapt the Customer class to only populate the columns that I need, and use lazy loading for the rest", while the behaviorist would say "I'll just implement a CustomerInfo class that does exactly what I need for this search results list, and when the user double-clicks one, then I'll instantiate a real Customer object for the user to view and edit."
Like many, I definitely come from this idealistic way of thinking. I think this was the appeal of object-oriented programming when I first started learning about it. However, like many others here, I've also come to see the advantage in a behavior-centric, such that you can ensure that only the behaviors that are appropriate in a given scenario are available. The difficulty in the change in thinking is that the concept of a "customer" is now more of an abstract concept that is not directly represented in your code. The business entity of "customer" is represented by the collection of classes the implement its responsibilities in various contexts, as well as the data in the database.
In my case, though I've bought into the idea of behavior-centric classes, I'm still stumbling a bit. In my application, I have the concept of a "request". A request is submitted by the client to the server to have some work done. The client submits requests and checks on their status until the requested work is complete. The server picks up requests from the queue, performs the work, updating the progress as it goes along, and finally marks the request complte.
Following the idealistic approach, I would have a single Request object which implemented all of the functionality required by both client and server. This would obviously be bad, because even if you trust developers on both sides to use the object appropriately, it simply complicates things on both sides, because developers have to look at the full public interface of the class and determine which methods are appropriate for them. Therefore, it's definitely preferable to have separate ClientRequest and ServerRequest classes.
The stumbling block is this: both ClientRequest and ServerRequest require the exact same data. ClientRequest needs read-only properties to access the data, and ServerRequest needs read-write properties. To avoid duplicating the private data members in each class, you have to declare them as "protected" instead of "private", which is generally frowned upon. If understand Rocky's comments, the approach he generally takes is to just give in and duplicate the data members between the two classes. In principle, I am opposed to this sort of duplication - in my simple example, it's only the duplication of 10 private member declarations, but in more complex scenarios it would only get worse.
So, is it ok to violate encapsulation by making the private members protected? Or do we just give in and duplicate? Is there a better answer?
Greg Bahns
gbahns:I think the discord for many developers comes from what Rocky referred to as a "naive and ideological" way of thinking. According to this mindset, object-oriented design and programming means that there should be a one-to-one correspondence between objects in your code and objects in the real world, and thus also between classes in your code and types of objects in the real world. According to this way of thinking, there should not be a Customer class and a CustomerInfo class, much less additional Customer classes for every other type of responsibility Customer entitiy might have.
To clarify, I was speaking of the idealist as the one who would strive for a one-to-one correspondence between objects and the real world. I did not mean to imply that this is what Rocky currently believes - obviously not.
Thanks to both of you for your replies. I'll consider Andy's suggestions for class design. I'm not sure I agree that the client should have a Request and a RequestStatus class - I was planning on having a single ClientRequest class used for submission and status polling. I would argue that the the behaviors of submitting a request and polling the status fit within the responsibility of servicing the client, but I can see that I might be off base there (i.e. what I'm calling a behavior might actually be the responsibility, and the behaviors are actually more fine-grained).
(Actually, as I've implemented it, there's just a static method for clients to submit requests, so they don't actually need a separate class for submitting. All they need is a class for polling the status.)
Greg
:I'm not sure I agree that the client should have a Request and a RequestStatus class - I was planning on having a single ClientRequest class used for submission and status polling.
:I would argue that the the behaviors of submitting a request and polling the status fit within the responsibility of servicing the client, but I can see that I might be off base there (i.e. what I'm calling a behavior might actually be the responsibility, and the behaviors are actually more fine-grained).
Gbahns,
I enjoyed
your post and glad you brought the topic up.
I find myself more in the idealistic camp that you describe. When you create an address class, idealistically
that would be the only one you will ever need.
The behavior of an address should not change between each project. A small downside to this is that you might
end up with properties that you don’t use in a particular project. Is this so bad? A use-case driven design dictates that you
must create a separate class for each use-case. Therefore, you end up with many more address classes. It doesn’t seem to me that a use-case driven
design promotes reuse as much. I would
rather have one address class that represent an idealistic view of an address opposed
to many that fit different use-cases. Objects should be designed based on behavior
not necessary use-cases. Use-cases can
help with your design but probably should not dictate your design completely.
I have looked at some sites that describe CRC cards. Some have different definitions for responsibility. This just makes things more confusing. Anyway, do not compare the definition of responsibility in CRC cards to the responsibility in the single-responsibility principle. This will only lead to confusion.
Rocky,
Those of us living in the Csla world have an added mental hurdle to jump over in the issue of behavior vs data and the related question of responsibility.
Every Csla object begins with data in instance variables, deals in and "mother hens" the data thru Property acessors, applies rules that are mostly data-centric, and fetches and saves the data. In other words, out of the box, 99% of a Csla object's functionality is like a intelligent suitcase full of data. And auto-generation methodologies neatly put a wrapper on this, since they all work with data tables. That is not a problem, of course - in fact Csla performs that indispensable function beautifully. It does, however, tend to make us see the world as being composed of nothing but Csla objects.
Three areas of responsibilty are always mentioned when talking about Csla objects. 1. Add new or update/delete existing data 2. Provide ReadOnly access to data, 3. Provide a list of "information items" in the data store. Of these, the second and third may or may not be limited to single tables, and it doesn't matter much because they are merely the front ends for a Sql query and I don't think that any of us have much problem grasping the use case or the behavior of these.
It is the first one, the Editable object, which causes the greatest difficulty in our understanding of behavior vs data, and unfortunately in these discussions is probably the hardest to dissect out in order to make the point. For one thing, the primary advertised responsibilty of an Editable Csla object pretty much has to do with DataTable(s), and by "definition" that reponsibilty is to fetch the data, guard it with its life, and when I modify it, save the changes back to the database. The trouble is that practically all of the custom code that gives an object its added "behavior" gets added to this type of object, hence the perennial question "why can't I reuse it" or "how can I reuse it" etc. Perhaps, it would help if there was a bit more discussion of OO kind of ways of how and why of this.
For example, talking about the Switchable object, it recently dawned on me that I can derive a switchable (Root) object by merely subclassing an existing child object and by removing the MarkAsChild call out of the child Constructor and making the child Constructor Protected and providing a Save method in the root. Similarly, I suppose what you are saying is that if there is functionality that we are stuffing into an Editable object, functionality that would be of use to other objects, it can be separated into a separate Class so it can be shared.
Jav
Copyright (c) Marimer LLC