From: Robert C. Martin on
On 11 Jun 2005 20:45:47 -0700, "topmind" <topmind(a)technologist.com>
wrote:

>
>>
>> >> And bound to the RDBMS.
>> >
>> >You OO'ers always make that sound like a bad thing. Youses are
>> >DB-phobics. I don't want to be bound to OO, can we wrap that away too?
>> >(I agree that the DB tools are sometimes lacking in implementation and
>> >portability).
>> >
>> >> If we had done that, our tests would be too
>> >> slow, and we would have to ship the system to our users with some kind
>> >> of RDBMS attached.
>> >
>> >My RDB-bound wiki was not "slow".
>>
>> You misunderstand. I run over 1,000 unit tests, and over 100
>> acceptance tests on the system. These tests combined take about 90
>> seconds to run (on a bad day). The reason for this speed is that I
>> use the in-memory version of the page object.
>
>I am not sure what your point is.

My point was that I was not suggesting that your RDB-bound wiki was
slow. I *was* suggesting that my tests would run slower if they used
a database.

>Do you have tests that show
>a RDBMS implementation would not scale as well?

No, it didn't seem necessary. I think I could finish running all the
unit tests before the RDB had finished building a connection. (slight
exaggeration).

>> >
>> >Anyhow, one can do something like this:
>> >
>> >function getWikiArticle(articleID) {
>> > if (sys::driver==RDBMS) {.....}
>> > elseif (sys::driver==Files) {.....}
>> > elseif (sys::driver==RAM) {.....}
>> > else {error())
>> >} // end-function
>>
>> True, one could do that. However, that makes a generic function
>> (getWikiArticle) depend upon three different implementations. That
>> kind of coupling is unfortunate. I'd rather have the getWikiArticle
>> function not know about RAM, RDBMS, and FILES, and that's what
>> polymorphism gives me.
>
>If we had hundreds of different "drivers" I could see the advantage of
>polymorphism. However, that is not likely in this case. Companies don't
>want to pay for multiple implementations of the same thing in most
>cases and RDBMS are a safe bet for most apps in my domain. It would be
>a poor investment to target the 1% who may want to use flat files
>because they hate Dr. Codd.

Nobody is talking about hating RDBs. In any case the cost of the
polymorphism was negligible, and it quickly enabled our user to add
the RDB plug-in when he needed it. Without that polymorphism, his
task would have been quite a bit more difficult.

>And, I am not fully clear on what you mean by "depend upon".

Given two binary modules A and B. If A mentions B, or a unique name
that lives within B, then A depends on B. This means A cannot be
deployed without B. It also means that if B changes, there is a
strong likelihood that A will need to be recompiled and redeployed.

Our user who produced the RDB plug-in for FitNesse was able to create
a new binary module that FitNesse did not depend upon. He then
modified a config file that told FitNesse the name of that binary
module. FitNesse used that binary module instead of it's internal
modules for page persistence.

Your point above about polymorphism being useful if there were
hundreds of different drivers comes into play here. We don't know how
many drivers there are for FitNesse. There *may* be hundreds of them.
The use of polymorphism has enabled our users to create them, without
forcing them to modify the source code of FitNesse to do so.

Consider, as another example, an ATM machine. The basic unit can do
standard things like deposit, withdrawal, and transfer. However, the
manufacturer would like to sell new features to their users, such as
pay gas bill, pay electric bill, pay credit card, etc. If the
software developers use polymorphism to dispatch to the features, then
the manufacture can sell new features simply by selling new DLLs or
jar files, without having to alter the source code of the existing
system, nor change the binary code of the ATM machines already in use.

>> >But I would really like to see poly in business-modeling issues, not
>> >storage and EXE distribution issues.
>>
>> Then look at the way FitNesse handles everything else. Or look at the
>> payroll example in the PPP book. (The library likely has a copy. If
>> not, a local Barnes and Noble will have one.)
>
>What are the hierarchies used? Please don't tell me it uses "account
>types". I addressed that in a sister message.

The word "Hierarchy" is a bit misleading. Although there is a lot of
polymorphism used in the example, there are very few class hierarchies
that have more than two levels. Typically the top level is an
interface, and the next level down completely implements that
interface. There are some exceptions to this rule, especially in some
of the transaction types.

Basically the structure looks like this:

|Payroll|----->|Employee|
* |
+--------->|PayClass|
|
+--------->|PaySchedule|
|
+--------->|PayDelivery|

