OO debate: assuming type of containing object

J

John A Grandy

I'm in a vigorous debate at my work regarding objects assuming knowledge of
the type their containing object.

This debate pertains specifically to ASP.NET, but I have decided to post in
the C# forum because this is where most of the OO gurus hang out, and I view
this as a fundamental issue of OO design.

In ASP.NET, objects of type WebForm and UserControl have an intrinsic Page
property which refers to their containing Page.

So, for an instance of UserControl1 "oUserControl1" located inside an
instance of WebForm1 "oWebForm1" , oUserControl1.Page = oWebForm1.

Nesting is also possible: for an instance of UserControl2 "oUserControl2"
located inside oUserControl1, oUserControl2.Page = oWebForm1.


By default, WebForms inherit from the base ASP.NET Page class :
System.Web.UI.Page.

One common pattern is to include common page functionality in a derived
class, and then derive all WebForms from it. For example, CorePage :
System.Web.UI.Page.

So if we define WebForm1 : CorePage , it is possible and convenient to write
following code inside UserControl1 :

((CorePage)Page).CustomProperty = "abcd";
((CorePage)Page).CustomMethod( textBox1.Text );

But if you do write such code, instances of this UserControl can only be
located inside WebForms which derive from CorePage.

We can also write the above code inside UserControl2. But if we do, all
instances of UserControl2 must be ultimately contained in WebForms which
derive from CorePage.


The debate is as follows: I argue that there are other ways for
UserControls to trigger functionality provided by containing objects.
Events are one such mechanism. I do not think that portability of objects
should be compromised in favor of coding convenience.

Others argue that for our project there is no anticipated need to ever use
WebForms that do not derive from CorePage. Further they argue that making
such an assumption is non-agile ( "agile" being a buzzword of such import on
the current sw dev scene that those arguing against "agile" are branded as
witches and burned at the stake).
 
C

Chris Mullins [MVP - C#]

John A Grandy said:
Others argue that for our project there is no anticipated need to ever use
WebForms that do not derive from CorePage. Further they argue that making
such an assumption is non-agile [...].

I'm on the fence for most of this, but having been down this EXACT path a
number of time, I've got some input here.

In many projects I've worked on, both Winforms and Web, we've had this
debate. Being from a C++ background, we usually end up grumbling about the
lack of Multiple Inheritence, and the horrible way .Net forces us to decide
here. Interfaces are clearly not the answer, and a mandated inheritence tree
is clearly not the answer. (But this isn't going to change, and yet another
rant of on this topic is pointless...)

In nearly every case, we've started with "SoapBoxUserControlBase" or
"SoapBoxFormBase". In nearly every case, we've ended up ripping this code
out. I guess we're just stubborn in that we keep doing it the hard way. We
also often need to put this functionality on classes that are not UI based,
which causes obvious issues.

We typically end up creating an Interface ("ISoapBoxSomething") and then
implementing this interface on the pieces that need it. Usually this has a
few events defined on it, and few properties. This ends up being the most
agile approach, as it allows the most flexability and the most change.

The obvious pattern here is a Decorator pattern, but for some reason we
often don't end up using it. I'm not quite sure why that is...
http://www.google.com/search?q=Decorator+Pattern
 
P

Peter Duniho

[...]
The debate is as follows: I argue that there are other ways for
UserControls to trigger functionality provided by containing objects.
Events are one such mechanism. I do not think that portability of objects
should be compromised in favor of coding convenience.

Others argue that for our project there is no anticipated need to ever use
WebForms that do not derive from CorePage. Further they argue that making
such an assumption is non-agile ( "agile" being a buzzword of such import on
the current sw dev scene that those arguing against "agile" are branded as
witches and burned at the stake).

Not to suggest that there's any value in using the latest buzzwords to
justify one's position (especially when they seem to be misused...how
is locking yourself into a specific design supposed to be "agile"?),
but at least from what you've posted it's not clear to me that your
position is the correct one.

Nothing about the example you provided suggests an obvious event-based
interface, nor do I feel that using an event necessarily avoids the
issues with respect to one class making assumptions about another. In
particular, if you could define a general-purpose event that satisfies
the need for generality, you could define a base class or interface
that does the same thing.

