Page 2 of 2

Re: OOPHP Advocacy arguments

Posted: Wed Oct 08, 2008 11:09 am
by allspiritseve
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.

Re: OOPHP Advocacy arguments

Posted: Wed Oct 08, 2008 12:28 pm
by Christopher
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. 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.
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.

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 ;)). It not like the old "don't use goto" days. But you need to learn the general best practice first -- then develop the wisdom to know when the general rule does not apply.

Re: OOPHP Advocacy arguments

Posted: Thu Oct 09, 2008 9:32 am
by webaddict
allspiritseve 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.
You've just walked in my trap :) My whole point in writing all of those paragraphs is that you're saying they are boolean values, while I am trying to tell you that you shouldn't care whether or not they are boolean values. You shouldn't care if the object uses other objects to do the actual action, you should only care that Page has a publish( ) function and that it actually publishes the page.

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.
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.
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.

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.
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.
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: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.
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:
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.
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.
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.
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: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.
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?

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( ) );
?>
 
See how that works? The first is aware of implementation and if you'd change this implementation, all tests would fail. In the second case, the change wouldn't effect the test, assuming the new implementation will execute the expected behaviour. It's all about implementation vs. interface, really. It's really a shame that most people know the saying "program to an interface instead of an implementation" and still are programming to the implementation. I'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 :)
allspiritseve 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.
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 concentration :lol: However, I'll read up on it and see if this is a good fit for the problem at hand. Thanks for the link.
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.
"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.
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.
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.

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).
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 ;)).
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:It not like the old "don't use goto" days.
Old? You mean the future days of "don't use goto"? :D

Re: OOPHP Advocacy arguments

Posted: Thu Oct 09, 2008 10:55 am
by allspiritseve
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.
I think you're completely missing my point. You don't have to lecture me on encapsulation and misplaced functionality. I understand their benefits.

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.
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 concentration :lol: However, I'll read up on it and see if this is a good fit for the problem at hand. Thanks for the link.
Sorry, I mentioned that one because its one of the few examples in PHP. I can try and whip up an example:

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>
 
Sure, it's simplistic, and an array would do so much better in this example, but you can see how the getters/setters are taken out of the domain object. Imagine an SQLBuilder that could construct a portion of a query to update the db, as well. I think it's overkill for most situations, but maybe you'll find a use for 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 :)
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.

Re: OOPHP Advocacy arguments

Posted: Thu Oct 09, 2008 12:36 pm
by Christopher
webaddict wrote:Besides, I resent the thought that object oriented programming is a better way to program than functional or procedural can be.
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:Old? You mean the future days of "don't use goto"? :D
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.