Squeak SmalltalkJoker Squeak Smalltalk : Philosophy : prevnext Domain Separate From Presentation

Separate Domain From Presentation

William Opdyke's 1992 Doctoral Thesis "Refactoring Object-Oriented 
Frameworks" identified eight categories that all refactorings fall 
into. Martin Fowler's book, "Refactoring Improving the Design of 
Existing Code"identifies 72 specific refactoring patterns, each of 
which involve programmer activity in one or more of Opdyke's eight 
categories. This article is about one specific refactoring pattern, on 
page 370 in Fowler's book, that Fowler named Separate Domain From 
Presentation.

No nontrivial project is perfect. Thus, every nontrivial program can 
always be improved. And, we're not very good if we can't spot places 
where we think improvements could be made. Of course, whether those 
improvements should be made, given time and money constraints, is an 
entirely different issue. However, we should always be able to spot 
candidates for improvement. After all, hindsight is much easier than 
foresight.

When I look back on past projects that I have worked on and ask myself 
where improvements could be made, and then I prioritize those 
improvements and categorize them, the top of the list has always been 
domain separation issues. Thus, the single biggest problem in every 
past project I've worked on has been the lack of an adequate 
separation of presentation code from domain code. In every case, the 
single suggestion that would have had the biggest impact on project 
quality, would have been to more fully separate the presentation from 
the domain. In other words, every past project has suffered 
significantly from a lack of proper and complete separation.

This problem is not language specific, as the following poor examples 
from Objective-C, C++, Java, and Smalltalk illustrate. Even though the 
languages for each project were different, the projects shared a 
common set of mistakes: If we can learn to avoid these mistakes, we 
will create systems that are simpler and easier to change and reuse.

Java

I once came to a Smalltalk project where the company had decided to 
migrate to Java (this was during the initial Java heyday). To 
kickstart their effort, they hired a bunch of very high priced Java 
consultants to design the project, and serve as Java mentors 
throughout the project. The client company believed in OO technology 
(thatís why they initially picked Smalltalk), but now they wanted an 
OO project using the best technology, which they erroneously were 
equating with "the most popular". They were willing to pay for the 
best, and thatís what they thought they were getting when they brought 
in an established Java firm to architect the migration. Before any 
code had been written, I had the opportunity to look at some of the 
design documents produced by these consultants.

The design was said to have a "three-tiered architecture", with three 
prominent layers in it. One layer had what they called View Data 
Objects, and another layer was a hybrid of Views (windows and 
associated widgets) together with what they called View Manager 
Objects.

Upon inspection of the View Data Objects, I found the only methods 
contained in these objects were getters and setters. In other words, 
all of the View Data Objects were nothing but data structures, with no 
real behavior (I commonly refer to such objects as struct objects, to 
signify they are nothing but data structures).

The View Manager Objects were designated as the mediators between the 
Views and the View Data Objects, where the Views were the normal 
widgets and windows that are (typically) painted with a GUI tool. In 
other words, the View Manager Objects were the equivalent of 
subclasses of ApplicationModel in VisualWorks (VW), or of 
AbtAppBldrView for VisualAge (VA), upon which your painted canvas is 
installed. In their design, as near as I could tell, all of their 
application behaviors were in the View Manager Objects. That would be 
functionally equivalent to putting all of your VW code in your 
ApplicationModel subclass, or your VA code in your AbtAppBldrView 
subclass.

Thus, every View was a view into a struct object, and the domain 
behaviors for the struct objects were written in the View Manager for 
each view (window and associated widgets). Additionally, just as the 
name suggests, the View Manager was also responsible for managing the 
application-specific behaviors of the view, such as programmatic tab 
sequencing and the disabling/enabling of buttons and text fields based 
on user input. Thus, the View Manager was tightly bound to the View, 
just as its name implies that it would be, and also had domain code 
interwoven within it.

The documents showed no layer distinction between the Views and the 
View Manager. The third layer was said to be the database itself (a 
major RDBMS). Thus, the layers, as defined by their documents, were as 
follows:

   - Views and View Managers

   - View Data Objects

   - RDBMS

