Re: Text terminal rendering design



Responding to Guild...

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.

Which is exactly what would happen in your case when the interface of the implementation object changes. Every client would have to change. The only alternative you have is to provide a true Facade with the same object and responsibility name. But then you need a new object to own the actual responsibility within the subsystem implementation. What do you call that, TheOtherSymbolFactory? IOW, you have to kludge your implementation of the subsystem.

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.

I think you did one of those two things. "Popping in a Facade" is the second option. But -- at a minimum -- that creates a namespace conflict so you have to kludge the implementation.

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.

Because to avoid changing the clients they must continue to invoke the same method from the same class. So the new Facade must be named SymbolFactory or Terminal as the case may be. That means that the SymbolFactory or Terminal object in the implementation needs to be renamed.

on the specific case of renaming the implementation object:

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?

Remember you justified using the implementation object as a Facade because it was a fundamental responsibility of the subject matter. If you change the name to match some new semantics and the original semantics was so important, why isn't the Facade name changing?

You can't have it both ways. If it really is a fundamental responsibility of the subsystem, then that semantics has changed and all the clients should be modified to reflect that change. OTOH, if it is only an implementation change that does not affect the clients, that semantics wasn't so fundamental to the subject matter in the first place and should have been encapsulated or at least abstracted to a higher level. IOW, a Facade should have been used originally.

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.

In an OO context encapsulation and implementation hiding are never trivial; one should always practice them, even when not practicing them does not seem to have a high cost. The purpose of the paradigm is to get the developer out of the business of making those judgments because decades of painful experience has determined that they often end up being wrong.

But this is somewhat academic. The problems we are talking about here are really rather simple. The big maintenance problems will come when you change the design strategy of the subsystem. In that case your two simple tasks may become three simple tasks. Is the client going to be responsible for triggering the third task as well? If so, the clients all need to change. Will you use a scheme where creating Symbols is unnecessary? Then SymbolFactory goes away entirely.

If the subsystem's responsibility is simply to display an icon for the client, then all those problems are irrelevant to the client. From the client's perspective all that is transparent and you can change the tasks, modify the sequence in which they are executed, add and remove objects, and whatnot to you heart's content. For that transparency all you have to do is define the level of abstraction of the UI service properly during application partitioning.

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.

Show me how easy it will be if one of those implementation objects goes away completely. Or you decide that intermediate conversions are so important they become a peer task to the initial icon conversion and terminal hardware control tasks. Or you decide you need to break up Terminal processing into two steps. Or to address nonfunctional requirements you have make decisions about whether to use an existing terminal-ready Symbol or create one. That will only be easy if you provide a Facade that emulates the original design, which is now obsolete. Then you are hoisted on the petard of your original vision that those tasks were fundamental public responsibilities of the subsystem.

The fundamental problem here is that in defining the subsystem during application partitioning you have hard-wired a particular design vision into the fundamental subsystem responsibilities. In that case you will be in serious trouble when the design vision changes because the problems won't be syntactic mismatches like names.

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.

Exactly.

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.

This gets back to a point that I made earlier. During application partitioning you have to decide what things the client controls about display and what things the UI subsystem controls. The interface then allows the client to supply everything it knows that is relevant to display. The client's view of those things may be different than the terminal's and view conversions may be required, but that is the UI's problem.

Everything else about the display the UI subsystem needs to supply as defaults. Trying to provide defaults for a vi character on a high-end graphics terminal may be an adventure, but if vi doesn't know about that stuff the end user is going to have to live with it. Nonetheless the UI can supply defaults for anything the client doesn't provide, including fonts.

However, there is nothing to prevent supporting clients that can provide lots of additional information as well as those that can't. To do that you just needs a Facade that provides multiple client interfaces. Then the Facade simply dispatches to whoever handles each situation within the UI subsystem so that missing defaults can be supplied.

There is a potential combinatorial problem in what various clients support (e.g., color and font vs just font). To handle that one just needs a couple of interface methods of various completeness where the client can provide a value of UNSPECIFIED for parameters it doesn't know about. This allows you to deal with any sort of client while providing the client with an interface appropriate to its understanding of display.