Each of the classes on the right is an interface, for which there are
several derivatives (shown below).

The algorithm in the Payroll class is (partially):

void Payroll::pay() {
foreach Employee e {
if (e.isPayDay(today)) {
Money pay = e.calculatePay();
e.deliverPay(pay);
}
}
}

The Employee class looks something like this:

class Employee {
private PayClass payClass;
private PaySchedule paySchedule;
private PayDelivery payDelivery;

public bool isPayDay(Date date) {
return paySchedule.isPayDay(date);
}

public Money calculatePay() {
return payClassification.calculatePay();
}

public void deliverPay(Money pay) {
payDelivery.deliverPay(pay);
}
}

There are three derivative of PayClass:

|PayClass|
A
|
+----------------+------------------+
| | |
|HourlyPayClass| |SalariedPayClass| |CommissionedPayClass|
| |
|* |*
V V
|TimeCard| |SalesReciept|

The 'calculatePay' method of PayClass is polymorphic. It is
implemented in HourlyPayClass to sum up the contained time cards and
calculate overtime.

It is implemented in SalariedPayClass to return the monthly salary.

It is implemented in CommissionedPayClass to sum up the sales
reciepts, apply a commission rate, and add a base salary.

There are three derivatives of PaySchedule:
WeeklySchedule, MonthySchedule, BiWeeklySchedule.

The 'isPayDay' method of PaySchedule is polymorphic. It is
implemented in WeeklySchedule to return true if the argument is a
Friday. Monthly schedule returns true if the argument is the last
business day of the month. BiWeekly schedule returns true only for
every other Friday.

There are three derivatives of PayDelivery:
MailDelivery, DirectDepositDelivery, and PaymasterDelivery

The 'deliverPay' method of MailDelivery causes the employees paycheck
to be mailed to him. You can guess what the others do.

This is just one very small part of the payroll application as
described in the www.objectmentor.com/PPP book. One nice thing about
this design is that the code inside the payroll class can be placed in
a binary module (a dll or jar file) and deployed independently from
the rest of the system. If we have a customer who has nothing but
hourly employees, we can simply ship the payroll module, and module
that contains HourlyPayClass. Moreover, users can add new PayClasses,
Schedules, and Delivery mechanisms without having to alter the source
code of the payroll application.

>> It's good for many things, not for everything. It's use is
>> situational, not specific to particular domains. There are situations
>> within every domain in which polymorphism is both useful and not.
>> That includes drivers, persistence, telecommunications, business
>> rules, guis, etc, etc. Wherever dependencies need to be managed
>> (which is just about everywhere) there is a potential for polymorphism
>> to facilitate that management.
>
>Well, perhaps if the situations where it is useful and not are
>clearified, we might find our areas of agreement. Is it only helfpul if
>one can find a good, safe hierarchical classification or multiple
>implementations of the same thing (device drivers)?

I described this in a different email. In summary, polymorphism is
useful when you want to be able to add new data structures (like
PayClass derivatives, PaySchedule derivatives, or PayDelivery
derivatives) without affecting existing functions (like Payroll:pay).

Switch statements are useful when you want to add new functions
without affecting existing data structures.


-----
Robert C. Martin (Uncle Bob) | email: unclebob(a)objectmentor.com
Object Mentor Inc. | blog: www.butunclebob.com
The Agile Transition Experts | web: www.objectmentor.com
800-338-6716