Part of the responsibility of the View Manager Objects was to move 
data between the data objects and the database, and process the data 
as needed during the transfer. In other words, the View Manager 
Objects were the data processors in a classical "read data/ process 
data/ write data" cycle typically found in procedural code.

In spite of what the documentation said, this was not a three-tiered 
architecture. It was a classic two-tiered architecture that we see so 
often with tools like Visual Basic or PowerBuilder, where the 
processing code is intertwined with the display code. It was not even 
an OO architecture. So much for high-priced Java "experts"!

C++

Now Iíll back up a few years and tell about a C++ project. I was asked 
to comment on and document a C++ class library that was being written 
to replace a solid (but procedural) C library they had been using. The 
primary architecture for the C++ project was a normal C procedural 
design, but with the struct keyword changed to a class keyword, and 
accessors written. Thatís it. Nothing else was different from a 
standard C program.

Thus, struct objects were everywhere, with nothing but getters and 
setters, and such objects were typically considered to be the domain 
layer, just as the Java project would do later.

What do you suppose my recommendations were for this project?

I was ignored, so staff meetings for this project were very 
frustrating. I once exclaimed: "there should be no publicly accessable 
accessors in the code!". Yes, that statement was false, and I knew it, 
but I was trying to drive a point home. Most of the people in the 
staff meeting never questioned me further, and just went away thinking 
I was nuts, but a couple of people came to me in private later and 
asked me to explain what I meant. My response was:

Think about it if you donít have accessors, where must you put the 
code?

In both cases, they paused and considered what I had just said, and 
then the light turned on. They understood what I meant. The answer was 
obvious the code had to be put into the class that was managing the 
data. Without accessors, there was no other place the code could be 
put!

Objective-C

Now Iíll back up a few more years to an Objective-C project. This was 
a NeXTSTEP application that followed the same poor architecture of the 
Java project that I mentioned first. To give you some idea of the size 
of the application, it encompassed approximately 28,000 lines of 
Objective-C code, and had 15-20 major windows in the user interface, 
and many minor windows in it. Each window of the application was built 
separately using NeXTís Interface Builder tool. This tool would save 
the interface into a file that NeXT called a NIB file (NeXT Interface 
Builder file), which again is analogous to the ApplicationModel 
subclass in VW or the AbtAppBldrView subclass in VA. It used a 
separate class for each window to interface that window to the domain, 
and this class was abstractly called the NIB Manager, because it 
"managed" the NIB file (the actual class name for the NIB manager of 
each NIB file varied, and it usually bore a name similar to what was 
in the title bar of the window that was being managed). Since each NIB 
file had exactly one window defined in it (and occasionally an 
additional dialog or two), each NIB Manager interfaced exactly one 
window to its dependent domain "data" objects. Hence, the architecture 
had:

  - the window and itís widgets, which corresponded to the View 
    objects in the Java example.

  - the NIB Manager, which corresponded to the Java View Manager

  - data structures to hold view data, which corresponded to the Java 
    View Data Objects

Hence, this project suffered from all of the same design problems that 
the Java project did.

Smalltalk

Now Iíll fast-forward to a project that came after all of the projects 
already mentioned. This was a Smalltalk project. On this project, the 
commendable decision was made by executive management to actively 
support "re-use". Of course, executive management also understandably 
wanted to leverage their existing legacy staff a staff that was not 
versed in Smalltalk. Management had also heard (and unfortunately 
believed) that Smalltalk was a "difficult" language to learn. 
Fortunately, they also believed that once you learned the language, 
you could develop much faster with Smalltalk than with other 
languages. But they also believed the myth that the implementation 
language was irrelevant to the design, and that you could design 
independently of the implementation language. Hence, they believed 
that all of their prior experiences with procedural languages 
qualified them to mandate the design and architecture of this project.

Now, with all of these beliefs, it should not come as a surprise what 
architecture was eventually mandated by management.

