Page 6 of 6

Posted: Mon Mar 14, 2005 12:00 am
by lastcraft
Hi...

To the original poster, the answer to "should I use classes?" A few and don't overdo it without advice. OO is hard and you will spend a year digging yourself a deep hole before you learn to dig yourself out.
BDKR wrote:If it were the case that
OOP is good for everything and the only possible route to success then MySQL, Postgres, Linux, Windows, Solaris, Apache, PHP, Python, the Half Life 2 engine, the Quake engines, fuel injection control code, and even drivers would be written using actual objects.
I tend to avoid this type of thread these days, but I couldn't resist commenting on this one. Forum discussions are never 100% precise in the lawyer sense and once the temperature rises, well every word gets poured over. I am sure i am going to say some things that are both imprecise and contentious. I may have to backtrack here and there, but what the hell. Asbestos undies at the ready...

Firstly minor point. I don't have access to the Windows source code, but I am reliably informed that since the NT code base took over, everything above the HAL is C++. The Solaris source has just been released, but I couldn't find anything on the Sun site that gave me easy access to it. Python is written mostly in Python and has a small core. Apache is built around dynamic modules that are actually quite small and have a much more sophisticated dispatch mechanism in Apache 2. BMW at least uses Java in it's engine management code (I think they wrote the java CAN stuff). The Quake I engine (haven't looked at the others) uses a whole language layer (a C like language) on top of the core code. That core is actually suprisingly object based.

The other apps. I have not looked at and don't have time right now :(. In short, all the ones I have looked at found procedural C coding inadequate and and to implement another abstraction on top.

Now I am not going to say that every domain is best solved with OO, but I will say (here is the contentious bit) that in each domain there is a better paradigm than procedural. By "better" I mean more maintainable by the way, as this is the part that deals with the economics of software. Open source stuff does not always follow economics, but that's another story ;). The key to better here is "polymorphic" and I'll come back to that. Of course this is nothing more than proof by repeated assertion on my part. I'll plant the seeds of my defence next.

Within the enterprise software domain (big web sites and stuff) the dominant paradigms are OO and relational (data mining). Regarding application delivery, OO dominates hands down. Do a web search for consultants that have Fortune 500 companies as their clients and you'll see what I mean. Reading the Thoughtworks blogs gives a pretty clear idea too. OK, this is just proof by association, so I am only one step up from repeated assertion.

Time to resort to code (hooray :) ). Here is some business behaviour encoded recently...

Code: Select all

class CallMetered extends ApiChargingModel {
    function CallMetered(&$account) { ... }

    function payForCall($function, $results, $searches) {
        $template = &$this->_account->getPaymentTemplate();
        $currency = &$template->getCurrency();
        $cost = $template->getCost();
        $this->_account->deduct(new $currency($cost));
    }

    function paySubscriptionCost($now) {
    }
}
It's used in a web services API. If you've implemented a web services architecture you will know that the charging models are complicated and often involve individual deals. This class is built from the account preferences and then used by a ServiceRunner which communicates with an XML-RPC server.

The flex points involved in this are the account, the payment model for that account, the currency, the function called, the amount of results, a monthly or other subscription or surcharge, a banded payment, the success or otherwise of the call, the transport protocol and the means of payment (in advance, in arrears, immediately). We can keep this code clean and separated because so much is polymorphic. Dollars look like UkPounds, CallMetered looks like MonthlySubscription, ThesaurusService looks like AdultFilterService and XmlrpcServer looks like RestServer. Robbed of polymorphism this would be a nightmare, so hard to maintain that it would be impossible for practical purposes. OO is forced here.

But why not functional programming? After all it works for Google's mapping thingy. Well that involves a mental translation, one so complicated that I just don't know how to do it in this case. The functions have to dance around the data like a choreographed ballet. Business almost always focuses on behaviour and really doesn't care about data too much except for the final bank balance and as stuff that gets passed around. Objects allow us to hide data like no other paradigm. It allows us to bundle behaviour into named entities. This is a good fit for business modelling.

Why not relational? Relational is great for fixed tasks on complex data, but doesn't do so well if the data changes the structure of the processing. You would have to come up with a datamodel that captured every type of charging inone schema. A schema that would then be terribly sensitive to change and anightmare to understand. Relational doesn't do encapsulation very well. At least not yet. Relational theory had types in, but that's a whole other debate.

Business also changes a lot. Someone said in this thread that you had to design thoroughly if you were using OO? The opposite is the case. You can change things around much easier with OO, to the point you can actually put the design in after you start coding. Agile development is built around this principle.