[Corollary. It should be clear that in this scheme there is an obvious third task for the UI: always creating a "natural" Symbol that has values for everything the terminal /might/ need. That Symbol contains the client's supplied data plus all of the defaults you need to supply for UNSPECIFIED values. In that case, the UI /always/ does a conversion from that Symbol to a terminal-ready Symbol.

Note that the defaults might ultimately depend upon the terminal type. In that case the defaults supplied for the "natural" symbol would be those a high-end client might supply if it could. Part of the conversion would then be replacing those values with whatever the terminal prefers. An obvious example is a font that the client would like that the terminal doesn't support.]


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.

Who are the clients and services here? Surely the Symbol Manager subsystem is not invoking the application?

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].

I have to disagree. If there is a nonfunctional performance requirement on how fast the UI displays icons, that requirement is clearly the UI's problem. If the UI decides to deal with it by using a custom memory manager to manage its heap objects, that is purely a matter of UI implementation because Symbol instances in the UI have nothing to do with the characters and icons that the client is already managing.

You keep pushing this idea that somehow the client should be managing objects that UI alone creates. The client has its own nonfunctional requirements and its own bunch of objects to worry about. It doesn't need to be concerned with the UI's objects and nonfunctional requirements. If there is a separate memory manager, it is a service subsystem where the client is the 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.

Exactly.

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.

The Memory Manger, if needed at all, will be an element of the overall design strategy for resolving the UI's nonfunctional requirements. That will likely require some degree of knowledge about the client problem space and how clients use the UI. As I already pointed out, the necessary view of that problem space is probably not part of the clients' view because the clients are tailored to a specific problem. At best the clients may already have some data that might be useful but even then it may not be accessible (e.g., vi probably isn't going to provide an interface to get at it and whoever is attaching your UI to vi isn't going to be inclined to rummage around within vi bowels to get it).

So the design strategy for addressing nonfunctional requirements is pretty much up to the UI designer. If the understanding of the client's problem space is limited, then the design strategy will be limited in proportion. There is nothing you can do about that and certainly nothing the client can do about it. At best all you can do is provide some exotic learning process that will monitor the clients' actual access and build a strategy over time.

Bottom line: how the UI addresses nonfunctional requirements is your problem and how well the UI does it depends on how well you understand the invariants of the clients' problem spaces. But that is a pure design problem and the clients themselves are out of the picture when the UI is executing.


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.

This is classic syntactic mismatch common in large scale reuse. The interface that Emacs wants to use is an output interface in the Bridge Model (that I talk about in the Application Partitioning category of my blog). That needs to be converted to the input interface that the service subsystem provides. That conversion would normally be provided in the implementation of the output interface for the client that wants to use your UI.

Since Emacs probably doesn't use the Bridge Model, it probably doesn't have a replaceable output interface. One way to deal with that is to provide a wrapper for Emacs that provides the interface that Emacs wants to use and converts it into one of the simpler interfaces that the UI Facade provides. Since Emacs is probably going to have a very simple view of display (displayCharacter(c)), that wrapper will be pretty simple.

The same technique would be used for any client that expected a particular interface for the UI. Clients would only invoke your UI Facade directly if one has access to their implementation or they have a replaceable output interface. Essentially this means that you have to create a custom wrapper for each new client. While tedious, it is easier and more robust than providing a gazillion interface methods in your UI Facade because you don't even have to recompile the UI subsystem; you just have to compile the wrapper object and somehow link it into the system.

Bottom line: syntactic mismatches between the client and the UI can be handled completely in the bridge between the subsystems.

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.

That's fine, but then it is just a Facade wrapper for the client's preferred output interface and doesn't need to know anything about managing the UI heap.

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.

You may need to understand the client's problem space to come up with a good design strategy for resolving nonfunctional requirements. But designing the UI subsystem is not the same thing as collaboration between the UI and the client. In practice, it is unlikely that client can provide values for decision variables in the optimization, much less provide cooperative services for the UI.

