Home > Articles

Structuring Applications with Graphical Interfaces

This chapter investigates the architectural building block that keeps applications with user interfaces maintainable and portable.
This chapter is from the book

Chapter 7 introduced the technical and conceptual basis for building user interfaces using the SWT framework that comes with Eclipse. At the core, development comprises two aspects: setting up a widget tree with layout information to create the visual appearance, and attaching event-listeners to the individual widgets to implement the application’s reaction to user input. Although this seems simple enough, this basis alone is too weak for building larger applications: Since the application’s functionality tends to be scattered throughout event-listeners, one will almost certainly end up with a code base that cannot be maintained, extended, and ported to different platforms—in other words, software that must be thrown away and redeveloped from scratch.

This chapter investigates the architectural building block that keeps applications with user interfaces maintainable and portable: In the code, one always separates the application’s business logic strictly from its graphical interface. Section 9.1 introduces this approach, called model-view separation, and traces it through different examples within the Eclipse platform. Next, Section 9.2 discusses its conceptual and technical basis, the classical MODEL-VIEW-CONTROLLER pattern. Section 9.3 introduces the JFace framework, which complements the basic SWT widgets by connecting them to the application’s data structures. Section 9.4 uses a running example MiniXcel, a minimal spreadsheet implementation, to give a self-contained overview and to explore several implementation details of model-view separation that must be mastered to create truly professional applications. Finally, Section 9.5 adds the aspect of making edits undoable, which is indispensable for achieving usability.

Throughout the presentation, we will pay particular attention to the fact that model-view separation is deceptively simple: While the concept itself is rather straightforward, its rendering in concrete code involves many pitfalls. We will discuss particularly those aspects that have often been treated incorrectly in the work of novices to the field.

Before we start to delve into these depths of software design and implementation, there is one general piece of advice to set them into perspective:

Always gear the application toward the end users’ requirements.

The reason for placing this point so prominently is that it is neglected sobook.jpg 258 often. As developers, we often get swept away by our enthusiasm for the technically possible and the elegance of our own solutions. However, software development is not a modern form of l’art pour l’art, but a means of solving other people’s pressing problems. These people, called “users,” dobook.jpg 229 not care about the software’s internals; they care about their own workflows. So before you even start to think about the software’s view and model andbook.jpg 28 the elegance of their separation, talk to the end users: What are their expectations of the software’s concrete behavior? How do they wish to interact with the software? Which particular tasks must the software support? The conscientious professional software engineer starts application development by learning about the users’ work—in other words, by learning about the software’s application domain. Everything said subquently must be subject to this overall guideline.

9.1 The Core: Model-View Separation

Every application has a purpose for which it is built and which provides its unique value to its users. Correspondingly, the application contains code that implements the business logic to fulfill that purpose. Apart from that, most applications need a graphical user interface, simply because they have nontechnical users who do not appreciate command-line tools too much.

Apart from all of the strategic considerations related to software qualitydouble_arrow.jpg 9.2.2 and maintenance, to be discussed later, it is useful to keep the code implementing the business logic and the user interface separate simply because they have different characteristics (Fig. 9.1). Users buy, for instance, CAD software because its business logic can do CAD and nifty computations, but they accept it into their working routine because they like the way they can interact with it. The business logic of a CAD system must be extremely reliable to prevent bridges from collapsing, and it must be stable enough through different software releases, for instance, to read the same files correctly throughout projects running for several years. The interface, in contrast, must be visually appealing and must adapt to the changing working habits of its users so that they can, for instance, exploit new input methods such as 3D interaction devices. To achieve stability, the business logic must adhere to rigorous contracts and must be tested comprehensively,arrow.jpg 7.11 arrow.jpg 5.3.5 while the interface is event-based and cannot be tested easily, especially if it is liable to frequent changes. Finally, the business logic must deal with internal data structures and basic services such as file I/O, which are easily ported to different platforms. The API of graphical interfaces, in contrast, varies dramatically between platforms, and user interface code is usually not portable at all—for instance, from SWT to Swing. Keeping business logic and user interface separate is therefore first of all a matter of separation of concerns.

Figure 9.1

Figure 9.1 Characteristics of Business Logic and the User Interface

Keep the user interface and the business logic in different modules.