"The aim of science is not to open the door to infinite wisdom,
but to set a limit to infinite error."
-- Bertolt Brecht, Life of Galileo
From: Isaac Gouy on
Robert C. Martin wrote:
> You *may* have to do that, if you don't have a generic way of
> representing shapes. Let's say that we don't. The solution to this
> problem has been around for a long time. It's called multiple
> dispatch. (e.g. some languages allow you to polymorphically dispatch
> on more than one argument. Thus (intersect(s1, s2) selects a function
> that conforms to the type of both s1 and s2.

For example, Nice, http://nice.sourceforge.net/

abstract class Shape {}
class Circle extends Shape {}
class Rectangle extends Shape {}

void intersect(Shape s1, Shape s2);
intersect(Circle s1, Circle s2){}
intersect(Circle s1, Rectangle s2){}
intersect(Rectangle s1, Circle s2){}
intersect(Rectangle s1, Rectangle s2){}

void main(String[] args){
let r = new Rectangle();
let c = new Circle();
c.intersect(r);
c.intersect(c);
r.intersect(c);
r.intersect(r);
}


> Most OO languages don't have multiple dispatch. However, just as
> general trees are isomorphic with binary trees, so too is multiple
> dispatch isomorphic with dual dispatch. (i.e. the Visitor pattern).

For more information on binary methods in OO, multimethods and
double-dispatch, see
On Binary Methods (1995) Kim Bruce, Luca Cardelli, Giuseppe Castagna,
et al.
http://citeseer.ist.psu.edu/3113.html

From: Isaac Gouy on
Robert C. Martin wrote:
> On 12 Jun 2005 10:11:39 -0700, "topmind" <topmind(a)technologist.com>
> wrote:
>
> >
> >Switch/case statements are more flexible.
>
> For some thing, and not for others.
>
> If you use switch statements then adding functions to existing data
> structures is relatively easy. All you do is replicate the switch
> statement in the new function, and fill in all the cases.
>
> However, with switch statements, adding new data structures to
> existing functions is hard. You have to find every existing switch
> statement and add the new case.
>
> If you use polymorphism then the reverse is true. Adding new data
> structures to existing functions is easy. All you do is write the new
> class, and all the existing functions polymorphically deploy to it.
>
> However, with OO, adding new functions to existing data structures is
> hard. You have to find every subclass and add a new method.
>
> Sometimes you want to be able to add new functions to existing data
> structures, and so you use a switch statement. Sometimes you want to
> be able to add new data structures to existing functions, and so you
> use polymorphism.
>
> They are yin and yang, opposite and complementary. Using just one or
> the other is imbalanced.
>
>
>
>
>
> -----
> Robert C. Martin (Uncle Bob) | email: unclebob(a)objectmentor.com
> Object Mentor Inc. | blog: www.butunclebob.com
> The Agile Transition Experts | web: www.objectmentor.com
> 800-338-6716
>
>
> "The aim of science is not to open the door to infinite wisdom,
> but to set a limit to infinite error."
> -- Bertolt Brecht, Life of Galileo

Seems like what's become known as "the expression problem"

See
"Independently Extensible Solutions to the Expression Problem" Matthias
Zenger, Martin Odersky
(200KB) http://scala.epfl.ch/docu/files/IC_TECH_REPORT_200433.pdf

From: Isaac Gouy on
Robert C. Martin wrote:
> On 12 Jun 2005 10:11:39 -0700, "topmind" <topmind(a)technologist.com>
> wrote:
>
> >
> >Switch/case statements are more flexible.
>
> For some thing, and not for others.
>
> If you use switch statements then adding functions to existing data
> structures is relatively easy. All you do is replicate the switch
> statement in the new function, and fill in all the cases.
>
> However, with switch statements, adding new data structures to
> existing functions is hard. You have to find every existing switch
> statement and add the new case.
>
> If you use polymorphism then the reverse is true. Adding new data
> structures to existing functions is easy. All you do is write the new
> class, and all the existing functions polymorphically deploy to it.
>
> However, with OO, adding new functions to existing data structures is
> hard. You have to find every subclass and add a new method.
>
> Sometimes you want to be able to add new functions to existing data
> structures, and so you use a switch statement. Sometimes you want to
> be able to add new data structures to existing functions, and so you
> use polymorphism.
>
> They are yin and yang, opposite and complementary. Using just one or
> the other is imbalanced.
>
>
>
>
>
> -----
> Robert C. Martin (Uncle Bob) | email: unclebob(a)objectmentor.com
> Object Mentor Inc. | blog: www.butunclebob.com
> The Agile Transition Experts | web: www.objectmentor.com
> 800-338-6716
>
>
> "The aim of science is not to open the door to infinite wisdom,
> but to set a limit to infinite error."
> -- Bertolt Brecht, Life of Galileo

Seems like what's become known as "the expression problem"

See
"Independently Extensible Solutions to the Expression Problem" Matthias
Zenger, Martin Odersky
(200KB) http://scala.epfl.ch/docu/files/IC_TECH_REPORT_200433.pdf

From: topmind on

> >>Says the person who hasn't presented objective evidence
> >>supporting his position.
> >
> > It is my opinion that paradigm preference is largely a *subjective*
> > thing. Thus, there is not much to objectively prove either way.
>
> Then why do you keep asking for objective evidence from the OO guys?
>

If you guys also believe the benefits of OO or poly are subjective
instead of absolute, then simply say so and then we are done. That is
not the message I get from youses.

-T-

First  |  Prev  |  Next  |  Last
Pages: 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
Next: Use Case Point Estimation