IMHO, events are useful for a specific purpose, related to supports a
particular kind of callback mechanism. They are orthogonal to the
question of inter-class dependency.

Now as far as that question goes (the one of inter-class dependency),
I'm all for designing code so that it can be reused, but I'm also not
in favor of obfuscating a design just so that you can keep your objects
separate. If an object truly depends on the specific behavior of
another object in some way, then I don't see any problem at all
representing that in the class design.

In the example you posted, as near as I can tell your control class
_does_ in fact depend on the CorePage class. Assuming it's a valid
dependency, I don't see any way around having your control class refer
specifically to the CorePage class.

That's not to say you can't create a reusable design. While you've
provided very little in the way of specifics regarding the design
you're dealing with, you certainly could separate your class hierarchy
out so that you parallel the dependent components. Specifically, have
both custom base page and control objects rather than just a custom
page object. In your control classes, put into the base class the
functionality that can be written dependent only on the original base
Page class, and put into a derived class the more specific
functionality that is dependent on your custom derived CorePage class.

In that way, if you do need to reuse the control code that isn't
dependent on the custom CorePage class, that's easily done. At the
same time, you have a derived control class that can make whatever
assumptions it needs to about the CorePage container instance.

If the above does not make sense in your scenario, I'll suggest that
your question is just too ambiguous. If you want a more sensible
reply, you should post a more concrete example. In particular, a very
simple example of each of the two designs you are trying to compare,
illustrating the class hierarchy and an example of the inter-class
dependency that concerns you. With an example like that, it will be
much easier to understand the question, as well as easier to understant
your suggestion that an event-based solution would be better, and
finally easier to comment usefully, providing specific alternatives to
the example you provide.

Pete
 
J

John A Grandy

Note that the "but that's non agile !" argument is in reference to
anticipating a need which does not currently exist (e.g. anticipating that
at some point in the future a given UserControl woulk need to reside in a
WebForm that does not derive from CorePage).

As far as more concrete examples, there are many, but there is a single
piece of functionality which all UserControls need access to :

This is configuration and display of a MessageDisplay UserControl that
generates custom script that displays errors and other informational
messages to the user.

Although we currently have no scenarios in which multiple UserControls would
need to originate such messages for a single postback, we decided to write
the MessageControl as a message aggregator.

The design you mention of creating a UserControl base class,
CoreUserControl, and requiring that any UserControl that might be contained
in a WebForm that derives from CorePage must derive from CoreUserControl,
was discussed but discarded as unnecessarily complex and involving too much
retrofit (bottom line "not agile!").

Events were discarded as too much coding-cost and added complexity. A
polling mechanism, doubly so.

What is driving this debate on the opposing side is really coding
convenience.

My argument is that very large swaths of intricate highly-tested UI
functionality are gradually being built into various UserControls. I
believe that the huge dev investment in these UserControls will be leveraged
at some point. We are a rapidly growing company, and sister applications
developed by separate dev groups are entirely possible. Even if not
planned, it may become business-imperative at some point for us to transfer
pre-built pieces of functionality to those groups.

This is where I think the agile dogma really breaks down. People become
empowered to argue against solid OO infrastructures on the basis that such
additional effort is "non-agile".
 
P

Peter Duniho

Note that the "but that's non agile !" argument is in reference to
anticipating a need which does not currently exist (e.g. anticipating that
at some point in the future a given UserControl woulk need to reside in a
WebForm that does not derive from CorePage).

You and your team should probably have a jar into which anyone who
mentions the word "agile" is required to put a quarter, or a dollar, or
something like that.

IMHO, using that word to describe code is pointless. It's a loaded
word without a good definition. All you have to do is say something's
"not agile" and it automatically becomes bad. Conversely, all you have
to do is say something is "agile" and it automatically becomes good.
Whether it is or is not actually bad or good. After all, who doesn't
want to be "agile"?

Personally, if I were forced to use the word "agile" to describe a
design or implementation, I would say that the more general, more
reusable design or implementation is more "agile" in the long run. But
really, I'd prefer not to be forced to use the word "agile" in the
first place. It's way too vague and prejudicial.
As far as more concrete examples, there are many, but there is a single
piece of functionality which all UserControls need access to :