The problems with OO? LIke any powerful paradigm it takes some learning. You wouldn't be a data modeller after only a year. You wouldn't be able to use a functional language to full effect without a university course and a fair understanding of mathematics.

Rasmus is a lone voice and now works for Oracle. He proposes putting all of the business logic into the database and having PHP as a thing templating system. Well that's probably a good thing for Oracle. Unfortunately only a small proportion of my code deals with a database, so that's no use to me, and I have to build something rather more complicated than a template layer. I think Rasmus is out of touch with the enterprise end of the PHP market.

I think the procedural option is a good thing for PHP because it opens it up to a wider audience. No use to me though. I no longer doing projects where it's viable.

yours, Marcus

Posted: Mon Mar 14, 2005 9:53 am
by McGruff
I should apologise for being so blunt in previous posts. I've been through the same discussion so many times and I'm definitely carrying some baggage around. I just wish there was some way to put this to bed once and for all.
BDKR wrote:Well first off, so nobody is confused, that's ADODB, not adobe.
Ahem. I'll have to stop using photoshop for db queries. The results do come out beautifully dithered though.

The class-free OOD which BDKR has touched on deserves respect as a weapon in the war against spaghetti. Nevertheless, I think it is very limiting in comparison to OOP. To my mind it's like trying to fill a swimming pool by hand with a leaky bucket compared to pressing the button on a turbo-charged pump unit which blasts out a jet of water strong enough to disperse entire crowds of rioting anti-OOPers at the garden gate ;)

- Objects aren't so well-defined. You might argue there are in fact no objects at all - just documentation. Access to the inner state of the data structures is not controlled.
- You've got to work harder to passing data around and more stuff is going to be exposed.
- You don't have inheritance more in this post by Vincent Voostinde.
- Polymorphism poses problems.

OO without classes is much weaker as a modelling language. I have no guarantee if the functions which the docs claim to be the sole members of a module are in fact the only ones which manipulate a particular data structure. In a complicated app, it could be easy for someone to pick the wrong function at the wrong time. If I find a bug, I'm going to have to read through all the code to check. And all those docs.

In OOP I'd have everything locked down in a class definition and a unit test. With the test, and good naming, I probably don't even need any docs - I can get on with producing something of real business value instead. You can of course write tests for procedural modules but you can never be sure if the final script doesn't break rules which exist only in the documentation. In this respect, there are no clearly delineated units to test. Encapsulating behaviour with data eliminates the problem.

In OOP testing is so important, and not just for quality control. It's also a design tool. Would it be possible to create a testing framework for procedural code with the equivalent of mock objects and expectations? (Without using OOP of course). Would it even make any sense?

The subtle difference between:

executeQuery($queryObj);

and

$query->execute();

is that one is imperative and one is declarative. In procedural you click the button, in OOP you telll the button to click.

Suppose you have a class with half a dozen private methods and just a couple in the interface. In procedural you could (imperatively) run all the functions one after the other on the data but now you've exposed all the private bits which the class did not. Or, you might have functions which contain other function calls, mimicing a class and its private methods. However, since there is no class scope, you've got more work to do passing data around to where it's needed.

This weekend I've been busy making some furniture. Horrible flat pack tat as it happens. Each box comes with a set of imperative instructions which explain how to build the item; as an OOP bigot, I really missed a declarative statement which would simply tell the furniture to build itself.

Anyway, suppose we have a client who wants a chest of drawers application. Let's model that in code.

Code: Select all

// OOP
$chest =& new Chest;
// procedural
$chest = createChest();
I want to put things in the drawers.

Code: Select all

// OOP
$chest->addItem($id, $item);
// procedural
addItem($chest, $id, $item)
Notice the extra parameter to pass in the procedural version.
I'll also want to take things out:

Code: Select all

// OOP
$item = $chest->getItem($item_id);
// procedural
$item = getItem($chest, $item_id);
Still got that extra parameter.

So far there's not much to choose between the two. Let's add a new factor: compression. Compression saves space allowing us to store more in the drawers. However, different items have different compression methods all of which have to be modelled. A sweater can be folded carefully rather than just stuffed in, saving a bit of space. An inflatable football could be deflated saving a lot of space. A pair of sunglasses can't be compressed at all.

We need a new object - Item. We want Items to know how to compress/decompress themselves. They will know their compressed and uncompressed size. In OOP that's no problem: size information is defined as class properties, and compress() decompress() methods are easily added to the Item interface. Different types of item will use different types compression but all present the same interface. The $chest object can simply call $item->compress() without knowing anything about the item type.