Accepting the goal of this separation, we have to investigate how it can be accomplished in the concrete software. Fig. 9.2 gives an overview, whose aspects we will explore in the remainder of this section. As a first step, one places the user interface and the business logic into separate modules, as indicated by the dashed horizontal dividing line in the figure. Referringdouble_arrow.jpg 9.2 to their roles in the MODEL-VIEW-CONTROLLER pattern, the business logic and the user interface are also called the model and the view, respectively, which explains the term model-view separation as a summary of the principle.

Figure 9.2

Figure 9.2 Overview of Model-View Separation

double_arrow.jpg A.1 In Eclipse, modules are implemented as plugins. Throughout the Eclipse code base, plugins with suffix .ui access the functionality provided by the corresponding plugins without that suffix. For instance, org.eclipse.jdt.ui accesses the Java Development Tools, whose logic comes in plugin org.eclipse.jdt.core, as well as org.eclipse.jdt.launching, org.eclipse.debug.core, and others.

Introducing separate plugins will at first appear as a somewhat largedouble_arrow.jpg A.1.2 overhead for small applications. However, the sophisticated support for plugin development in Eclipse removes any technical complexity and exhibits the benefits of the split: The functionality can be linked into different applications to enable reuse; unit tests run much faster on plugins that dodouble_arrow.jpg A.1 not require the user interface to come up; the OSGi class loader ensures that the logic code cannot inadvertently access interface classes; the logic module remains small and focused on its task; and several more. And, finally, successful small applications have a tendency to grow quickly into successful large applications; the split into different plugins ensures that they will also grow gracefully.

The model contains the application’s core functionality.

From the users’ perspective, an application is all about the user interface, since they are not and should not be aware of any other part. The interface creates simplifications and abstractions that keep all the technical complexitybook.jpg 229 under the hood. When writing a letter with a word processor, for example, one certainly does not want to think about linear optimization problems for line and page breaking.book.jpg 142

The software engineer, in contrast, focuses on the business logic, or the model, in Fig. 9.2. That component contains the data structures and algorithms that solve the problems that the application is built for. Its objects constitute the machinery that the whole project relies on. Its answers to thedouble_arrow.jpg 11.1 technical, conceptual, and maybe scientific challenges make up the team’s and the company’s competitive advantage. The user interface from this perspective is merely a thin, albeit commercially all-important, wrapper that enables nontechnical users to take full advantage of the functionality.

We have chosen the term “core functionality” rather than just “functionality” in this summary because the user interface does provide its own nontrivial behavior. Visual highlights and effects, reactions to drag-and-dropdouble_arrow.jpg 9.4.4 gestures, and wizards to guide the user—they all require careful engineering in themselves. Yet, they do not belong to the “core,” because they would need to be rebuilt from scratch on a new platform.

Never mention user interface classes in the logic.

The goal of the proposed division is to keep the business logic independent of the user interface, because this will establish precisely the separation of concerns indicated in Fig. 9.2. This can, however, be accomplished only if the code implementing the business logic never mentions user interface classes, such as widgets, images, or other resources: A single reference to a specific user interface library destroys portability and testability. At the level of modules, this means that the user interface module will reference the logic module, but not the reverse.

Connect the user interface to the logic using OBSERVER.

The question is then how logic objects can ever communicate with interface objects at all. The key insight here is that the OBSERVER pattern enables precisely this communication: The subject in the pattern accesses its observersarrow.jpg 2.1.2 only through an interface that is defined from the perspective of the subject and is independent of the concrete observers.

In the case of model-view separation, the observer interface is contained in the business logic module, and that module sends change messages to observers in the interface module (see Fig. 9.2). These observers will translate the generic change notifications into concrete updates of the widgets.

Let us look at the example of Eclipse’s management of background jobs, which also exhibits several interesting facets beyond the bare fundamentals.arrow.jpg 2.1.1 We have already seen that the platform’s JobManager allows observers to register for change notifications:

org.eclipse.core.internal.jobs.JobManager

public void addJobChangeListener(IJobChangeListener listener)
public void removeJobChangeListener(IJobChangeListener listener)

The interface IJobChangeListener is contained in the same package as the job manager itself, in org.eclipse.core.runtime.jobs. Neither that interface nor the IJobChangeEvent is connected in any way to possible user interfaces.

org.eclipse.core.runtime.jobs.IJobChangeListener

