|
How-To For Writing an Application For
Multiple Operating Systems
You may have the need to build an application that
runs on MS Windows, but also on other operating systems. Even if
your current plans envision only the support for MS Windows, this
may change in the
future.
Your best strategy is to plan for an expanded support
from the start. This article is intended to provide some necessary
information to make this easier.
The basic options
At the onset of a new project some options with
respect to multiple platform support are:
-
Go with a one-platform
solution. If you can trust that a vast majority of your
customers have just one platform, and that for the lifetime of
your software it will stay that way, this is a viable option. Your
choice of best tools for one specific platform are greatest. But while at
any point in time and for every market there may exist a dominant
operating system, the software industry is far from static. The inherent
danger with this option is you have difficulties taking advantages
of new
developments. Another drawback is fundamental, but not as
obvious: Having only one platform allows application code to
become intertwined with code that is particular to the operating
system. For developers there is no need to clearly separate the
logic of the application from the integration into the operating
system. The likely result is an undesired mix of issues from
different programming disciplines in the same code (the
application logic with its set of challenges, and the GUI calls
with its particularities).
-
Use design tools that are inherently
cross-platform. Perl, Java, Python, WxWindows... Depending on
your application you may be in a position to "write once, run
anywhere." In most cases the drawbacks to this solution are either
degraded execution speed (many of the cross-platform languages are
interpreted at run time), or limitations that are imposed by the
technology chosen (many of the cross-platform APIs do not, or not
fully, support C++).
-
Carefully plan out your project requirements and
find optimal solutions for each. This solution provides the
potential for an application that performs optimally on many
platforms. However, it is also the option that requires the most
up-front planning and a good understanding of the application
requirements, as well as a detailed understanding of available
alternatives.
Component Software, Inc. has developed a strategy for
cross-platform applications and is using it successfully. The strategy
is based on the principal of concentrating on the functionality
of the application, and to introduce requirements that the
application has as abstractions.
The major benefits of this strategy are:
-
The application is driving the development, leading
to software whose priority is to fulfill the application's tasks. Many application development environments require
the user to follow their methodologies, resulting in programs in which the application's
design and implementation is compromised heavily by impositions of
the development environment.
-
Areas of expertise are better separated into
identifiable units of work. If no distinction has to be made
between code that implements the logic of the application and code
that realizes the connection to the operating system, it is only
natural that the two fuse into one. In such a case, the software developer has
to be an expert in both the application and the operating
system. In contrast, when the application code is clearly
separated into its own routines and files, these parts of the
program can be worked on by specialists for the application
domain, while the code that connects the application to the
underlying operating system can be worked on by specialists that
don't have to know much about the application.
Cross-platform strategy: Isolating Application Code
and Abstracting the Platform Requirements
An example to illustrate this methodology is the
handling of multiple threads in an application. Different platforms
have their specific calls into the operating system to accomplish
creation and management of threads. However, the specification is
defined by the application's requirement only (leaving out anything
that is specific to one or the other platform). The application
developer is now in a position to define the interface for threads
that satisfies the application's requirements.
It is clear that the application can only perform its
tasks if the operating system provides a solution for all of these
requirements. However, the particular solution of any
operating system will not be coded into the application program
itself. Instead, the application declares the interface
(typically as functions or
objects if the chosen programming language supports it), and simply
requires that this interface is implemented. The application must
specify exactly what it expects the behavior of the implementation to be,
but it does not worry about how it is realized. The
application is coded utilizing the interface and trusts that on
each platform that it will run on there will be an
implementation available. These implementations are called
adapters in the rest of this article, since their purpose is to
adapt the underlying platforms to the requirement of the
application.
Practical Considerations
The basic thrust of the described methodology is to
have the application drive the development. In practice it is
necessary to gauge if the application requirements can be met by the
targeted platforms. Are there aggressive requirements for event
responses? If so, some platforms may not be able to provide a
satisfactory implementation. Does the application need a lot of
information from a user at a particular point in time? If so, maybe it is
difficult to get the information organized effectively on a
graphical user interface.
Most applications will also be developed under
resource limitations, making it attractive for a number of
applications to agree on the same adapter interfaces. If a platform provides
an implementation of such a shared interface, all of the applications
can share development and support costs.
The following matrix shows one way of looking at how
an application code can be partitioned into groups:

From a code re-use point- of- view it is best to move as
much code out of the lower-left quadrant. Whenever practical, code
should make use of the upper-right quadrant, since libraries are
typically well-maintained and broadly available. Functionality that is
often used by many applications and/or many adapters (yet has no
dependency on the application or the operating system) can also be
packaged as a library and considered part of the upper-right
quadrant, yielding the typical economies-of-scale
benefits.
From an ease-of-coding perspective the situation is
not as straight-forward. Would it be easier to code some
functionality of the application entirely with custom code, or could
it be done with calls into a library? That question can only be
satisfactorily answered in each specific situation. However, a
general rule can be applied: Libraries become more valuable when
their content can be used easily by many applications (or adapters). Historically, a set of standard code (in the form of
libraries) has emerged that can be used easily enough. Over time
this trend will likely continue in an evolutionary fashion.
Component Software, Inc. makes two examples available on-line in
which the methodology described here is used:
The use of C++ classes
to facilitate the use of multiple threads, available for Windows,
Linux,
and Mac
OSX,
and a simple application, which demonstrates a GUI
application with adapters for graphical user interface elements,
also available for Windows,
Linux,
and Mac OSX.
|