At best you can provide the ability in the interface to override the decision variable defaults used in the design. But the client is not going to solve the problem for you.

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 both the client and the UI are being developed in parallel and IF the developers on each team are communicating and IF the client developers are willing to put in infrastructure to solve UI's problems, THEN there may be some synergy. But I wouldn't hold my breath. B-)

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.

If different clients have quite different profiles of usage, you are not going to be able to address nonfunctional requirements uniformly well. If you need a high degree of optimization, then you have two choices. You can differentiate your product market by servicing only a selected group of clients (e.g., character editors and word processors) whose problem spaces are quite similar. Alternatively you can serve the general market by providing different implementations (e.g., DLLs) for the UI for different groups of clients with similar problem spaces.

But the resolution of the problem will always be /within/ the UI implementation (or a service subsystem to which it delegates).

On display problem spaces:

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.

I still contend that any common notion of 'terminal' in a display context is not something you will readily find in a smoke signals problem space. The goal is to map the problem space naturally and intuitively, not awkwardly.

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.

Actually I think we are. Terminal is fundamentally an implementation abstraction. You are just trying to make it serve double duty as a subsystem interface as well. Your whole argument here is that you /can/ use implementation object interfaces as the subsystem interface while I am arguing that you shouldn't.

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.

I have been arguing encapsulation and implementation hiding all the while. I have argued the subsystem interface should be at a higher level of abstraction than the interfaces of implementation objects. I have argued that the subsystem interface presents the client's view of the invariants of the subsystem subject matter. I have argued that subsystem interfaces are Facade patterns that provide stability for the client in the face of arbitrary change within the subsystem implementation. Finally, I've expounded at length over the value of polymorphic dispatch in allowing entire implementations to be substituted because the client can use the same interface without knowing which implementation is actually in play.

All this stuff -- one could argue the entire OO paradigm -- plays together to ensure that the client doesn't care anything about how the subsystem is implemented. So if this is a big surprise, then I have utterly failed in trying to make my case.

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.

I thought you said that you read the category on Application Partitioning in my blog. The posts on interfaces and the Bridge Model goes into substantial detail about how one handles this sort of syntactic mismatch. If you missed those posts, I would suggest reading them.

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.

Then what object is handling the actual rendering of a Symbol to the hardware within the implementation? If you are using Terminal for the subsystem Facade at that high level of abstraction, then why do you also need SymbolFactory in the Facade?

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.

I am suggesting I can design your UI without a Symbol abstraction. I'm not talking about just renaming it to Icon or DisplayData; I'm talking about a design that doesn't need that notion of 'symbol' at all. For example:

[Screen]
| 1
| organizes [Message]
| A
| R1 <<ordered>> | R3
| +-------+-------+
* | 1 R2 derived from 1 | |
[Cell] ---------------------- [WithDefaults] [Raw]
| | 0..1 | 1
| | derived from |
[Converter] | R4 |
A +------------------+
| R5
...

The closest thing here to a Symbol is [Cell] but the semantics are quite different because it is the actual video RAM image. The process to convert the message data packet to a cell will be challenging but nothing that one can't decompose with a bunch of [Converter] subclasses and Strategy pattern delegations.

Whether this is the best design isn't relevant; it just has to be plausible. The point of the subsystem Facade interface is to fully decouple the client from whatever design one actually has, regardless of how good it is.


*************
There is nothing wrong with me that could
not be cured by a capful of Drano.

H. S. Lahman
hsl@xxxxxxxxxxxxxxxxx
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
info@xxxxxxxxxxxxxxxxx for your copy.
Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH



.



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: Help on choosing a valid pattern: composite or not?
    ... But that class would only exist in the UI subsystem in my ... In the GUI subsystem where GfxNode might live I am expressing an entirely different set of paradigms for display and I might have a handy MVC infrastructure to make the code simpler, which is where GfxNode comes into the picture. ... I can go directly to the View from the subsystem interface. ... Let's say I have defined a Facade pattern class for the interface called, for lack of anything better, GUIInterface. ...
    (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)