This is configuration and display of a MessageDisplay UserControl that
generates custom script that displays errors and other informational
messages to the user.

That's not a concrete example. That's an abstract description of some
general functionality.
Although we currently have no scenarios in which multiple UserControls would
need to originate such messages for a single postback, we decided to write
the MessageControl as a message aggregator.

The design you mention of creating a UserControl base class,
CoreUserControl, and requiring that any UserControl that might be contained
in a WebForm that derives from CorePage must derive from CoreUserControl,
was discussed but discarded as unnecessarily complex and involving too much
retrofit (bottom line "not agile!").

I never suggested that all controls need to inherit the same base
class. I'm saying that if there is really a possibility of reusing a
control outside of a context where the CorePage class is used, then
that means there is some portion of the implementation of the control
that doesn't depend on the CorePage class, and which can be put into a
separate base class that doesn't depend on the CorePage class.

Again, given the lack of a concrete example who knows if that advice is
actually useful in your case. But it's what comes to mind when I read
your message.
Events were discarded as too much coding-cost and added complexity. A
polling mechanism, doubly so.

Again, I don't see how events (or even polling) comes into play here.
If you've got some specific behavior that exists in the CorePage class
and is unique to that class, it has to be represented somehow. And it
has to be accessed somehow. You can't access that representation
without having some concrete dependency on the class.

How best to represent and implement that dependency depends on a
variety of factors, but ultimately that dependency will exist.

Anyway, I don't really get the feeling that you're looking for anything
other than a statement that fully supports your own position on the
matter. I'm not sure that a thread in a newsgroup is really the best
way to resolve the issue, especially when there's no concrete example
to play with and talk about.
[...]
This is where I think the agile dogma really breaks down. People become
empowered to argue against solid OO infrastructures on the basis that such
additional effort is "non-agile".

See above for my feelings about using the word "agile".

Pete
 
J

John A Grandy

Eventing would work as follows : CoreUserControl would implement a
DisplayMessage event. In the PreRender event of container pages, delegates
would be added for the DisplayMessage event of each contained control. Every
delegate would point to the same handler that would aggregate the message
info into the MessageDisplay control.

Polling would work as follows: CoreUserControl would expose properties
relevant to displaying a message. In the PreRender event of container
pages, the controls collection would be recursively iterated, checking those
properties and aggregating all messages into the MessageDisplay control.

An even better solution would be to locate a single MessageDisplay control
in the MasterPage and perform the polling in the MasterPage's PreRender
event.

In none of these solutions is any dependency between CoreUserControl and
CorePage is required.


(I'm using the term "polling" a little loosely.)
 
P

Peter Duniho

[event and polling abstract descriptions snipped]

In none of these solutions is any dependency between CoreUserControl and
CorePage is required.

I disagree. In each example, you wind up requiring something to be
implemented in your CoreUserControl that is specific to the CorePage.

I agree that by putting the dependency entirely as a queryable sort of
thing (subscribe to the event, look for a property, etc) you allow the
controls to be in a container other than the one you've designed for.
But then your controls have at best some wasted code (inefficient) and
at worst include functionality that the author of the code assumes (for
better or worse) will actually be used, causing problems if it's not
(for example, what happens when an author of a control creates some
sort of message queue that gets cleared any time a property was
queried, but the property is never queried?).

I don't have anything in particular against those particular solutions,
but I think it's a mistake to assume that they in and of themselves
protect you against dependencies. They don't, unless you impose
additional rules to be followed. And in some respects, they are more
dangerous because the dependencies can be subtle and
implementation-dependent, rather than being codified in the design.

More fundamentally, I disagree with the assertion that there is no
practical solution to writing code that makes an assumption about the
container while still preserving reusability. See my previous posts.
Whether that's the solution you want, I can't say. But if you've got
people who are set on doing something like that, it's not going to get
you anywhere to say that it won't work at all, because that's a
proveably false statement. If you would promote an event-based
solution, you need a more compelling argument than a proveably false
statement. :)

Pete
 
J

John A Grandy

Events are the standard ASP.NET mechanism for transferring data to and
triggerring behavior in parent containers. To eliminate any dependencies,
we can build the event code directly into each UserControl. If it is
desired that the container control act upon these events, appropriate code
can be added. Thousands of ASP.NET user controls and server controls have
been written using this model. Hundreds of these are solid commercial
products deployed in hundreds if not thousands of large-scale production
apps.
 
