Re: Text terminal rendering design



You see, all the client knows is the abstract interface, so I am
free to give it any object that satisfies that interface. In
particular, nothing the client is coupled to prevents me from
giving it a real facade object if I choose.

H. S. Lahman wrote:
Note that one can extend your argument to the use of getters and
setters for object attributes at the 3GL level. Why bother when it
would be so easy to fix it when and if it needs to change?

Unfortunately, I do not exactly see the parallel with getters and
setters. Are you talking about the choice between using getters and
setters versus making the data public? That doesn't seem easy to fix
at all, since you would have to edit every place where the data is
accessed.

The problem is that to undo it you have two choices: change the
client's invocation or employ some kludge in the implementation
like renaming objects/methods to be something they are not.

I didn't have to do any of those things in the fix I described. Are
you talking about getters and setters or my situation? I can pop in a
facade in a completely painless manner without being forced to rename
or kludge anything.

So you have to muck around with the implementation in some
artificial way that no longer maps directly to the problem space.
That's called Architectural Drift and it is just as much of a
no-no.

That doesn't seem to match the situation that I am looking at very
well. I am sure I have failed to describe it properly. The only time
I would need to pop in an facade would be if the implementation were
changing somehow, a new method name, a changing responsibility,
something like that. The object that was playing the double role as
facade and implementation must change, so my little trick has to end.

The change to the object is motivated by the problem space, so it is
entirely appropriate. The new object that I am creating is a facade
object, and so it isn't expected to map to the problem space. This
little transformation that I am proposing is completely trivial and
inconsequential to all participants, so I feel confident that it is
not what Architectural Drift is intended to mean.

You solve the maintenance problem by creating the same Facade
object you could have provided in the first place.

Exactly.

Only now we have to keep the same implementation name for the
Facade to avoid touching the client.

Why would you want to change the name of the Facade? You can never do
that once it is being used by a client. It should probably have been
a good name from the start.

But we had already determined that name is no longer accurate when
we did the rename, so there is something wrong with that picture.

But surely there is something wrong with that thinking. After all,
what we actually wanted to rename was the implementation object,
right? If we had wanted to rename the Facade then we are in trouble
no matter what we do. So why would you complain that the
implementation is changing names while the Facade keeps the old name?

We do OO development to make maintenance easier, not to palm off
extra work or problems on the maintainer because we didn't feel
like doing it right in the first place.

That's a good point, but it really isn't much work. As I expect to be
the maintainer myself, I'd rather have a slightly simplified
subsystem at the cost of a trivial bit of work in the event that I
find I actually needed that facade.

The point is that the facade issue is entirely trivial. Even if the
actual physical implementation doesn't have what you would call a
facade object, from a design perspective 'Terminal' is a facade and
you should think of it that way.

(Though now I suppose I will be renaming it. "UI" seems a bit too
general for my tastes, since there are plenty of UIs that are
completely incompatible with this subsystem interface. I need a
subsystem name that represents the grid-of-symbols nature of the UI.)

If the application is partitioned properly and the subsystem
interface is properly abstracted, then it is far more likely for
the interfaces of implementation objects to change than for the
subsystem interface to change.

That is why I tried to show you how easy it was to change the
interface of the exposed implementation objects without changing the
subsystem interface. Unfortunately, I failed, but I assure you that
my failure was entirely my fault and not the fault of my design. It
really is trivial in my design, but less trivial to explain than to
do.

Let's assume the client is Emacs. Try thinking about what message
Emacs might send that reflects only its context. In particular,
try to think of a context purely within the Emacs problem space
that you could unambiguously map into creating a Symbol in the UI.

I believe that I see your point. I know it would be nice to present
the client with trivial interface onto the UI so that the client can
focus more upon its real problem space. The ideal interface would be
simply: display(x,y,symbol). Just that one message as simple as that.

It will take me a few paragraphs to prepare to respond to your point.
Please be patient and reserve judgement for a moment.

My problem is that there are things that need to be specified for the
UI to do its job and they are not normally what I would think of as
being part of the Emacs problem space. For example, Emacs just wants
to display the letters and punctuation that the user is typing, but
the UI subsystem needs to know what color to display them.

I've seen Emacs making use of color, but suppose that Emacs doesn't
care about the color. Suppose we are talking about vi or something
like that. Choosing the color is not part of the client's problem
space if the client is vi, but someone still has to choose the color.