The legacy team was tasked to create a set of "re-usable RPC services" 
that were to reside on the legacy machines (IBM mainframes), and were 
to be written in the legacy language (COBOL). Those services would be 
callable via standard RPC mechanisms. Thus, those services were 
exactly as the "RPC" name implies Remote Procedure Calls and were 
semantically just a set of classical subroutine calls into a 
subroutine library. The fact that those subroutines executed on a 
remote machine was irrelevant to those semantics. A service call was 
just a conventional subroutine call.

The Smalltalkers were then tasked with creating the GUI to call those 
services. Hence, the Smalltalk program was to be presentation only, 
with no domain logic. And the actual domain logic was to be in a layer 
that was just a procedural, classical subroutine library, written in 
an entirely different language.

At first glance, this project appeared to at least recognize a 
distinction between the domain layer and the presentation layer. But 
when minor domain behavior changes or additions were needed by the 
Smalltalkers, it was easier for them to just throw some minor changes 
into their ApplicationModel subclass that was driving the window than 
it was to push for the needed changes in the COBOL services. Thus, 
some of the domain behaviors became intermingled with the presentation 
logic, and the balance of the domain behaviors were in an RPC 
subroutine library written in COBOL.

Confession

I was the architect of exactly one of these projects. I was the one 
that designed the Objective-C project. It was my first foray into 
OO-land, about ten years ago (with the exception of dabbling with C++ 
in college a few years earlier), and you can see it wasn't OO at all. 
I didn't even know how to do OO at that time but I thought I did. And 
that, I believe, is the main reason that we see these same mistakes 
over and over those other designers (and often management) think they 
know OO, but don't.

Among other problems, every one of those projects suffered from the 
lack of an adequate and crisp separation of presentation code from 
domain code.

So what should we do about it?

Once And Only Once

"Once And Only Once" for the old RDBMS crowd is represented in their 
mathematically rigorous theories of normalization. The whole impetus 
for relational database normalization is so that data appears "Once 
And Only Once" in the database, because otherwise there are 
well-documented "update" anomalies that can occur, due to the classic 
two-space problem created when the same data exists in more than one 
place.

What many people miss, though, is that this same two-space problem 
that normalization is supposed to correct for data can also exist for 
code. If you donít practice "Once And Only Once" for code, a very 
similar set of anomalies can occur, where the behaviors can get out of 
sync. "Once And Only Once" for code is the next logical step down the 
evolutionary path begun many years ago by the RDBMS crowd but this 
time it is for code instead of data.

"Once And Only Once" is the basis of good design. It is foundational, 
and is the feature behind what makes the OO paradigm what it is. For 
example, in the simplest case, proper use of the OO paradigm 
eliminates the repetitive use of "if", "case", and "switch" statements 
(or their equivalent in whatever language you want to consider), and 
instead implements the equivalent functionality within the messenger 
itself. Proper use of the OO paradigm forces a "Once And Only Once" of 
these kinds of control structures into a single replacement 
mechanism-- the messenger itself.

Additionally, static languages (such as C++ or Java) mix the notions 
of classes and typing, and try to make them mean the same thing. They 
are forced to do this so that they can annotate variables with type 
information, and in so doing, they scatter type information all 
through the program type information ends up in each variable 
declaration as well as within the class declarations. For example, 
consider the following hypothetical code snippet:

Graph myGraph = new Graph();

Why should I have to say "Graph" twice? This is a clear violation of 
"Once And Only Once".

In contrast, with Smalltalk the concept of "substitutability" (and 
therefore "subtyping") is not associated with the inheritance 
hierarchy, and types are encapsulated with the objects themselves. 
This means that should a type change later be necessary, then 
Smalltalk has succeeded in better localization of the change than Java 
or C++. This difference can clearly be seen if the process of making a 
change to a method signature in a class requires all clients of the 
affected class to recompile, even if they donít use the method that is 
being changed! Such constraints donít exist in dynamic languages like 
Smalltalk the only clients that are effected in this case are those 
that actually use the method that was changed. This difference is 
because of a closer adherence to "Once And Only Once", where type 
information isnít replicated with every variable declaration. Thus, 
static OO languages by their very nature unavoidably introduce 
two-space problems into your program, and this is precisely why 
programs created with them are generally more brittle than programs 
created with dynamic OO languages such as Smalltalk.

