Sure, you're right. Those examples are not entirely devoid of business logic. Saying there is "a lot of behaviour involved" isn't quite true though. Most of what you mentioned are boolean flags.
If you look at your age calculation example above, that was a good example of having functionality outside of the business object that needed to be refactored inside it. For the examples I mentioned, though, you aren't going to find functionality outside the domain objects, because there isn't much. Those types of sites are generally content-driven, not functionality-driven. So getters for those properties aren't indicators of misplaced functionality, which was the original point I was trying to make.
I tend to look at websites and applications as a gradient, so I don't think any discussion on a clear cut is relevant. I would argue, though, that websites tend to fall more on the side of little to no busines logic, and web applications would have a great deal more business logic.
I'm not going to get into the argument of whether some people should be using OOP for their sites. But everyone wants to jump on the OOP bandwagon, and I've seen a lot of people (and been there myself) who get confused over the getter/setter debate. IMHO, most of those objects that they are debating whether to use getters and setters with are similar to the ones I mentioned earlier, which are little more than arrays (with maybe a couple flags here and there like you mentioned). Telling them they must have misplaced functionality is kind of misleading.
If you're looking for a clean way to make domain objects truly encapsulated, then you're looking for the builder pattern. I think there's a decent wikipedia article that has the same pattern in four different languages, including PHP, that is a good example. It's really kind of overkill though, because for content like I mentioned above you'd end up with almost nothing in your domain objects. I think somebody mentioned on sitepoint (when I brought up the builder pattern a couple of months ago) that they export arrays for use by the view. I tend to just stick with getters and setters for all properties for now. Sure, it's not perfect, but I'm just not making complex enough apps to warrant something like the builder pattern.
OOPHP Advocacy arguments
Moderator: General Moderators
- allspiritseve
- DevNet Resident
- Posts: 1174
- Joined: Thu Mar 06, 2008 8:23 am
- Location: Ann Arbor, MI (USA)
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: OOPHP Advocacy arguments
First, I don't think "everyone wants to jump on the OOP bandwagon" -- I think that it is the only bandwagon around. One comment I have made is: Try to find a book on designing software using Structured/Procedural Progamming written in the last 5 years (how about 10 yearsallspiritseve wrote:I'm not going to get into the argument of whether some people should be using OOP for their sites. But everyone wants to jump on the OOP bandwagon, and I've seen a lot of people (and been there myself) who get confused over the getter/setter debate. IMHO, most of those objects that they are debating whether to use getters and setters with are similar to the ones I mentioned earlier, which are little more than arrays (with maybe a couple flags here and there like you mentioned). Telling them they must have misplaced functionality is kind of misleading.
Second, about getters/setters. It is important to notice that they are considered a code smell and not evil. Notice the sophistication in the concept of these OOP code smells. In OOP there is an acknowledgment that there are clear cases for implementations that are considered bad in general practice (see Fowler on when Models need a dependency on the View
(#10850)
Re: OOPHP Advocacy arguments
You've just walked in my trapallspiritseve wrote:Sure, you're right. Those examples are not entirely devoid of business logic. Saying there is "a lot of behaviour involved" isn't quite true though. Most of what you mentioned are boolean flags.
That's my whole point. I don't have the time to write up an example, but if you have an example of a Controller and a Model that has getters/setters, I can show that one change would ripple changes through all layers of your application. That's the beauty of OO: it doesn't have to.
if( $page->getPublished( ) == true ) and if( $page->getStatus( ) !== 'hidden' ), that's all I have to say. You're destroying the ability to change implementation, because the logic is _outside_ of the object, where it should be _inside_ the object. When using $page->isPublished( ) and $page->isHidden( ), no assumptions would be made as to how a page decides on if it is or isn't published or hidden. When you're comparing return values of getMethods to another value, it's almost certain that your logic isn't where it should be.allspiritseve wrote:If you look at your age calculation example above, that was a good example of having functionality outside of the business object that needed to be refactored inside it. For the examples I mentioned, though, you aren't going to find functionality outside the domain objects, because there isn't much.
When only displaying - like I've said in every post - there is nothing wrong in using getters to obtain values. When using them in a logical statement, you might want to reconsider where you are placing that logic.
In my eyes, every piece of software has functionality, every piece of software has content, so I don't really get the "functionality vs. content". Getters for those properties _are_ misplaced functionality, because you're breaking encapsulation and making it harder on yourself to change an object's implementation. Again: if you're comparing stuff against the outcome of a getX() method, you're almost certainly misplacing the functionality.allspiritseve wrote:Those types of sites are generally content-driven, not functionality-driven. So getters for those properties aren't indicators of misplaced functionality, which was the original point I was trying to make.
Well, it certainly is a difficult question to answer, but you can not go around the fact that almost all software _must_ have some kind of bussiness logic (unless it's read-only). Maybe this is the problem? The mere simple fact that we're miscommunicating? In my opinion and terminology, bussiness logic is _really_ wide. Quoting Wikipedia's point of view on Bussiness Logic:allspiritseve wrote:I tend to look at websites and applications as a gradient, so I don't think any discussion on a clear cut is relevant. I would argue, though, that websites tend to fall more on the side of little to no busines logic, and web applications would have a great deal more business logic.
So, everything that changes the data of a Domain Object, should be in the object itself. It represents the real world, so there always is behaviour associated with the data. Of course there is logic that just doesn't make sense in the domain object, so that could be refactored into the controller or another Domain Object. Obviously, you could opt for having only Data Transfer Object and implementing the logic in the controller, but from my point of view this brakes the principle of MVC: the ability to change one layer without affecting the other.Business objects are sometimes called domain objects; a domain model represents the set of domain objects and the relationships between them.
A business object often encapsulates all of the data and business behavior associated with the entity that it represents.
Hey, I'm no exception. No-one is born with knowledge on writing software, and it's debates like this that've helped me improve my understanding of object oriented programming.allspiritseve wrote:I'm not going to get into the argument of whether some people should be using OOP for their sites. But everyone wants to jump on the OOP bandwagon, and I've seen a lot of people (and been there myself) who get confused over the getter/setter debate.
Well, if you still see it that way, I won't argue anymore after this post, but I disagree. If you want to write decent OO code, an array should be an array, whereas an object should have behaviour. If it doesn't, I wonder why you're not using an array instead. Now, I'm not saying you're doing it wrong, I mean whatever floats your boat is fine with me. But stating that "domain objects" don't have to have behaviour and then implementing that exact behaviour somewhere else using setters/getters actually is promoting procedural programming. Why write an object if it won't contain any behaviour?allspiritseve wrote:IMHO, most of those objects that they are debating whether to use getters and setters with are similar to the ones I mentioned earlier, which are little more than arrays (with maybe a couple flags here and there like you mentioned). Telling them they must have misplaced functionality is kind of misleading.
The biggest advantage of writing the behaviour in the object vs. writing it outside of the object is clearly testability, plus the fact that it's well encapsulated (thus changeable without ripple-effect) and more clear than scattering behaviour everywhere. There's no point in testing setters/getters, there is a point in testing if the behaviour of an object actually is the behaviour you expected. Maybe an illustration would clear things up:
Code: Select all
<?php
// try this:
$this->assertEquals( 'hidden', $page->setStatus( 'hidden' )->getStatus( ) );
$this->assertTrue( $page->setPublished( true )->getPublished( ) );
// versus:
$this->assertTrue( $page->hide( )->isHidden( ) );
$this->assertTrue( $page->publish( )->isPublished( ) );
?>
Thanks for that, although I'm not quite certain on how to implement that. That usually is the problem with examples on pizza's: I read about them, get hungry and gone is my concentrationallspiritseve wrote:If you're looking for a clean way to make domain objects truly encapsulated, then you're looking for the builder pattern. I think there's a decent wikipedia article that has the same pattern in four different languages, including PHP, that is a good example.
"Almost nothing" is still something that can and probably will change over time. Then again, if you can't justify the time of writing behaviour instead of setters/getters vs. the time you'll spend changing your software, then by all means: use setters/getters. An array would work as well, but I'd like my View layer to be able to access non-mutating behaviour, so I'm sure I not repeating myself. $appointment->isOverdue( ) is logic I wish to use in my View layer, $appointment->remove( ) certainly isn't.allspiritseve wrote:It's really kind of overkill though, because for content like I mentioned above you'd end up with almost nothing in your domain objects. I think somebody mentioned on sitepoint (when I brought up the builder pattern a couple of months ago) that they export arrays for use by the view. I tend to just stick with getters and setters for all properties for now. Sure, it's not perfect, but I'm just not making complex enough apps to warrant something like the builder pattern.
Yes, but the problem is that I see a lot of people that are still doing procedural programming in their Controller layer/View layer. Besides, I resent the thought that object oriented programming is a better way to program than functional or procedural can be. Good functional programs exist, although they tend to be less complicated, yet a bit harder to change. I think a realistic assessment is that authors that have enough experience to write a good book, usually have enough experience in writing big applications, which means OO is probably the better fit.arborint wrote:First, I don't think "everyone wants to jump on the OOP bandwagon" -- I think that it is the only bandwagon around. One comment I have made is: Try to find a book on designing software using Structured/Procedural Progamming written in the last 5 years (how about 10 years). I think it is a realistic assessment that if you are not doing OOP then you have almost no support for improving your skills.
It's natural for OO programmers to want to tackle everything using objects. However, if I have to write something that has five pages, I won't use objects for it (except for library objects, such as a template system or SwiftMailer).
Yes, there is a difference between plain big failures such as don't use goto and a code smell. Programming is all about the compromises you have to make, so as to achieve your objectives. Still, it is important to have rules of thumb and I think I've said this before: getters and setters are not evil per se, but they can be easily abused to do procedural programming in a class construct. You have to be aware of it's dangers and I'm afraid many of us aren't. That isn't the least bit strange since most everyone I know that is programming PHP, started in a procedural language, not having an object-oriented mindset.arborint wrote:Second, about getters/setters. It is important to notice that they are considered a code smell and not evil. Notice the sophistication in the concept of these OOP code smells. In OOP there is an acknowledgment that there are clear cases for implementations that are considered bad in general practice (see Fowler on when Models need a dependency on the View).
Old? You mean the future days of "don't use goto"?arborint wrote:It not like the old "don't use goto" days.
- allspiritseve
- DevNet Resident
- Posts: 1174
- Joined: Thu Mar 06, 2008 8:23 am
- Location: Ann Arbor, MI (USA)
Re: OOPHP Advocacy arguments
I think you're completely missing my point. You don't have to lecture me on encapsulation and misplaced functionality. I understand their benefits.webaddict wrote:Well, if you still see it that way, I won't argue anymore after this post, but I disagree. If you want to write decent OO code, an array should be an array, whereas an object should have behaviour. If it doesn't, I wonder why you're not using an array instead. Now, I'm not saying you're doing it wrong, I mean whatever floats your boat is fine with me. But stating that "domain objects" don't have to have behaviour and then implementing that exact behaviour somewhere else using setters/getters actually is promoting procedural programming. Why write an object if it won't contain any behaviour?
...
"Almost nothing" is still something that can and probably will change over time. Then again, if you can't justify the time of writing behaviour instead of setters/getters vs. the time you'll spend changing your software, then by all means: use setters/getters. An array would work as well, but I'd like my View layer to be able to access non-mutating behaviour, so I'm sure I not repeating myself.
...
It's natural for OO programmers to want to tackle everything using objects. However, if I have to write something that has five pages, I won't use objects for it.
When I mentioned boolean values, I wasn't advocating a getter/setter on those values. But they aren't interacting with any other property. I agree it does have some behavior, but it's not going to radically change those classes I mentioned. Most of the other properties will need getters/setters. To set the title, you have to pass it as a parameter to a method, unlike with your boolean values that can be modified with a method call w/ no parameters.
You're absolutely right. Domain objects can and will pick up behavior over time. You can't add behavior to an array, though. Add that to the fact that many aspiring programmers want to tackle everything using objects (but don't really know how). I don't think many of them think like you, in that if something has five pages, they won't use objects. I know, because I've been there myself. You know how it is on sitepoint, when people start asking about mvc, and come in with their god base classes and accessing properties directly.
Why write an object that doesn't have any behavior? I don't know. I'd prefer an object with all getters and setters though, because 1. properties are encapsulated and 2. I can refactor the class as I go, moving outside behaviour inside. It's a process, and I don't expect anyone to get it right the first time.
I think the point I am trying to make, is that there are legitimate examples that come up where getters/setters indicate a lack of behavior, not misplaced behavior. We may disagree on whether people should be using objects when they lack that behavior, but I think that's just a preference.
Sorry, I mentioned that one because its one of the few examples in PHP. I can try and whip up an example:webaddict wrote:Thanks for that, although I'm not quite certain on how to implement that. That usually is the problem with examples on pizza's: I read about them, get hungry and gone is my concentrationHowever, I'll read up on it and see if this is a good fit for the problem at hand. Thanks for the link.
Code: Select all
class Page {
private $title;
private $body;
function import (Builder $builder) {
$this->title = $builder->getTitle();
$this->body = $builder->getBody();
}
function export (Builder $builder) {
$builder->setTitle ($this->title);
$builder->setBody ($this->body);
return $builder;
}
}
class HTMLBuilder implements Builder {
private $title;
private $body;
function getTitle() {
return $this->title;
}
function setTitle ($title) {
$this->title = $title;
}
function getBody() {
return $this->body;
}
function setBody() {
$this->body = $body;
}
}
$builder = new HTMLBuilder();
$builder->setTitle ($request->get('title'));
$builder->setBody ($request->get('body'));
$page = new Page();
$page->import ($builder);
$builder = $page->export ($builder);
<h1><?=$builder->getTitle(); ?></h1>
<p><?=$builder->getBody(); ?></p>
I appreciate that. I'm not sure why you respect me as a programmer... I don't feel like I've done all that much worthwhile. But I appreciate it.webaddict wrote:'m definitely not saying you're one of them, allspiritseve, I've read a lot of your topics here and on SitePoint, and I respect you as a programmer. I do want you to know that
Last edited by allspiritseve on Mon Oct 13, 2008 11:10 am, edited 1 time in total.
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: OOPHP Advocacy arguments
I understand the idea of being balanced in your outlook, but you are disagreeing with many, many smart people in making that statement.webaddict wrote:Besides, I resent the thought that object oriented programming is a better way to program than functional or procedural can be.
There are several classes of problems, parsers for example, where using goto produces a better solution. The break/label solution gets part of the way there, but not all the way.webaddict wrote:Old? You mean the future days of "don't use goto"?
(#10850)