The UI subsystem interface is supposed to be flexible and powerful to
allow the client to specify a broad range of symbols. It is designed
to be more than sufficient to meet the clients needs for
communicating the nature of the symbol to be displayed through the
subsystem interface barrier.

I want to be able to change the UI subsystem without changing the
client, so I can add new hardware support, but I also want to be able
to change the client without changing the UI subsystem, even if that
means the client will be asking to display some unusual new symbols.
That sort of flexibility necessarily means that the messages for
specifying the symbol to be displayed will be various and
complicated.

It certainly will not be a single 'createSymbol' message, it will be
several and various messages designed to convey various symbols to
the UI subsystem from the client. I want it to be as simple as
possible, but to achieve my goals for this subsystem it needs to have
at least a little of that flexibility.

Emacs doesn't do fonts, but I'm sure you can imagine how it could
have some support for them, for example. A better example is probably
LaTeX, which is a typesetting program capable of writing a wide
variety of symbols. No one typesets on a fixed grid like my subsystem
uses, but math symbols can still be very useful.

Unless you have thought of something which I have not, choosing one
symbol out of a broad range like that, including colors and
attributes such as bold and underline, will require a seriously
nontrivial series of messages sent from the client who needs
something displayed to the UI subsystem who is responsible for
displaying it.

Finally, to address your point, I cannot think of what part of the
Emacs problem space would map to creating a symbol or accepting and
dealing with a terminal-ready symbol. In fact, I am pretty sure that
there is no place in the problem space for that sort of thing. But in
exactly the same way there is no place in the problem space for any
of the complex interactions needed to specify what symbol to show.

All Emacs wants to do is say, 'display(x,y,symbol)'. That is part of
Emacs's problem space. None of the rest really fits, but someone has
to do it and it does not fit into the UI subsystem's problem space
either. The UI subsystem certainly could not choose the color of a
symbol, for example, even though color is not part of the vi problem
space.

So I have been suggesting a relationship between subsystems like
this:
[Symbol Manager]------[Application]------[UI]

Here [Symbol Manager] takes care of the ugly business of memory
management for symbols for the application. Symbol manager is exposed
to application problem space knowledge that helps it decide when a
symbol is no longer needed, as well as the memory constraints of the
overall software, things that the UI really should not have to deal
with.

The problem is that memory management and keeping track of symbols is
not part of the application's problem space any more than it is part
of the UI, and this forces [Application] to deal with [Symbol
Manager] and the terminal-ready symbols from [UI].

If I understand correctly, you have been suggesting something like:
[Application]------[UI]------[Symbol Manager]

Here, the interface between [UI] and [Application] becomes much
simpler. It is getting closer to exactly what the application wants
to deal with. Emacs does not want to deal with terminal-ready
symbols, and now it doesn't have to. That sort of thing is not even
possible under the simplified interface. UI gives the terminal-ready
symbols to Symbol Manager, instead.

The problem is that now Symbol Manager is removed from Application.
It is no longer touching anything that knows about Application's
problem space. In the likely event that Symbol Manager needs
information about that problem space to determine which symbols to
keep and which to throw away, that information would have to be
handled by UI. To maintain cohesion, UI is deliberately ignorant of
the meaning of the symbols it is displaying, making it almost useless
if Symbol Manager is trying to do anything clever.

Now I have been inspired by the thoughts you have suggested about
Emacs into creating this third alternative:
[Application]------[Symbol Manager]------[UI]

Application is where Emacs sits with its word-processing problem
domain. It only cares about the aspects of the symbols that are
related to its domain. It probably cares about color, but not about
mathematical symbols. (I don't know. I'm not actually an Emacs user.)
Emacs does not want to be told what UI interface it needs to use; it
already has a UI interface that it intends to talk through in order
to demand that the appropriate symbols are displayed in the
appropriate places. If I try to design my subsystem interface to work
for things other than Emacs, it will not be exactly what Emacs
demands and therefore Emacs won't use it.

Therefore, I propose that Symbol Manager be put in the middle as an
Adapter, but for subsystems rather than for classes. On one side of
Symbol Manager we have an interface much like what you have been
suggesting, but even more tailored for the specific application. On
the other side, we have an interface like I have been suggesting for
a UI subsystem that doesn't know what it is appropriate to keep
terminal-ready symbols in memory and when to recreate them later.

