[MUD-Dev] Re: TECH: reliablity (was: Distributed Muds)

John Buehler johnbue at msn.com
Thu May 3 16:49:20 New Zealand Standard Time 2001


Ola Fosheim Grostad writes:
> John Buehler wrote:

>> Oh, I think I get it now.  There are no component design tenants.
>> The size of a component is up to you, and the abstraction distance
>> from the raw functionality that you are accessing is up to you.

> Uhm, but if so then there is no such thing as component design...?
> Sure you can tweak OO and structured programming and what not to fit
> your needs, but...

There was a component design methodology that *we* were using, but
component technology does not require a specific design methodology by
a given organization.  We used small components and a mechanism to
graphically wire together those components to make bigger components.
We didn't want to try to build high quality big components.  They're a
real challenge to build.

> Again, I do see that components make sense in some areas, just not
> in the MUD core.  Except maybe if you have a frozen design and need
> to speed up development using an incremental strategy (as opposed to
> an evolutionary one).

I think we need to talk about the specifics of a MUD core.  I see some
standard tasks and some nonstandard ones inside of a MUD.  Those that
are standard can use existing components.  Those that are nonstandard
can be incorporated into custom components.

> Isn't it true that the further you go towards pure components, the
> closer you get to the waterfall model (which was specification
> based!)  and structured programming?  That's how I see it anyway.

To me, the waterfall model suggests an inflexibility in the entire
process.  Define all your specifications, give them to your engineers
and they build the software.  We found out very quickly that
specifications must be given room to breathe.  But the 'breathing
process' must be very carefully structured, and that's part of what
the precise contract and component development methodology attack.
Imagine fast versioning of specifications and implementations instead
of just doing in-place modifications of both whenever you felt you
needed to.  The fast versioning approach means that you recognize the
fact that you're diddling with the contract and the implementation.
If there is code out there still thinking that it's working with the
old contract, you'll get immediate feedback when you try to run your
application.  That, instead of the code running, but running
strangely.

The COM mechanism for dealing with contracts is to use GUIDs, which
embody every element of a contract that can be expressed.  That's
because they're just identifiers.  But the important point is that it
represents more than just a function signature.  It represents the
behavior that the function (or set of functions) is required to
deliver.  Change the contractual behavior and the GUID changes.
Software looking for the old GUID from the new component will get
upset when the new component blinks innocently, wondering what the
client is talking about.

>> And you would be creating a component as soon as you construct that
>> module.  You don't call it a component, but it is.  And you won't
>> be managing the contracts that relate to it very strictly, and that
>> will burn you whenever you blink or lose concentration while
>> working with it.

> And that can't happen with components? :)

Not when you follow a strict component methodology.  That methodology
is intentionally focused on this problem.  Make contracts a first
order member of your design and manage them carefully.  If you open a
specification and dink around with it, it automatically gets
versioned, producing new GUID (a new contract identifier).  Voila,
nobody implements that contract unless you manually go and ensure that
specific components do.  Given the proper testing tools, you can't
even check that component back into the public population of
components until it passes the tests that verify that it behaves
according to the new contract.  This was the stuff that we were
working on and working towards.  They're still at it from what I
understand.

> (I do use invariants and produce code to check them where possible.
> Unfortunately I don't get to program a whole lot, but when I do...)

And these are the tools of a diligent engineer.  The testing
methodology that we were after was intended to ensure that an
engineer, diligent or not, would produce a high quality component.
Engineers who start out diligent will be able to crank components out
far faster than those who do not.  As it should be.

>> The first component does general collision detection.  Then when
>> you only want an area spell that affects level 40 dwarves, you
>> construct a new contract and a new component.  Fortunately, you
>> have a general purpose collision detection component that you can
>> use for the lion's share of the work (through aggregation or
>> delegation, not code reuse).

> So now you have a less efficient design with additional methods you
> could otherwise have avoided. With lots of interdependencies, it
> will become pure hell to specify useful pre and postconditions, not
> to mention reading and updating them :). You may of course reduce
> what is covered by the pre/post conditions, but then they become
> less useful.

I would have assumed that additional preconditions on the existing
contract would have worked just dandy.  That produces a new contract,
of course, but one that should be easily implemented using the
existing component.  I don't see the introduction of additional
methods at all.  But I may be missing something.

> To cut down the searchtime you basically need to let the spatial
> datastructure "know" more about the objects and structures that
> contain information about them. (for instance, by storing avatars
> and other objects in separate sets, knowing somehow that objID x is
> a dwarf is an avatar or possibly knowing intimately about other
> datastructures that is maintaining information about objects) But
> the more units know about each other the less component based the
> design becomes...

This is a design issue.  Did the engineer who came up with the
contract for collision detection permit culling?  Does it maintain its
own internal data structures or does it have a means of traversing
foreign data structures?  Do I pass in the structures or does it
maintain a reference to the component holding the avatars and such?

There are so many scenario permutations that are possible that we
could go around on this forever.  You can postulate an inappropriate
contract and I can postulate an appropriate one.  Because collision
detection is a generic problem, I can easily see this component being
fairly open to accessing a number of different schemas that contain
object location and dimension information.

>> To obtain an interface requires a call and a simple lookup to
>> retrieve a pointer.  To make a method call, a pointer dereference
>> and a procedure call are the overhead.  To the best of my
>> knowledge, it's the same overhead as C++ (actually COM was required
>> to being compatible with Microsoft C++).  If you go with
>> fine-grained components, you can accumulate significant call
>> overhead.  If you go with coarse-grained components, the call
>> overhead is limited.  Which is, of course, the same equation as for
>> any pile of code.

> Except that with components the idea is that everything should pass
> explicitly through a clean-cut interface. In practical decent C++
> code you do use a lot of inlined methods and templates and try to
> reduce the number of virtual ones. Wherever you know what class you
> are calling you don't really have to go for a virtual one anyway...
> I like shallow class hierarchies.

All software is governed by precise contracts.  This is simply a
statement of fact because computers are Turing machines.  Specific
things happen as a result of running software.  Component
methodologies insist that engineers figure out what that behavior is
and write it down in the form of a contract document (well, actually,
we come up with the contracts, then implement them...).  How chunks of
code are embodied is up for grabs.  Using COM, we are limited to
embodying contract implementations as either a function call or as a
COM interface.  There is nothing about precise contracts and
components that says that an implementation cannot accomodate
inlining.  As for templates, there's a way of dealing with
parameterized types without duplicating code.

For what it's worth, we also liked shallow class hierarchies.  As in
no depth.  We didn't do contract inheritance.  We did do contract
construction from base contracts, but that's different.

JB

_______________________________________________
MUD-Dev mailing list
MUD-Dev at kanga.nu
https://www.kanga.nu/lists/listinfo/mud-dev



More information about the MUD-Dev mailing list