Practicing "Once And Only Once" will also force you to gather the 
domain code into one place the domain layer because otherwise the 
domain logic gets scattered all through the other layers. There is no 
way to practice "Once And Only Once" without gathering the domain 
behaviors into one place.

Of course, it is not difficult to introduce two-space problems into a 
poorly built Smalltalk program. Problems caused by bad system design 
can dwarf the magnitude of the inherent two-space problems built into 
a well-crafted Java or C++ program. We need to avoid making these 
mistakes, otherwise much of the advantage of using Smalltalk is lost.

And how do we do that?

We do that by practicing "Once And Only Once". And, the most 
significant application of "Once And Only Once", and the one with the 
most far-reaching effects, is to gather all of the domain behaviors 
into one place the domain layer.

The Domain Layer

So what exactly is the domain layer? What behaviors belong in the 
domain objects?

The domain layer, properly done, is the life and intelligence of the 
object system. Properly done, it is the program! And, it has no 
particular user interface! It doesnít care about the nature of the 
user interface, or even if there is a user interface. In an 
environment where the object paradigm is the only paradigm in the 
system, the domain layer is what is left after youíve tried 
relentlessly to make the rest of the system so simple it couldnít 
possibly break.

Anytime the Presentation Layer (typically a GUI) ends up with code 
that is not so simple it couldn't possibly break, treat that situation 
as a code smell, and try to fix it by simplifying the GUI code and 
moving the code to the domain layer. What I have found, is quite often 
you think you need a piece code in the GUI, but it turns out that, 
given a little more thought, it was actually possible to move it to 
the domain layer, and in the process keep the GUI code so simple it 
can't possibly break.

What is invalid data? What data is mandatory? Only the domain should 
know. If you embed this knowledge in the GUI, you will violate "Once 
And Only Once". What if the rules change? Do you really want to track 
down every place in the GUI where the validation knowledge is present? 
The GUI is the wrong place for validation logic.

Also, there is no particular need, aside from human convenience and 
human aesthetics, for the user interface to even be graphical. The 
user interface could be command line oriented, if you wish it to be. 
Thus, it should be possible to exercise the program from a Smalltalk 
workspace.

The domain layer is the program, and any other code in the system 
should border on the trivial. If you donít have it that way, then you 
probably havenít completely separated the domain layer from the rest 
of the system.

Separate Domain From Presentation(370), is a refactoring near the end 
of Martin Fowlerís Refactoring book, in a chapter that was co-authored 
by Kent Beck. That chapter is entitled Big Refactorings, and Separate 
Domain From Presentation it is indeed a big refactoring. Many 
refactorings can be mechanically done, as is evidenced by the 
existence of the Refactoring Browser. But Separate Domain From 
Presentation(370) cannot be mechanically done. Only a general 
guideline of the mechanics of the refactoring can be given.

If you are presented with a program that does not have the domain 
separated properly, typically it will be because the domain code is 
intertwined with the display code. For this situation, the mechanics 
of the refactoring are as follows:

Mechanics

    * Each window of the GUI of your application will have an 
      overriding theme. It could be anything, but a few examples might 
      be a customer name-and-address theme, or an application security 
      theme, or a clerk setup theme, or a preferences theme, or 
      anything else. You need to discover the major theme of each 
      window. That theme very likely will identify a domain class. 
      Create the domain class represented by the major theme of each 
      window.

    * For each window, identify the data that the window uses. Of that 
      data, identify which of it is domain data, and which of it 
      should be private to the user interface, and which of it is 
      needed for both. Create an instance variable in the domain class 
      for each piece of domain data, even if it is also needed 
      directly by the user interface.

    * Initially you will need to create, as a minimum, getter methods 
      for the instance variables of your domain class, and you 
      probably will need setter methods as well. Of course, the use of 
      these methods outside of your domain class is a violation of 
      encapsulation, but until you get all of the domain behaviors 
      properly moved from your window manager (subclass of 
      ApplicationModel for VW or AbtAppBldrView for VA) into your 
      domain class, you have no choice. You might be able to refactor 
      out the external use of these accessors later, but for now, your 
      window manager will need to be able to access the raw data of 
      your domain, just as it is doing now, and process that data. 
      Thus, it will need accessors.

    * Change the window manager class to access the data from the 
      domain class via the domain accessors. In doing so, you will 
      also be identifying all of the code that accesses the data.

    * Now that you have identified the code that accesses the data, 
      move that code down into the domain class so that external use 
      of the accessor is no longer needed. If your window manager 
      class contains SQL code, all of that code needs to be moved to 
      the domain object.

    * As a test to determine if you have moved all of the code that 
      you should, you should be able to modify the getters of your 
      domain class to just return copies of the domain data instead of 
      the actual domain data, and making that change should not impact 
      the operation of your program. If making that change does impact 
      your program, then your window manager class is directly 
      manipulating domain data instead of letting the domain class do 
      it. You need to break that coupling.

    * At this point, you should have a separation of GUI from the 
      domain, although the domain classes will probably not be well 
      factored. Factoring the domain classes is a different set of 
      refactorings to be done later.