Symbol Manager knows intimately about the problem space of
Application. Symbol Manager knows exactly what Application wants and
is rather highly coupled to Application, since a different
application with even a slight change in the problem space will
probably require a different Symbol Manager. This means that it knows
which symbols are likely to be reused in the near future and it even
knows whether the application problem space includes a concept of
color, so Application does not have to be exposed to colors when not
appropriate.

Symbol Manager knows much about the application, but it has a
completely different problem space. Its job is first to take the
relatively compact encoding that the application uses for symbols and
explode it into a complex series of messages designed to convey to UI
what the symbol is supposed to look like. Symbol Manager can do that
relatively easily because it knows the meaning of the application
symbol encoding.

Symbol Manager also accepts terminal-ready symbols from the UI as
handles. It does this because Symbol Manager has the responsibility
of somehow recording the connection between the application encoding
and the hardware encoding, when appropriate. I say 'when
appropriate' because it might be the case that for a certain
application the symbols are never recorded and the terminal-ready
encoding would be recomputed every time the symbol is displayed. That
decision is the responsibility of the Symbol Manager.

So now UI only needs to understand the hardware or the smoke signals
or the cave wall paintings or whatever it is using to display
symbols. It takes a complex series of messages that convey the
appearance of symbols that it might need to draw and uses its
knowledge of the hardware to spit out a digest of that symbol. (It
doesn't display the symbol immediately, because the symbol may need
to be displayed many places in both space and time and that sort of
decision is not the UI's responsibility.)

The benefit is that all the work that I've put into understanding the
hardware to implement UI does not have to be scrapped for every new
application with slightly different UI needs. I do not have to expose
the UI subsystem to even the slightest hint of the application's
problem domain, not even for nonfunctional requirements management.

I can leave the UI subsystem untouched and only replace the much
simpler Symbol Manager.

I think this addresses and resolves all of the issues you have been
raising. Does it?

Any nonfunctional requirement on how fast the UI subsystem
displays a client icon is a requirement on that subject matter;
pertains only to the subsystem's mission and how it is performed.
So the subject matter does need to be good at resolving it.

Since that requirement only applies to the UI subsystem's mission,
it has no relevance to the client. Therefore any resolution of the
requirement must be encapsulated in the UI subsystem.

The problem with that was the fact that the UI subsystem could not
have done it well without being exposed to the client's problem
space. It is nicely keeping UI problem space out of the client
subsystem, but it would have created the opposite problem.

Thinking this way was what inspired me to put a third subsystem in
the middle where the UI problem space and the application problem
space mingle, nicely keeping both clients of the middle subsystem
pure.

I'll repeat the same question I asked before: Why would the client
even know the UI subsystem had a performance requirement, much
less used fancy memory management to resolve it? The client
probably has its own performance requirements to worry about; it
doesn't need the UI subsystem's as well.

Whoever is programming the client is probably the last programmer to
touch the project before the software is complete. That means that
the client programmer is the one who will see whatever performance
problems the UI subsystem has when talking to that particular client.

If I were to make the UI subsystem work out the sort of performance
problems you are suggesting, then the UI would be dealing with client
problem space issues, like how often certain symbols are repeated.

One client programmer would come to me telling me that the subsystem
works horribly with his project and he would ask me to change it. I
would be reluctant because the same subsystem works so well for so
many other clients. I would end up making a different version of the
UI subsystem for each client, which is a major pain for a nontrivial
subsystem.

Notice that createSymbol does not return with the terminal-ready
symbol. The client is not telling the UI subsystem when to create
it, just that it should be created because it will be needed
soon. When the UI subsystem feels like creating the symbol, only
then will it be passed back to the client.

As you described it createSymbol returned a Symbol handle.

My thoughts on the design of this subsystem have matured since I said
that.

Sure. Why not? Is there something about Terminal that you've
noticed that makes it inappropriate for sending smoke signals?

Because the OO paradigm is based on problem space abstraction.
Where is the computer terminal in a problem space populated by a
fireplace, kindling, a blanket, and the odd itinerant buffalo?

My notion of Terminal does not contain the word 'computer'. I have
abstracted the concept of a Terminal from what it is often used to
mean to just its essential features. These features could be
awkwardly emulated by smoke signals. It would be very awkward, but it
could be done.

Problem space abstraction is used because customers don't like
change any more than developers. So when the customer space
changes, it is accommodated in a manner that produces the least
disruption of existing customer infrastructure.

We are talking about the subsystem interface, not the implementation.
A notion of Terminal that could be implemented by smoke signals
actually reduces the need for change by the developers when the
problem space changes, such as if we lose our physical terminal and
are forced to use smoke signals.

If there is one single point to summarize all my arguments here it
would be that one should be able to swap subsystem implementations
without changing the subsystem interface. And if the interface
doesn't change, then the client doesn't change. All you have to do
is link in a new DLL.

Well, I couldn't have been expected to know that when you were
talking about changing the UI subsystem from one that uses a real
computer terminal to one that uses smoke signals, you intended for
the two subsystems to have the same interface. Normally I would
expect the interfaces would be different on such radically different
subsystems.

If you already have a client and you pick a subsystem off the shelf,
you can't expect the subsystem you find to have just exactly the
interface that your client wants. That is why I expect swapping
subsystems is harder than it sounds and it is part of the motivation
for my new Adapter design.

In fact, there is always going to be many layers between the user and
the hardware. My UI subsystem is merely intended as a relatively
high-level manipulator of a more low level subsystem that controls
the hardware more directly with a more primitive interface. That more
primitive subsystem likely is a DLL, like PDCurses, and all my
subsystem is doing is hiding the knowledge of how to use that
primitive interface so it can be swapped for other primitive
subsystems with different interfaces.

I just want to force uniformity upon a world of various computer
terminal libraries so that one application can be used in many
places.

That would be fine if Terminal really were a Facade (though it
would be an awful choice of name). But your Terminal is not a
Facade; it is an abstraction that is required to implement the UI
subject matter.

No, it really is a Facade, and I guess it really is an awful choice
of name. I don't particularly like UI either, though.

But the notion of a terminal-ready Symbol isn't even common to all
possible designs for display on computer terminal hardware.

Sure it is. Every computer terminal is responsible for displaying
symbols; it is part of their nature. The symbols it displays are
terminal-ready by definition, otherwise they are not ready to be
displayed by the terminal. On the other hand, terminal-ready symbols
do not have to correspond to an actual object in the OO design, but
that doesn't mean they don't exist. Since they exist, they could be
mapped to an object in the design.

It certainly isn't common to all UI subsystem designs because I
could delegate talking to the hardware to a lower level subsystem
and the UI subsystem would then need no concept of 'terminal' at
all.

I have no illusion that I will actually be talking directly to the
hardware. I'm always going to be talking through some lower level
subsystem, even if it happens to be the operating system of the
computer. However, every subsystem that can be useful for this
purpose has some notion of symbol, and as far as my subsystem is
concerned, the symbols that the lower level subsystem accepts are the
terminal-ready symbols.
.



Relevant Pages

  • Re: Text terminal rendering design
    ... Which is exactly what would happen in your case when the interface ... Every client would have to ... The only alternative you have is to provide a true Facade ... you have to kludge your implementation of the subsystem. ...
    (comp.object)
  • Re: Text terminal rendering design
    ... Which is exactly what would happen in your case when the interface of the implementation object changes. ... But then you need a new object to own the actual responsibility within the subsystem implementation. ... I can pop in a facade in a completely painless manner without being forced to rename or kludge anything. ... Facade to avoid touching the client. ...
    (comp.object)
  • Re: Text terminal rendering design
    ... The idea is that I have the client coordinate the conversion of symbols from its view of the symbols to the terminal-ready version as an extra step in addition to actually telling the subsystem to display a symbol. ... I am referring to giving the client implementation objects rather than facade objects. ...
    (comp.object)
  • Re: Text terminal rendering design
    ... subsystem subject matter so we need an interface to encapsulate them. ... The public members are the interface of that object and taken together all the interfaces of all the revealed objects becomes the interface of the subsystem. ... Your client is invoking specific ...
    (comp.object)
  • Re: Newbie Modelling Interface Question
    ... >>different interfaces for different client contexts, ... >>Facade wrapper, ... How do these approaches expose the subsystem ... > point of an interface was to prevent exposing the implementation. ...
    (comp.object)