public interface IJobChangeListener {
    public void scheduled(IJobChangeEvent event);
    public void aboutToRun(IJobChangeEvent event);
    public void running(IJobChangeEvent event);
    public void done(IJobChangeEvent event);
     ...
}

The standard user interface for jobs is the Progress view, implemented in class ProgressView and several helpers. They reside in the user interface package org.eclipse.ui.internal.progress. The central class is thearrow.jpg 1.3.8 (singleton) ProgressManager, which registers to observe the (singleton) JobManager.

org.eclipse.ui.internal.progress.ProgressManager.JobMonitor

ProgressManager() {
     ...
    Job.getJobManager().addJobChangeListener(this.changeListener);
}

org.eclipse.ui.internal.progress.ProgressManager

private void shutdown() {
     ...
    Job.getJobManager().removeJobChangeListener(
        this.changeListener);
}

Construct view-related information at the view level.

The example of the Progress view also illustrates a typical aspect that accounts for a lot of the complexity involved in presenting the business logic adequately to the user: the need to create intermediate view-related data structures.

The model of jobs is essentially a flat list, where each job provides progress reports through progress monitors. Usability, however, is improvedarrow.jpg 7.10.2 by arranging the display into a tree of running jobs, job groups, tasks, and subtasks that integrates all available information. The ProgressManager in the user interface therefore constructs a tree of JobTreeElement objects. Since the information is useful only for a specific intended user interface and might change when the users’ preferences change, the maintenance of the tree is handled entirely in the view, not in the model.

The ProgressManager’s internal logic then integrates two sources of information into a single consistent tree: the running and finished jobs, obtained through the observer registered in the preceding example, and the progress reports sent by the running jobs, to be discussed next.

Let the model access the view only through interfaces.

The observer pattern is only one instance of a more general principle, if we perceive the view and the model as different layers of the overall application.double_arrow.jpg 12.2.2 book.jpg 59 In this context, a lower layer accesses a higher layer only through interfaces defined in the lower layer, so as to allow higher layers to be exchanged later on. Furthermore, the calls to higher layers usually take the form of event notifications (see Fig. 9.2). In a typical example, the operating system’s networking component does not assume anything about applications waiting for data, but it will notify them about newly arrived data by passing that data into the buffers belonging to the application’s sockets.

Both aspects—the access through interfaces and the notifications—can also be seen in the handling of progress reports. The model-level Jobs receive an object to be called back for the reports, but this object is given as an interface IProgressMonitor:

org.eclipse.core.runtime.jobs.Job

protected abstract IStatus run(IProgressMonitor monitor);

The user interface can then create a suitable object to receive the callbacks. In Eclipse, this is also done in the ProgressManager class, where progressFor() creates a view-level JobMonitor.

org.eclipse.ui.internal.progress.ProgressManager

public IProgressMonitor createMonitor(Job job,
                                      IProgressMonitor group,
                                      int ticks) {
    JobMonitor monitor = progressFor(job);
     ... handle grouping of jobs
    return monitor;
}

The guideline of accessing the user interface only through interfaces can also be seen as a positive rendering of the earlier strict rule that no class from the user interface must ever occur in the model code. If the model code must collaborate with a view object, it must do so through model-level interfaces implemented by view objects.

Event-listeners mainly invoke operations defined in the model.

We have now discussed in detail the notifications sent from the model layer to the view layer, depicted on the left-hand side of Fig. 9.2. This focus isdouble_arrow.jpg 12.1 justified by the fact that the decoupling between model and view originates from the proper use of interfaces at this point.

The right-hand side of Fig. 9.2 shows the complementary collaborationarrow.jpg 7.1 between view and model. By technical necessity, the user input is always delivered to the application code in the form of events. The question then arises as to how the expected behavior of the overall application should be divided between the event-listeners in the view and the code in the model component.

The main insight is that the event-listeners are a particularly bad placearrow.jpg 5.3.5 for valuable code. The code cannot be tested easily, which makes it hardarrow.jpg 5.4.8 to get it stable in the first place, let alone keep it stable under necessary changes. Also, the code will probably be lost entirely when the users demand a different interface or the application is ported to a different platform (Fig. 9.1).

It is therefore a good idea to place as little code and logic as possible into the event-listeners, and to move as much as possible into the modelarrow.jpg 4.1 arrow.jpg 5.1 instead. There, it can be made reliable through contracts and testing; there, it can be reused on different operation systems; there, it can be maintained independently of the vagaries of user interface development.