Procedurally, $item would be an array. Since behaviour is only notionally attached to procedural "objects" how can it know how to decompress itself? You could store a function name in the $item array alogside the rest of the item data. A generic compress($item) function could read the stored function name and apply the appropriate compression algorithm. That feels a little bit clumsy by comparison.

Also, if I have an array with information of several different types I'd normally take that as a smell suggesting refactoring into an object. In the procedural option, I'd expect to find that the array data structures will quickly become "overloaded" as things get more complex. Complex multi-dimensional arrays are more awkward to work with and it gets even harder to figure out which behaviour belongs with which data.

Next, let's look at a simple table template function:

Code: Select all

function createTable($data_structure) 
{
    $html = '<table>';

    while(false !== ($item = fetch($data_structure))) 
    {
        $html .= '<tr>';
        $html .= '<td>';
        $html .= $item;
        $html .= '</td>';
        $html .= '</tr>';
    }
    $html .= '</table>';
    return $html;
}
Let's assume we're comparing this with a Table class which takes an iterator as an argument. For simplicity the iterator has a single fetch() accessor (you'd need more than that in real life).

In OOP I can pass any kind of iterator to the Table class: an array iterator, a db result iterator and so on. I've got a big problem if I try to do the same procedurally: I can only define one function named "fetch". Behaviours notionally part a single object are in fact exposed to the entire script. If I have a series of tables in a layout which get their data from different types of data structure, I might have to write separate createTable functions with calls to fetchSqlResultRow() for a db query, fetchArrayItem() for an array, and so on. More work for the parser. Bread and butter OOP patterns such as Command and Observer suffer from the same problem. As in the drawers example, you could pass fn names in the hash to get around this - but it's not nice.

Passing fn names in the data structure could also deal with the weak (or rather non-existent) data/behaviour contract:

Code: Select all

function foo($data_structure) 
{
    if(!in_array('foo', $data_structure['allowed_methods']))
    {
        trigger_error('I\'m sorry Dave but I can\'t allow you to do that.', E_USER_ERROR);
    }
    
    // etc

}
Again, that seems clumsy in comparison to OOP and it does nothing to address the exposure problem in the createTable example. Classes exist in php: so why not use them?

In real life clients change their minds or simply don't comprehend their needs in sufficient detail until discussions with the programming team bring these out. OOP is more powerful as a modelling language and better at hitting this moving target. That's really what it's all about rather than code re-use.

Can you mix OOP and procedural? Well you can but there's a mismatch between imperative and declarative. I've never had to work with such a system but I'd expect this would interfere with refactoring.

BDKR has suggested OOP is slower and there are situations where this is unacceptable. In general I'm quite sceptical about the alleged performance hit with OOP. This isn't aimed at anyone in particular but being over-concerned with performance issues is, I think, looking in the wrong direction. Pre or post increments for example will get you nowhere. These things are good to know about but you must keep them in perspective. High-level languages like php are all about ease of expression and you shouldn't be afraid to use that. The correct direction in which to look, I think, is good design. If you don't have an easily maintainable, modular application it will be much more difficult to optimise.

In BDKR's example, with a huge load spike, I'd want to take a very careful look at the queries and indexing. If someone had an idea to boost performance I'd certainly want to do some benchmarking, but I can't see how using non-OOP php code to access the database is going to make a significant difference. Of course you know your own system much better than I, BDKR.

Some interesting discussion about optimisation here.

Posted: Tue Apr 05, 2005 10:48 am
by BDKR
GREAT POST! The best yet!

But there are still a couple of things that I will say.
The class-free OOD which BDKR has touched on deserves respect as a weapon in the war against spaghetti. Nevertheless, I think it is very limiting in comparison to OOP.
And that's all it is. A weapon against spaghetti. In those instances that I don't believe "full blown" OOP is the answer, I still keep these ideas in mind. But at the same time, OOD by itself is important to using objects proper. The term "OOD" itself refers to design with objects. The fact that those objects are conceptual or actual (perhaps I should say concrete) is besides the point. I don't know how many times I've said that.
To my mind it's like trying to fill a swimming pool by hand with a leaky bucket compared to pressing the button on a turbo-charged pump unit which blasts out a jet of water strong enough to disperse entire crowds of rioting anti-OOPers at the garden gate Wink
LOL! But seriously, nobody that has posted here is anti-OOP! You really need to step back and see if your feeling the need to says such things isn't do to zeal.

Anyway, you've done a very good job of explaining the difference between using Objects and merely using OOD with procedural code. There is not one thing that I'm going to dis-agree with. I've know all along it's limits that's why as a whole, I would prefer using objects as opposed to just passing data structues around. I implore you to go back and read the things that I've said in the past. Especially the idea that OOD trumps OOP in importance. Plain and simple as that.

You've got to remember that even I posted elsewhere in this thread that I have my own OO framework for database access that I still develop. Yes, it even uses real objects. :lol: Furthermore, (and I haven't yet said this on this board. I did mention on a car performance board.) I believe that over time OOP and scripting languages will be used more and more for what we consider low level tasks. Processors just keep getting more powerful. That said, why not take advantage of that power and develop low level controllers of various type in easier and faster to develop as well as less error prone OOL's like Python and Ruby? Languages like C and assembler are going to be around for sometime, but the march to high level languages is unstoppable.