Example

Here is an example of a screen of a Preferences window used in a 
VisualWorks application. The window manager class for this window is 
PreferencesUI, which was built as a subclass of the VisualWorks 
ApplicationModel class.

The main theme of this screen was factored out into the domain class 
called Company. Looking at this window, and the data held by the 
window, immediately revealed two additional domain classes: 
USPhoneLine and USPostalAddress (actually, they began as Phone and 
PostalAddress, but changed to USPhoneLine and USPostalAddress at a 
later date). Domain and range constraints that were originally 
embedded in the GUI were moved to their respective domain classes, and 
the properties of all the textfields in the GUI were switched to 
display and hold strings only. For example, the PhoneLine class was 
given the ability to separate a string into the 
AreaCode/Exchange/Station/Extension components of a phone number, and 
would echo back a properly formatted string of the current phone 
number when requested to do so. Thus, when the GUI would "Save" a 
phone number, it handed the string to the domain, which was an 
instance of the Company class. The company would then instantiate a 
USPhoneLine instance, passing to it the string that it was given. The 
USPhoneLine class would interpret the string while it constructed an 
instance, and the company would answer that formatted interpretation 
back to the GUI. The GUI would then redisplayed whatever the domain 
responded with, so that the user could see what the domainís 
interpretation of what they had typed in was.

Likewise, whatever was typed in the "State:" textfield was just handed 
to the domain (an instance of the USPostalAddress class, in this 
case), and the domain would echo back its interpretation of it. If the 
domain could make sense of it, a two-letter abbreviation for the state 
that was recognized was answered, and that interpretation (the 
two-letter state abbreviation) was redisplayed so that the user got 
immediate feedback.

The other widgets followed a similar design, wherein they accepted 
whatever the user typed in, and just handed it to the domain without 
otherwise trying to interpret the data. It was up to the domain to 
interpret the data, and the GUI just redisplayed whatever the domain 
decided its interpretation was. For example, the code to process the 
"Minimum Acceptable Customer Age:" was just:

minCustAge value: (company minCustAge: minCustAge value).

In this code snippet, the string in the ĎminCustAgeí textfield is 
accessed and passed to the company. The company looks at the incoming 
data, and makes a determination of what to do with it based on the 
business rules it knows about. It then answers its interpretation of 
the data passed to it, and that interpretation is then redisplayed to 
the user. The GUI doesnít otherwise look at or try to interpret the 
values at all.

The net result was that the GUI was dramatically simplified, with most 
of the code moving to the domain layer. And, about half of what was 
left of the GUI code ended up in the #save method that was triggered 
when the "Save" button was clicked, and all of that code just blindly 
moved data to the domain and redisplayed the domainís answer, just as 
the code snippet shows.

Of course, this design approach meant that the application became 
screen-oriented, and didnít give feedback to the user until the "Save" 
button was actually clicked, because it was at that time that the 
screen data was sent to the domain for its interpretation. But, this 
application was later webified, and this screen-oriented behavior was 
actually desired, because HTML web browsers are screen-oriented.

It worked well.