In the end, the ideal event-listener invokes only a few methods on the model. The only logic that necessarily remains in the event-listeners relates to the interface-level functionality such as the handling of drag-and-drop ofdouble_arrow.jpg 9.4.4 data and of visual feedback on the current editing gestures.

Design the model first.

It is tempting to start a new project with the user interface: You make rapid progress due to the WindowBuilder, you get early encouragementarrow.jpg 7.2 from prospective users, and you can show off to your team leader. All of this is important, since nifty data structures without a usable interface are not worth much—in the end, the users have to accept the application and use it confidently. For this reason, it can also be strategically sensible to start with the interface and even a mock-up of the interface, to check whether anybody will buy the finished product.

Because starting with the user interface is such an obvious choice, we wish to advocate the complementary approach: to start with the model.book.jpg 59 Here are a few reasons for postponing work on the user interface for a little while.

  • You stand a better chance that the model will be portable and reusable. As with the test-first principle, the missing concrete collaborators inarrow.jpg 5.2 the user interface reduce the danger of defining the model, and in particular the observer interfaces (Fig. 9.2), specifically for those collaborators.arrow.jpg 2.1.2
  • Test-first is applicable to the model, and it will have its usual benefits.arrow.jpg 5.2
  • The model will naturally contain all required functionality, so that the danger of placing too much functionality into the listeners is avoided from the start.
  • There is no danger that a mock-up user interface presumes an API for the model that cannot be supported efficiently.
  • The mission-critical challenges, such as in algorithmics, will be encountered and can be explored before an expensive investment in the user interface has taken place. If it turns out that the application will take a longer time than expected or cannot be built at all, the company has lost less money. Also, there is still time to hire experts to overcome the problems before the release.
  • The user interface can focus on usability. Once the functionality is available, the user interface team just has to provide the most effective access paths to that functionality; it does not have to delve into the business logic aspects.

double_arrow.jpg 9.2.2 Together, these aspects maximize the benefits of model-view separation.

Envision the interface while creating the model.

Conversely, a strict focus on the model is likely to have drawbacks for the final product. From an engineering point of view, the API of the model may not suit the demands of the interface, so that workarounds have to be found:

  • The event-listeners contain extensive logic to access the existing API. This means that this logic will be lost when the interface has to change.
  • arrow.jpg 2.4.1 The model contains adapters to provide the expected API.
  • The model has to be refactored.

From a usability perspective, the fixed model API may induce developers to take the easy way out of these overheads and to provide a user interface that merely mirrors the internals. A typical example comprises CRUD (CReatebook.jpg 220,145,266 Update Delete) interfaces to databases, which are easy to obtain, but whichbook.jpg 114 are known to provide insufficient support for the user’s workflows.

Model-view separation incurs an extra complexity that will pay off.

We have seen much motivation and many benefits of model-view separation,double_arrow.jpg 9.2.2 and we will discuss the details. At the end of this overview, however, let us consider not the benefits, but the costs of model-view separation.

  • Splitting the code into separate modules always involves the design of interfaces between the modules, and the communication about them can take a lot of time and presents the potential for mistakes that must be remedied later at high cost. When a data structure is kept right in the user interface, one can hack in a new requirement at the last minute. In contrast, if the data is encapsulated in a different module, one may have to negotiate with the developers who are responsible first.
  • The collaboration from model to view always takes place by generic change notifications (Fig. 9.2), rather than specific method calls that update parts of the screen. In the model, one has to provide thearrow.jpg 2.1 general OBSERVER pattern for many objects, even if there is in thearrow.jpg 2.1.4 end only a single concrete observer in the user interface. Furthermore,double_arrow.jpg 9.4.3 the logic to translate the changes into screen updates itself can be substantial and complex, especially if it is necessary to repaint the smallest possible screen area to keep the application responsive.

Model-view separation is therefore an effort that must be taken at thedouble_arrow.jpg 9.4 start of a project. The walk-through example of MiniXcel will give you a mental checklist of the single steps, which allows you to assess the overall effort up front. We hope that the checklist is then simple enough to convince you of using model-view separation in all but the most trivial throwaway applications. Even in projects of a few thousand lines, the investment in the extra structure will pay off quickly, since the software becomes more testable, maintainable, and changeable. And if the application happens to live longer than expected, as is usually the case for useful software, it is ready for that next step as well.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020