There is also this...
BDKR has suggested OOP is slower and there are situations where this is unacceptable. In general I'm quite sceptical about the alleged performance hit with OOP. This isn't aimed at anyone in particular but being over-concerned with performance issues is, I think, looking in the wrong direction. Pre or post increments for example will get you nowhere. These things are good to know about but you must keep them in perspective. High-level languages like php are all about ease of expression and you shouldn't be afraid to use that. The correct direction in which to look, I think, is good design. If you don't have an easily maintainable, modular application it will be much more difficult to optimise.
I'll stand by any statement made by me and anybody else that well organized procedural code will be faster than well organized OO code.

There is also the idea that the moment someone talks about performance concerns, they are immediately overly concerned with the issue. From there the offender is guilty of the whole premature optimization thing (http://c2.com/cgi/wiki?PrematureOptimization). What a lot of people fail to realize is that it is very easy to see in advance where some issues will appear. In the example that I gave, it was allready a well known fact that the bulk of were placed in the last moments before post time. Therefore, what we made were design considerations. NOT optimizations after that fact. Nor where they done without evidence of well known conditions.
In BDKR's example, with a huge load spike, I'd want to take a very careful look at the queries and indexing. If someone had an idea to boost performance I'd certainly want to do some benchmarking, but I can't see how using non-OOP php code to access the database is going to make a significant difference. Of course you know your own system much better than I, BDKR.
This is bold as you were not there to know what was done from the viewpoint of physical configuration of the database hardware, configuration of the server, and long looks at the queries done by the developer of the transaction servers. We did a lot of work up front and made some modifications as we went. Ultimately, the database servers were capable of over 2100 inserts a second! That's nothing to sneeze at.

Our decisions were based on what was known at the time. For example, if John Lim, who wrote the ADODB php db abstraction layer noted a 30% overhead from not using any abstraction at all (just straight calls to the database) out of his own well optimized classes (and he did), then what logical assumptions can be made concerning a condition where we were seeing close to a million queries in 15 minute period?

There is another thing that occurs to me here, but I'm not sure exactly how to put it. It seems that the bulk of the developers here are seeing through glasses of a particular color. Perhaps I'm wrong and my apologies if that's the case. But how many here have had to develop applications, web based or otherwise, but also use PHP (or whatever) to aid in glueing together disparate systems in a cluster or even deal with routing issues and dynamically controlling 802.11b WWAN equipment? I even had a gig where we were beginning to deal with production floor automation (Python was getting the nod here!). What I really think I'm saying is that our experience has a lot to do with our views. I suspect mine may be a good deal different than that of most PHP developers. There are so many areas an object or collection of objects were overkill for a job.

However, if all I've done is application development (I include web sites here), then my view could very possibly be different.

But all that aside, I think your post is great. I really, really do. I just wish that you could see that there really is nothing to put to rest here. My argument is simply that OOP is not good for everything. I feel my experience bears that out.

Posted: Tue Apr 05, 2005 10:53 am
by BDKR
I'll respond to you lastcraft when I get more time. :wink:

Posted: Tue Apr 05, 2005 11:52 am
by The Monkey
I just wanted to bump in for a minute and comment on how much I enjoy reading the discussion you guys have going on here. I especially appreciated McGruff's last post complete with examples of OOP / Procedural accomplishing the same task - made the idea he was trying to say much simpler to understand. :D

Posted: Tue Apr 05, 2005 3:05 pm
by McGruff
Hi BDKR. I've definitely got coloured glasses: I feel there is a real need to actively encourage learner programmers to look at OOP seriously. At first glance it looks unecessarily complicated and inefficient. There's a hurdle to get over and a big commitment to make since it takes a year or two to really get to grips with so yes I'm cheerleading on the touchline. I'll even shave my legs and dress up in short skirt if it helps. I'd love to see a strong body of php work all unit-tested and OOP but it just doesn't exist.

And yes, my experience is purely with programming web apps so my comments should be seen as relating to what I see as the best practices to use if you're working with php in this area.