Maverick Porting Code Model
version 1.1 March 24, 2006
by Geoffrey Slinker
Abstract
Porting code will ocurr as long as there are changes in software systems and the
need to move code onto these new systems. Porting code "line by line" is an
approach that is so close to the implementation that the design is not seen.
Understanding the purpose of the code and the reasons why the code includes the
statements it does is essential. Porting code requires a broad and thorough
knowledge of the current implementation, the current system, the current
implementation language, the functional requirements of the current
product, the new implementation, the new system, and the new
implementation language (sometimes in a port all of the things mentioned do not
change). Since there is such a broad and thorough understanding needed its
amazing that the task is given to "junior" developers. Ultimately code porting
should be requirements porting.
Introduction
Porting code is an ongoing issue. As long as there are changes in software
systems and the need to move code onto these new systems. Porting code is a
difficult task that is often assigned to "junior" developers or developers that
are not viewed as "current" or are not working on the core products or leading
edge. The sheer amount of understanding needed to port a system is well beyound
the typical understanding of those that usually get "stuck" with porting code.
If you have ever experienced a failure in porting a system I would ask you,
"Did you put your best people on the job or did you use someone else?".
Reasons for Porting
Following is a brief list of possible reasons to port a system. This list is not
supposed to be a complete listing but just a subset of the possible reasons.
-
Multiple platform release (consumer products, office suite products...)
-
Often a desktop application will be released for a derivative of Microsoft
Windows and then be followed with releases for Macintosh OS X and some flavor
of Linux.
-
Host platform change (switching product line to a different and unrelated
platform)
-
Often a desktop application will be re-deployed as a Web application.
-
Host platform update (host platform has new Operating System
(OS) that is different and may be significantly different)
-
A significant change has been made to the OS such as the change from Macintosh
OS 9 to Mac OS X.
Porting Code has many Problems
-
Propagates optimizations made for a specific configuration.
-
Propagates bugs hidden in the code.
-
Propagates work-arounds that were introduced into the code because of
inadequacies of the host platform.
-
Causes the creation of abstraction layers for OS specific things such as file
systems, shared memory, threading, socket implementations, and synchronization.
-
Propagates incorrect assumptions of the system, code takes the path of least
resistance and programmers unknowingly code around problems. They choose some
system call that doesn't work and so without investigating why their first
choice was wrong they find another routine to call or they change some
parameter that makes everything "suddenly" work.
From my experience I say, "Don't port code. It's not worth it." But we have to
migrate systems to future needs. What should we do? We should port functional
requirements, domain models, and domain language.
How to Port Software
There is no generic answer to how to port software. It is a situational problem
just like most problems in software development. Following are some steps that
can be applied if your situation calls for them.
-
The team to port the software is the same team that developed the system to be
ported. These people have the domain knowledge and the understanding of such
things as "why the code uses linked list instead of a hash". But there are more
things this team knows. They know the customer. They know why the config files
were tweaked the way they are. They know why they used a flat file instead of a
database. They know many other answers to the situational questions that were
answered that caused the software to emerge the way it did. They also know that
the new situation is different. In the previous examples they might say, "We
used a flat file back then because the DB licenses were too expensive and the
user base was only around 50 people. Now we need to use an SQL database that is
transacted and fault tolerant." Just porting the flat file would be a mistake
that a noninformed junior programmer would make.
-
Port at a higher level than "line by line". If the code is developed with an
object oriented language and you are porting it to an object oriented language
then examine the public methods and consider them as candidates for public
methods in the new implementation. If the code is non-object oriented then
examine which functions are "exported" and consider them. The goal of these
activities is to identify the interfaces.
-
Provide a validation technique. Provide a way to capture the operating results
of the current system in a way that can be used to compare to the operating
results of the new system. If the comparison can be automated all the better!
This will require an input set of data to drive the system in a predictable
manner. This input data should cover normal operating conditions as well as
exceptional conditions.
-
If performance is a significant issue then least common denominator abstaction
layers will be a problem. Mapping the Windows thread messaging and
synchronization model onto Solaris will result in inefficiencies in Solaris. I
worked on a code port from Windows to Solaris where the approach was to port
the Windows API's that were used in the product to Solaris. By doing this there
would be one code base for each product. After porting such things as
WaitForSingleObject, WaitForMultipleObjects, CreateEvent, PulseEvent, and
Interlocked Compares to Posix Thread equivelants we had achieved a single
source for the "core" product. Since the Solaris version had to jump with
"Window's hoops" it was inefficient. Also whenever a new Windows function was
used in the product someone had to make a Solaris equivelant and so the porting
team was always "down stream" of the "core" team.
-
If "look and feel" is a significant issue for the platforms supported then a
least common denominator solution for GUI components will not suffice. When
porting from Windows to Macintosh if you truly expect Macintosh adoption then
you must give them a Macintosh solution. If anyone remembers the first version
of WordPerfect for the Macintosh you will know what I mean!
-
Resist adding any new functionality until you have all of the required old
functionality in place and working correctly. Do not ignore any system wide
considerations for the new functionality but at the same time do not let the
new functionality couple unnecessarily with the old domain.
Port the model and the functionality to the new system. Do not try to "just"
port the code.
If you are fortunate enough to be in a modern development shop that has customer
tests and programmer tests available you can use Test Driven Development
to drive the port.
-
Port the customer tests to the new system to drive the validation process.
-
Divide the existing programmer tests in a fashion so that you can deliver
functioning subsystems and efficiently use all of the team members by working
in parallel.
-
Select a programmer test and port it to the new system.
-
Run the selected test and develope the solution for that test. Use any aspect
of the existing system that is applicable in the new situation. If you can then
copy and paste code but don't do this without understanding the old solution.
Conclusion
Porting code will ocurr as long as there are changes in software systems.
Porting code "line by line" erroneously propagates situational choices that are
most likely not applicable to the new system. Understanding the reasons of the
current code state is essential. Porting code requires a broad and
thorough knowledge that is had by the team that developed the original
system. Porting can not be done by junior programmers with
minimal guidance. Ultimately you should not port code but you should
port requirements, interfaces, and domain models.
Revision History:
Draft April 2004
v1.0 May 2005
v1.1 March 2006