Re: What doesn't lend itself to OO?
From: Mark Nicholls (Nicholls.Mark_at_mtvne.com)
Date: 07/27/04
- Next message: Robert C. Martin: "Re: Static vs. Dynamic typing (big advantage or not)---WAS: c.programming: OOP and memory management"
- Previous message: Gerry Quinn: "Re: Rework [Was: Static vs. Dynamic typing...]"
- In reply to: H. S. Lahman: "Re: What doesn't lend itself to OO?"
- Next in thread: H. S. Lahman: "Re: What doesn't lend itself to OO?"
- Reply: H. S. Lahman: "Re: What doesn't lend itself to OO?"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: 27 Jul 2004 05:32:42 -0700
> >>That is quintessential OO because it is about using pure messages to
> >>decouple implementations. The message itself is an object but it is a
> >>dumb data holder that is constructed solely for the collaboration. It
> >>has no semantics in terms of the problem in hand; just the semantics of
> >>data transfer. That decoupling of semantics through the message is why
> >>message and method are separated in OOA/D.
> >>
> >>Contrast that with the idea of passing object references or accessing
> >>objects remotely. The semantic coupling is horrendous and one is
> >>essentially exposing the client or service implementation. Even worse,
> >>one is inviting the other process to modify the object or access it in a
> >>completely open-ended and unpredictable fashion. Essentially one has
> >>unlimited opportunity for foot-shooting.
> >
> >
> > Don't get me wrong, but the vanilla (naive) OOA/D approach does not do
> > this, and such issues are rarely if ever talked about in OOA/D books,
> > and in fact is absent from most mainstream middleware packages until
> > very recently, the mantra has been not to worry about where the
> > objects exist because that has been abstracted away in a puff of OO
> > magic, sadly the real world intervenes because the problems associated
> > with interprocess/interapplication/intersystem communication don't sit
> > well with the direct coupling of state and operation.
>
> I submit that there are OOA/D authors today who boot strapped their
> OOA/D from spending their formative years writing OOPL code where
> compromises like eliminating the separation of message and method are
> pervasive. Consequently they have mapped very procedural techniques
> onto OO construction. These are the guys who converted to OO in the
> '80s and '90s from a procedural background and are now writing books.
yep
>
> I also submit that even classic OOA/D authors tend to present A&D
> methodologies in terms of How-To guidelines. IOW, they distill the
> fundamentals into practical methodologies. So I agree one has to do a
> lot of reading to between the lines to infer the fundamentals.
yep
>
> Even "Executable UML" by Mellor and Balcer is more interested in
> defining an MDA profile than discussing Why one should use that profile
> -- and it is the premier exposition of the methodology I espouse. So it
> very explicitly separates message from method and separates knowledge
> and behavior responsibilities in terms of synchronous access and
> asynchronous access. Yet it doesn't actually /say/ that is what it is
> doing. Instead it says one should use state machines to describe
> behavior. Nor does it say anywhere that passing object references as
> message data introduces horrendous coupling issues. Instead it says one
> should employ event-based interfaces for object behaviors and subsystems.
To be honest I find OO literature and software engineers in general
very week on system/subsystem design. Booch barely mentions subsystem
decomposition over and above a diagramming technique, Rumbaugh not
much better, Wirf Brock gives half a page. I suspect this is because
OO can say little helpful about it over and above tradition SD.
I posted a message here several weeks ago about the nature of
decomposing systems especially 'enterprises' into seperate subsystems,
I am trapped by BPR consultants on one side doing top down analysis
who see a holistic lump of a system and software engineers on the
other who also see the ideal as one super system. I suspect because of
a history of being a R/T engineer, the idea of breaking a system into
cohesive subsystems before designing those systems is natural.
>
> As far as middleware packages and infrastructures are concerned, very
> few of them are OO. Most of the OOness lies in marketing hype that
> carries on the grand tradition of wrapping an OO Facade around a
> function library that began with MFC.
>
> However, I would point out that there is a big difference between
> employing a paradigm to solve an specific problem and designing software
> to implement that solution or designing the applications that access
> that solution.
>
> COM-like composition is a fine paradigm for creating very general
> software infrastructures. But that is solving a very specific problem
> with quite unique constraints. One can provide an OOA/D model that
> implements the /solution/ paradigm without the model itself being
> expressed with the paradigm. Similarly, client applications can access
> a solution based on that paradigm without their construction being based
> upon it.
>
> For example, the world of RDBs is characterized by the RDM. One can
> design a data base engine in an OO manner using objects like Schema,
> Table, Field, Join, etc. But they are just vanilla OO abstractions of
> the problem space. That DB engine design itself isn't using P/R to
> construct the software. Similarly, the applications that access the DB
> engine will abstract their problems in terms of Account, Customer, etc.
> rather that Table, Tuple, etc. Those applications only need to
> understand the semantics of the RDB paradigm in their application
> interfaces, not the solution to their specific problem.
>
> The analogy to COM/Middleware is similar:
>
> DB engine => middleware infrastructure
> RDM paradigm => composition paradigm
> problem space abstraction => problem space abstraction
> client => client.
>
> <snip agreements>
>
> >
> >
> >>In addition I would point out that the performance problem that dictates
> >>stateless objects pretty much only exists on DB servers and middleware
> >>where the main problem is processing large gobs of data rather than
> >>solving business problems. The reason transaction processing lives on
> >>despite the demise of batch processing is that it is a good paradigm for
> >>data processing. So in those sorts of environments one already has to
> >>live with that paradigm. So the issue of self-contained messages
> >>becomes pretty academic.
> >
> >
> > not so sure about this, If my GetTime() service was exposed as a
> > service on the internet and simply accessed a clock, I wouldn't want
> > it to be statefull.
>
> OK, but I see that as pretty much the same problem. In practice, it is
> a classic client/server situation with large numbers of clients and a
> single, resource-limited server. And, in fact, most 'net applications
> don't really do much except data entry checking; they just pass the data
> through to a DB for later processing. In that sense they are not unlike
> a middleware server.
>
> [BTW, this is an example of why I get amused when people talk about how
> unique 'net software is. That's pretty much a croc. Even the markup
> and scripting languages are just rehashes of technology that was
> abandoned in the '70s. Exactly the same things were done for decades
> before the web. (It is sad how few developers realize that the internet
> existed for decades before the W3 or that multi-client networking
> applications also preceded the web by a couple of decades.) The only
> thing that makes web applications "new and challenging" is the fact that
> IT developers now have to explicitly think about issues like
> concurrency, asynchronous processing, resources, bandwidth, and timeouts
> that were all nicely serialized or hidden for them previously.]
>
> Just out of curiosity, though, why shouldn't the clock service be
> stateful? It isn't really a resource issue because there only needs to
> be one instance.
I think we need to be clear about what 'stateless' programming means
in this context, I don't particularly think it means state rather than
specific identity.
If the clock service has identity then the client looks like...
// create a specific instance of the clock service on the server
CGMTClockService clock = new CGMTClockService();
// invoke GetTime on that specific object
Console.WriteLine(clock.GetTime());
Now what happens on the server if the client crashes after the 1st
line, there is an object with no client, and we need to create all
sorts of dreadful strategies for making sure it is still needed -
timouts, pinging etc.
What happens if I want to create a farm of two servers if clock is
created on server A, the load balancer needs to know this else it may
send the request to server B and this specific clock doesn't exist
there.
Note clock really has no 'state' except it's class and this is
important because
CGMTClockService does something different to CCETClockService.
So don't do it, just do the equivalent of
Console.WriteLine(CClockService.GetTime(GMT));
there is only one request so it can be farmed, load balanced and any
state data required is created and released in a single request.
a functional API.
>
>
> >
> > Though I do agree that the use of DB servers in most business apps
> > makes the implementation of stateless services relatively easy except
> > to say that I don't really consider them to be as stateless as client
> > held state...the server application is maintaining state but via some
> > sort of handle, client held state to me is much to be prefered because
> > the server is not responsible for maintaining any state at all.
> >
> >
> >>In other environments where the software is solving business problems
> >>the collaborations will generally by more complex and will inherently
> >>require some degree of persistence in the service between client
> >>requests. The remote clock handling multiple time zones and calendar
> >>synchronization is an example of that. In those situations it is almost
> >>always better to provide the persistence in the service or in some
> >>common repository like a DB or shared memory.
> >
> >
> > If possible on the client BUT I accept there are a whole raft of
> > scenarios where this is unreasonable and unwanted i.e. the raison
> > d'etre (!) for the service is to supply some sort of persistence.
>
> There's no free lunch; wherever state is maintained persistently there
> is a downside. If it is in the server, then one has resource issues in
> a multi-client environment. If it is in the DB, then one has the
> performance hit of additional physical I/O access and one increases the
> likelihood of needing deadlock resolution. If it is in the client, then
> the client needs to know a lot about the persistence limitations and
> there will be encoding/decoding overhead into generic formats like XML.
> (Not to mention that most of the client state will originally come
> from the DB through the server anyway; all one is really doing is
> optimizing the access.)
>
If no persistence is required, then there would seem to be no need for
the extra headache. Keep the state on the client and make the
interface a completely stateless one, all state needs to be passed in
to get a given result.
> Essentially one has made every client responsible for also managing and
> optimizing DB access in addition to solving the customer's problem.
> That duplication fine if all the customer is doing is ad hoc reporting
> and data entry because it can be largely reused as in RAD IDEs. But
> when the applications are also solving significant problems, one has to
> touch /all/ those solutions when something changes in DB-land. That's a
> maintainability problem, which must be important because one is doing OO
> in the first place.
>
If you need to put stuff in the DB, I would put it in and keep that
state in the DB server.
> So I would try to put state on the server or in the DB until that
> downside was /demonstrated/ to be unacceptable. Fortunately for us
> translationists the issue is largely academic; it's just a strategy
> switch in the translation rules to move the state and one doesn't have
> to maintain the code if it is put in the client. B-)).
>
> >>>If I did this for all my code (and I do it more than most e.g. my
> >>>likeing for dumb readonly shared composites and behaviour rich
> >>>visitors) you would suggest I wasn't doing OO I think.
> >>
> >>How much of that is because you are dealing with "canned" layered model
> >>infrastructures that exposes too much about the data layer? Sadly, most
> >>of those infrastructures aren't very OO despite the marketing hype.
> >>That's just another reason to isolate persistence and UI in application
> >>subsystems whenever one is beyond CRUD/USER pipeline applications.
> >
> >
> > I don't know, you wouldn't like my code - sometimes I don't - some of
> > it has to do with working in an inherently multithreaded world where
> > changing state is a nightmare...I usually just push everything into a
> > single threaded queue.
>
> Use state machines. B-) If the only problem is data consistency during
> concurrent execution (as opposed to hard R-T constraints), then all one
> needs to do is provide multiple instances of the event queue manager.
> The event doesn't get on the queue until the data is consistent,
> regardless of whether there are one or many queues, so data consistency
> comes for free in just getting the asynchronous processing to work for
> the object state machine interactions.
I am currently either creating objects with readonly state, and/or
creating a single threaded queue and/or passing data by value.
>
> One can then allocate object state machines to event queue managers for
> concurrency and put each event queue manager in its own thread. Simple
> blocking constraints can even be supported via semaphores in the event
> queue managers rather than invoking the <expensive> thread pausing
> mechanisms.
>
hmmm, can't quite see this.
> [If blocking is necessary, it has to be managed somehow. Doing it by
> pausing state machines, though, is more aspect-like (i.e., the code
> looks the same everywhere) and is easier to manage because the scope is
> at the state action (method) level and one can count on the FSM rules to
> ensure that scope.]
>
interesting but not with it.
> >
> >
> >>>>Where the problem arises is when "canned" infrastructures designed to
> >>>>hide the client/server boundary as an application layer define a layer
> >>>>interface that exposes the server implementation model. That forces the
> >>>>client application to employ the server implementation model. That is
> >>>>bad OO.
> >>>>
> >>>
> >>>hmm, you'll have to illustrate.
> >>
> >>Consider COM components. They utilize a very mixin-based composition
> >>approach. That is great for providing highly general infrastructures
> >>where one can't anticipate the final structure. But it is not a very OO
> >>approach for individual applications because it trashes cohesion and
> >>deviates from the problem space (e.g., Printable Sony Walkman). That
> >>composition bias is very apparent because inheritance is the primary
> >>vehicle for cobbling things together so it tends to foster that sort of
> >>construction at the individual application level.
> >
> >
> > hmmm I still don't understand and I don't think I agree.
> >
> > I personally think COM encourages composition over inheritance,
> > because there is no temptation to use implementation inheritance to
> > expose hooks. I don't believe a 'Printable Sony Walkman' is any more
> > likely in COM than in C++, in fact probably less - you know I'm a COM
> > fan. COM gets a bad rap because of VB, VB gets a bad rap because it's
> > relatively easy to use - this is a good thing BUT you do tend to get
> > the more bodge together mentality because more inexperienced people
> > can use it - I am a big fan, there now appears to be a huge gap in the
> > market for a simple but serious mainstream development tool in the
> > market now MS are busy trying to out nerd the java world.
>
> We seem to have different views of COM. B-) To me the primary
> mechanism of COM composition is mixin-like inheritance. In one wants to
> add a streaming facility to the component in hand, it is inherited from
> Streamable (or whatever it is called -- it's been a long time since I
> was exposed to COM and I wasn't paying much attention even then).
How would you do it in C++. If you would use MI in C++ then you can MI
the interface and message forward (weak delegation), if you would do
it another way, and I expect you would, the COM would allow you to do
that.
You can't do implementation inheritance - so delegate.
You can't extend interfaces - so multiply inherit them (or other).
both of the above are of dubious merit anyway.
>
> IME, once one opens Pandora's Box, one will start to get Printable Sony
> Walkmans. I am also a strong believer that methodologies, languages,
> and tools should /enforce/ good practices rather than simply supporting
> them. Using getters/setters is neither convenient, obviously necessary
> for a given attribute, nor even the most efficient technique in some
> cases. But we still use them methodologically because that Good
> Practice ensures we won't shoot ourselves in the foot in some situation
> in the future. IOW, once the box is opened, one is in the position of
> guessing which foot-shooting situations will arise; better to not have
> to worry about it.
>
oh dear, I stil don't use getters/setters, I still believe they imply
an implemation that may not exist - but I accept the argument.
I would argue while the world of C++ has disappeared down a multitude
of bad practive, MI, deep inheritance tree, multithreaded nightmares
the world of VB 6 (COM) has not because most of these things were
thankfully unavailable.
> >
> >
> >>In contrast, individual applications are abstracted to a very particular
> >>problem in hand. So if one routinely applies the COM composition
> >>paradigm one ends up bypassing OO maintainability in favor of the view
> >>that it is easier to cobble together a new component for a specific
> >>change than to worry about modifying the existing application to be in
> >>synch with the problem space. The result is enormous code bloat.
> >>Worse, it leads to architectural drift in the applications away form the
> >>problem space leading to a maintainability nightmare when the
> >>application matures.
> >>
> >
> >
> > Bad implementation does not make a bad tool. COM may encourage this
> > because it encourages composition over inheritance, there is less
> > coupling within an application and so it becomes much easier to coble
> > a bodge together than have to reengineer the system due to a new
> > requirement.
>
> And when one has collected together a flock of
> almost-but-not-quite-the-same widgets and the requirements change, how
> does one decide which widgets need to be modified or replaced? One can
> guess that only a specific context is affected and modify that. Then
> one must have a whole lot of faith in one's test suite.
Again to "... collect together a flock of
almost-but-not-quite-the-same widgets", would not be good practice, to
have them available is nice and better than not having them available.
I would not subscribe to the view that a tool should be complex and
difficult to understand and use, and not have as many 3rd party
components available as possible - if the cost of this is that less
experienced people can build bad software then so be it, I don't blame
the tool for that, it is an unfortunate consequence of it's success.
>
> Alternatively, one can go examine every context where each flock member
> is used to see which widgets are affected by the requirements change.
> That puts one knee deep in Spaghetti Code. B-).
Hopefully, being a wise and sensible developer you would choose
components from reliable sources.
>
> But the real issue here is architectural drift. That increases the
> chances that a relatively minor change in the problem space will trigger
> a massive refactoring of the application. That sort of refactoring is
> independent of whether COM techniques were used; is is a direct result
> of the software structure not matching the problem space structure,
> regardless of the construction techniques. My point is the the COM
> composition paradigm strongly encourages architectural drift. IOW, it
> may be somewhat more difficult now to implement an individual change
> while preserving the problem space structure than doing so while
> ignoring the problem space structure, but one will pay for it later.
>
Again, it encourages decoupled code, and this can be abused - but I
would hope that you were a champion of high cohesion and low coupling,
we can if you want return to the days of deep inheritance tree's where
every small shift in requirements triggers the avalanche - I prefer
that my architecture to be robust and flexible enough to absorb many
shifts before it collapses around me.
- Next message: Robert C. Martin: "Re: Static vs. Dynamic typing (big advantage or not)---WAS: c.programming: OOP and memory management"
- Previous message: Gerry Quinn: "Re: Rework [Was: Static vs. Dynamic typing...]"
- In reply to: H. S. Lahman: "Re: What doesn't lend itself to OO?"
- Next in thread: H. S. Lahman: "Re: What doesn't lend itself to OO?"
- Reply: H. S. Lahman: "Re: What doesn't lend itself to OO?"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|