P

Peter Duniho

Events are the standard ASP.NET mechanism for transferring data to and
triggerring behavior in parent containers. To eliminate any dependencies,
we can build the event code directly into each UserControl. If it is
desired that the container control act upon these events, appropriate code
can be added. Thousands of ASP.NET user controls and server controls have
been written using this model. Hundreds of these are solid commercial
products deployed in hundreds if not thousands of large-scale production
apps.

Thank you for the review on industry use of events. I don't know how,
but I guess I must have given you the impression that I'm ignorant or
something.

I'm not saying that using events wouldn't work. I'm not saying that
there are no advantages to using events. I'm not even saying that I
know for sure that events aren't the best way to address the issues
you're dealing with. What I _am_ saying is that if you define an event
for the express use of your CorePage class, then that's a dependency in
the class defining the event on that CorePage class.

It's a different kind of dependency to be sure, but it's still a dependency.

You seem to believe that this is a cut-and-dried case of you being
right and everyone else (on your team) being wrong. I think that's far
too narrow-minded a view to take. If you are going to convince your
team to follow your lead, you need to find more compelling arguments in
favor of your design than those you've stated here.

And that's not to say such arguments don't exist. Events are a nice
way to solve things. But as long as you act like they completely avoid
any dependency between the classes, you're going to have trouble
convincing anyone who knows otherwise.

Pete
 
J

John A Grandy

I'm just stating arguments.

If Chris Mullins is a good indication, then lots of teams are having this
debate.

What I don't understand is why the pro-casting side won't admit that their
argument is a pure coding convenience argument. Instead you hear ridiculous
things such as "the designers of ASP.NET must have wanted you to do it this
way or they wouldn't have provided the intrinsic Page object".

I wonder what ScottGu thinks.
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

John said:
The debate is as follows: I argue that there are other ways for
UserControls to trigger functionality provided by containing objects.
Events are one such mechanism. I do not think that portability of objects
should be compromised in favor of coding convenience.

Others argue that for our project there is no anticipated need to ever use
WebForms that do not derive from CorePage. Further they argue that making
such an assumption is non-agile ( "agile" being a buzzword of such import on
the current sw dev scene that those arguing against "agile" are branded as
witches and burned at the stake).

How the communication between controls is done, isn't only about
reusability. By keeping the communication channels as limited as
possible, they can be kept well defined and easily manageable.

For example, when a control wants access to a method in a common base
class for the page, it's not a bad idea to use an interface, for several
reasons:

:: You get a reference to an interface, with which you can only do what
was indended.

- The intellisense won't show you half a million other properties,
methods and events from the Page class that you don't care about.

- You can't use a method from the Page class instead of a method from
the base class by mistake, as they are simply not available.

:: It's flexible, as the interface can either be implemented by a base
class or by the page itself, and the control doesn't have to know which
it is. If one of the pages needs to implement


Creating pages and controls that depend on each other doesn't only
prevent reusability, it also makes the code harder to follow. You have
to be aware of all the code in the page and all the code in all
controls, to be able to tell how the code is working. Welcome back,
spaghetti code...

If a control instead uses interfaces and events, you can tell how the
code in the control is working without knowing anything about the code
in the page and the code in other controls on the page. This is how OO
programming should be.
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

Göran Andersson said:
How the communication between controls is done, isn't only about
reusability. By keeping the communication channels as limited as
possible, they can be kept well defined and easily manageable.

For example, when a control wants access to a method in a common base
class for the page, it's not a bad idea to use an interface, for several
reasons:

:: You get a reference to an interface, with which you can only do what
was indended.

- The intellisense won't show you half a million other properties,
methods and events from the Page class that you don't care about.

- You can't use a method from the Page class instead of a method from
the base class by mistake, as they are simply not available.

:: It's flexible, as the interface can either be implemented by a base
class or by the page itself, and the control doesn't have to know which
it is. If one of the pages needs to implement

Lost it in the middle of a thought there... ;)

If one of the pages needs to implement the methods differently, that can
be done without changing the base class to handle it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top