Re: OODesign - OPF, design pattern
- From: "Peter Morris" <support@xxxxxxxxxxxxxxxxxxxx>
- Date: Wed, 29 Aug 2007 16:28:00 +0100
Maybe I am, I can't be sure. After all, it's the implementation that I
see and have to deal with, usually. If it's bad, so is my opinion about
the underlying concept.
If the film is crap the book must be too :-)
when I hear someone tell me they're going to use the Visitor pattern to
extend their class, I always cringe a little. Why can't they simply
change the class in question? It's under their control, for goodness
sake!
I can understand why people would use it. For example, why should class
that has absolutely nothing to do with XML know how to serialise/deserialise
itself to XML, Binary, or a maybe a DB? Why should it know how to print to
PDF, PNG, or a printer? These are all operations that are the
responsibility of another class.
If I had such a requirement then I'd use the visitor pattern. So far though
I have not used it. I went to use it once for writing some XML but soon
found it was too much work. If I have to get this structure to do lots of
different things that are not related to site visits + actions then maybe I
will put it back :-)
To me, that's doing things just for the sake of things, and it's nothing
more than a diversion from the boredom of conventional ways.
And over complicating it too in my opinion.
For the record, I'm not saying that's necessarily you, Peter (although
your initial post made me wonder quite a bit :))! I'm merely observing
my immediate reality.
My ProcessParameters stuff? The purpose of that is to allow the exact same
code to run on PPC, Desktop, WebService, or WebSite.
I can see a big problem with this. It may be fine for a single
developer, or even two developers who think alike. But a team of
developers can hardly be left waiting while one of them is tweaking
the framework. It becomes a serious bottleneck!
Correct, if there were many of us writing it then we'd have to do something
else. Now that it is written we have had 2 or 3 people writing the app at
the same time. It's very easy because each task is in its own file so it's
quite easy for many people to work on it at the same time.
My grudge with OO frameworks (not OO in general!) is that they are
usually being developed as you go. And there's really no other way,
because they are so broad (and potentially capable, I'm not denying
that), they'd take forever if you'd try to implement them in their
entirety before moving on to actual business logic of your product.
That's why you develop what you need now, and extend it when you need
something else. As long as you don't throw in "dirty hacks" your framework
will remain "nice" :-)
It's a bad example, but I've seen a case of abstracting away the
creation of the main form in a Delphi application a few years back. It
took around a 100 lines of code to do it and was IMO a shining
demonstration of what not to do
http://www.hmrc.gov.uk/employers/employee_leaves.htm
Oooh, another pet peeve! Code generators.
<sarcasm>Tools that help me solve a problem I probably wouldn't even
have if I'd just stay away from complex frameworks.</sarcasm>
Or, tools that let me work visually, which is usually much easier because
01: It's easier to get an overview of what you are doing.
02: It's easier for the customer to understand, and therefore more likely to
be correct from the start.
Seriosuly, though... They /can/ be beneficial. But they can also
inflict hidden maintenance costs if there's too much code. And some
frameworks out have code generators there are spewing out enormous
amounts of auto-code.
I don't know what to say. I don't suffer any such problems. I just change
my model and click Generate Code. My existing source is updated, preserving
all my method implementations etc. If I want to change the code that is
generated I change the generator and then regenerate. My generator only
"spews out" what I would have typed, but it does it quicker and more
accurately.
In reality, I don't see much difference in modifying a class diagram
and modifying a class manually. Properties and methods are hardly too
complex to write. A properly configured template expansion in modern IDEs
can save just as much time as a separate dialog where you need to
enter 80% of the same strings anyway.
It depends on what you do. For example, try manually writing a complex
state machine. Give me UML any day!
Sure, if you boil it down to this level, it's almost the same diagram
for both OO design and the conventional design. But we both know that
once you zoom in even just a little, OO design reveals more layers.
No, I meant exactly that. A layer in the middle that returns sets of data
and also reacts to certain changes in the data it is passed back. E.G.
Changing the state of something from Editing to Submitted could create
another row notifying someone in the publishing department to take a look at
it.
For
example, say you're using the .NET grid control, but you need a more
feature-rich control. So you decide to switch to DX XtraGrid.
With a conventional design, you need to crewrite all the event handlers
and all the code that's calling the grid control in any way.
With OO design, you need to change the adapter class in your View that's
hooked up to those same event handlers and, if you're lucky, only the
implementation of the adapter's public interface. But it turns out
you're not that lucky. You need a new interface on your adapter, because
in your initial design, you didn't anticipate that you'd be switching to
so radically different grid, and as such the adapter's original
interface isn't compatible anymore.
In your example you would just implement data binding interfaces and then
you'd be able to bind to any control.
You may call my example a stretch, but I've seen plenty of this. Having
OO framework that's capable of adapting to the wildest imaginable range
of changes in theory, and in the end still having to change just as much
code (but usually more, because every real-life framework is leaking
abstractions to outer layers, which in turn also need to be adjusted).
That's because they obviously tried to write a framework that did everything
they could possibly want, well before they actually knew what they wanted.
My problems weren't limited to a databinding level. They were
everywhere, e.g. in handling drag-n'-drop, responding to focus
changes... You know, all the little things that all 3rd-party controls
like to handle internally.
I don't see how dragging OPF stuff is any harder than the dragging you would
normally write manually.
I wasn't talking about memory leaks. By "leaking abstractions" I meant
this: http://www.joelonsoftware.com/articles/LeakyAbstractions.html
This is easy to avoid. You just make sure your layers are in physically
separate projects and make sure each does not
A: Reference a project it shouldn't
B: Include source from another project as its own
It's a real problem when layers, which were supposed to be isolated from
one another, share knowledge about their internals. This automatically
means that any non-trivial change in one of them will require some kind
of change in the other. This means an annoying distraction at best and a
maintenance nightmare at worst.
I've not experienced this. Maybe it is because my layers do not reference
each other in code.
I've never written wrappers. I either databding (ECO) or my composite
GUI control knows how to display the request object and also how to set
the response values (my compact framework app).
Ah, so you *do* write them! You're just calling them "composite UI
controls". :)
No, I don't write wrappers around controls. My composite controls are just
the equivalent of your Form, except that the only code you will see in my
form is stuff like this
SomeTextBox.Enabled = SomeRadioButton.Checked;
Only GUI specific code, no business or app logic at all. In fact the
"composite control" only knows what to show + which properties on the
underlying object to set back. I can use the same control in any context.
For example, this PPC app will present the user with a list of options as to
what to do once entering a site
( ) Adhoc orders
( ) Report break in
( ) Manage vending machines
.....etc....
( ) Upvend a brand
( ) Restock
( ) Repair
( ) Uninstall
.....etc....
So I save time here, I reuse the same type of ProcessParameters
(ChooseActionParameters). I'm not wrapping TextBox / Button etc.
I almost read this as "It's not something I've ever /been able/ to do".
There are many things I cannot do, I just don't talk about them as much :-)
Sure, if you go .NET-style and say that framework doesn't count as
weight, it really boils down to 3 small assemblies. But then again,
it's still you who has to maintain those other assemblies ("the
background", as Joanna would say). I still count this as being at
project's expense, unless you really have quite a few projects that are
using your framework exactly as it is. Then I agree it's definitely
worth it.
Even if we never use it in another project it will be very useful. When I
started to write this app I had a sneaky suspicion that it would end up
being much more complicated than I was being told, so I wrote it this way.
I was right. The complexity of the software has proven to be very easy to
implement using this approach. In fact the other company developing the PPC
software (the customer had to choose between the two) took twice as long
with 2 coders and only implemented about 50% of the original specification.
In half the time, only a single coder, I implemented the spec + about 25%
more on top (stuff that "cropped up").
Usually though, I see frameworks being developed with /intention/ to be
used anywhere, when in reality, they're only ever used once or maybe
twice, provided some modifications are made first.
You should always write what is best for your current app. I must admit
that I would like to work on a pet project of mine which I could then use
for multiple projects, but I don't have time :-)
In my experience, the features that develop-as-you-go OO-frameworks have
most problems with, are the variations on the same theme. If they are
vastly distinct, it's less of a hassle, because you can just extend the
framework. Adapting existing parts of it, OTOH, is quite something else,
because it breaks the inital design. :)
The VCL is a framework. They don't have a form for every possibility, it's
impossible, they just provide you with tools you can use to make what you
want + allow you to create modified versions in case you need something
special. That's what your framework should do.
That's not nearly enough! In any moderately complex OO framework, you'll
have a range of common ancestor classes that implement the core
interfaces and patterns. TObserver, TAspectObserver, TActor, etc. Then,
other classes will either descend directly from those, or indirectly
incapsulate them as to implement a sort of multiple inheritance.
The only ones I used in my PPC framework were an implementation of the
observer pattern + something I named memento which probably isn't one :-)
My problem is, I've seen no convincing real-world examples where it
actually made sense to do things so radically differently from the
conventional ways. It all seems to be just focus-shifting in the end -
do you make all your changes here, or do you make them there (and
there... oh, yes, and over there, too :))?
That's because I am not allowed to give you my source :-)
.
- Follow-Ups:
- Re: OODesign - OPF, design pattern
- From: Aleksander Oven
- Re: OODesign - OPF, design pattern
- References:
- OODesign - OPF, design pattern
- From: Alan T
- Re: OODesign - OPF, design pattern
- From: Peter Morris
- Re: OODesign - OPF, design pattern
- From: Alan T
- Re: OODesign - OPF, design pattern
- From: Peter Morris
- Re: OODesign - OPF, design pattern
- From: Aleksander Oven
- Re: OODesign - OPF, design pattern
- From: Peter Morris
- Re: OODesign - OPF, design pattern
- From: Aleksander Oven
- OODesign - OPF, design pattern
- Prev by Date: Re: A very good blog about the Delphi 2007 Help Issue
- Next by Date: Re: A very good blog about the Delphi 2007 Help Issue
- Previous by thread: Re: OODesign - OPF, design pattern
- Next by thread: Re: OODesign - OPF, design pattern
- Index(es):