Beruflich Dokumente
Kultur Dokumente
By
Budianto
Student Number: 20299965
DISSERTATION
Submitted in partial fulfillment of the requirement
for the degree of Master of Engineering in Information Communication Technology
in School of Electrical, Electronic and Computer Engineering of
University of Western Australia
Budianto
15B Garvey St
Waterford, 6152
Western Australia
29 May 2009
The Dean
Faculty of Engineering Computing and Mathematics
The University of Western Australia
35 Stirling Highway
CRAWLEY WA 6009
Dear Sir
I submit to you this dissertation entitled “Refactoring AutoSim for Program Comprehension” in
partial fulfillment of the requirement of the award of Master of Engineering in Information and
Communication Technology.
Yours faithfully
Budianto
ii
Abstract
This dissertation provides Automotive Simulator program restructuring activities that improve
software design, software understandability, and software reusability.
Firstly, it introduces some low level refactoring that is the fundamental aspect of program
restructuring especially to improve code readabilities and program comprehension. These
refactoring is also the preliminary strategies to assist the high level refactoring that can be used
to improve the software design and software reusability.
This dissertation identifies the code readability issues in Automotive Simulator, presents some
low level refactoring operations to improve code readability, explores some multithreading
implementation, performs program restructuring on the multithreading management, mitigates
singleton pattern overuse, implements state transition modeling using state pattern, and
introduces the creational pattern for data creation.
iii
Acknowledgement
First of all, I would like to thank my supervisor, Thomas Bräunl, for His guidance and also
advices given are the most appreciated. I am grateful for his valuable time for reading the first
draft of this dissertation and giving lots of insights in every weekly Monday meeting as well. I
am amazed by his stamina towards several research projects that encourage me to do this project.
I hope that our collaboration will continue in the coming days.
I wish to thank to Terry Woodings, for being an inspiring lecturer and his tremendous views on
software engineering. His insightful assignments also keep me busy and give invaluable ideas to
this project as well.
Thanks to AusAID for supporting my study in the University of Western Australia. I also thank
to Christine Kerin, the AusAID liaison, who provides support during my study.
I would like to thank Steven Bradley for sharing the ideas and also discussing about each
project‟s progress and difficulties that both faced. I am also thankful to Hilman Pardede and
Shaun my classmates.
I wish to thank to my beloved parents for their supports, and especially their guidance and also
the encouragements given. For their love and understanding that are the most precious things for
me.
I would like to thank to Eveline for her supports, encouragements and her prayer for me until this
project is being accomplished.
I wish to thank to all my friends both in Indonesia and Perth, for all their encouragements and
pray for me. I feel really grateful also for the great fellowship that I have found in MRII Perth
and Phillia Philharmonic Choir that giving me such a huge supports and motivations.
Finally, I thank God for granting me talents and opportunities that made this possible and for my
salvation. Fundamentally, everything is vanity without Him.
iv
Table of Contents
Acknowledgement ........................................................................................................................ iv
v
2.3.5 Refactoring in Practices .......................................................................................... 16
4.5 Discussion....................................................................................................................... 37
vi
Chapter 5 Refactoring Multithreading Application ............................................................... 38
5.7 Summary......................................................................................................................... 47
6.4.1 Example................................................................................................................... 54
vii
7.2.3 State Pattern ............................................................................................................ 65
7.4.1 Example................................................................................................................... 69
8.4 Discussion....................................................................................................................... 95
References .................................................................................................................................... 99
viii
List of Tables
ix
List of Figures
x
Figure 4-7. if statement restructuring to Normal Case Ordering .................................................. 34
Figure 4-8. Simplifying if statement using simple comparison .................................................... 34
Figure 4-9. Simplifying if statement using boolean function ....................................................... 34
Figure 4-10. An Example Replace Temp with Query Refactoring ............................................... 35
Figure 4-11. An Example of Extract Method Refactoring ............................................................ 35
Figure 4-12. An Example Rename Method Refactoring .............................................................. 36
Figure 4-13. Simplifying Long Methods using Extract Method Refactoring ............................... 36
Figure 5-1. Original UML Diagram of Threads in AutoSim ........................................................ 39
Figure 5-2. Original UML Diagram of AutoSim Client Threads ................................................. 39
Figure 5-3. Busy Waiting Loops in Main.cpp ............................................................................... 40
Figure 5-4. Sleep Methods to delay between Thread Calling ....................................................... 41
Figure 5-5. Sequence Diagram of GUIThread implementation in AutoSim Client...................... 42
Figure 5-6. MoveMethod Refactoring on the show methods ....................................................... 43
Figure 5-7. MoveMethod on main.cpp ......................................................................................... 43
Figure 5-8. AutoSim Server's Class Diagram ............................................................................... 44
Figure 5-9. AutoSim Server's Simulation Package ....................................................................... 44
Figure 5-10. Exception Handler's Message Sending from RakNetClient to QApplication .......... 46
Figure 5-11. Exception Handler of AutoSim Client ..................................................................... 46
Figure 6-1. Singleton Pattern ........................................................................................................ 48
Figure 6-2. ClientController class. .................................................................................... 49
Figure 6-3. The Fault location in the MessageList class ............................................................... 51
Figure 6-4. The Actual Fault Location .......................................................................................... 51
Figure 7-1 Simple Finite State Machine (FSM) Diagram. ............................................................ 61
Figure 7-2 FSM Implementation using Nested State Switch. ....................................................... 62
Figure 7-3 State Table of statechart on Figure 7-1 ....................................................................... 63
Figure 7-4 State Table Implementation ......................................................................................... 64
Figure 7-5. UML Diagram of State pattern ................................................................................... 65
Figure 7-6 A Piece of code that represents AutoSim Implementation .......................................... 67
Figure 7-7 Client Class.................................................................................................................. 69
Figure 7-8 A Piece of Original AutoSim Code ............................................................................. 70
Figure 7-9 Move Field Refactoring............................................................................................... 71
xi
Figure 7-10 UML Diagram of SubClasses after Extract Sub Class Refactoring .......................... 72
Figure 7-11 Extract Sub Class Refactoring ................................................................................... 72
Figure 7-12 Class diagram after Replace Data Value with Object Refactoring ........................... 73
Figure 7-13 Replace Data Value with Object Refactoring ........................................................... 73
Figure 7-14 Class Diagram after Add Method Refactoring .......................................................... 74
Figure 7-15 Add Method Refactoring ........................................................................................... 74
Figure 7-16 Class Diagram after Move Method Refactoring ....................................................... 75
Figure 7-17 Move Method Refactoring ........................................................................................ 75
Figure 7-18 AutoSim State Transition Diagram ........................................................................... 76
Figure 7-19 State Pattern of AutoSim's Server Application ......................................................... 77
Figure 7-20 FSM of Simulation States.......................................................................................... 77
Figure 7-21 State Pattern of Simulation's State............................................................................. 78
Figure 7-22 AutoSim Client's State Transition Diagram ............................................................. 78
Figure 7-23 State Pattern of AutoSim's Client State Diagram ...................................................... 79
Figure 8-1. BuildData Class Diagram ........................................................................................... 82
Figure 8-2 The MAP Collection of Graphic tag ........................................................................... 84
Figure 8-3 The First Extract Method Refactoring on fromXML function .................................... 86
Figure 8-4 The Second Extract Method Refactoring on fromXML function ............................... 87
Figure 8-5 Inline Method in fromXML function .......................................................................... 87
Figure 8-6 The Extract Method Refactoring on XMLExtractArrayData function ....................... 88
Figure 8-7 BuildData Class Diagram after ExtractMethod Refactoring ....................................... 89
Figure 8-8 Class Diagram after Extract Class Refactoring .......................................................... 93
Figure 8-9 BuildData class before and after Extract Class Refactoring .................................. 93
Figure 8-10 BuildDataCreator class .................................................................................... 94
xii
Chapter 1
Introduction
Economic benefit. Simulation is cost effective compare with the real world experiment
Support the system prediction. In the real life, we cannot stretch the timing to see the
future time. However modeling the environment using simulation allows us to predict the
future as the timing can be speed up.
Provides a Framework. Simulation can be used to resemble different types of
environments that provide an abstraction about the various possibilities. Thus simulation
can provides a framework.
Provides a model for Analysis. The real world problem is difficult to understand since
there are many factors that work together. Analyzing a particular problem need a model
that can give information about a particular issues without any other factors that influence
1
our perception about the system. The users are allowed to adjust parameters to see the
simulation behavior and the result can be used to model the real world environment.
Support safely. Simulation will provides a virtual world that support safety issues in the
real world. For instance, simulation can be employed to test the safely of product.
However automotive simulation also provides undesirable disadvantages particularly its fidelity
to the real world. This is an essential task of simulation to ensure its accuracy to imitate the real
world that is being studied.
2
Figure 1-2 Daimler-Benz Simulator[2]
In Europe the first driving simulator is developed by Volkswagen in the beginning of 70s and
later, iDOF simulator was produced in 1984. Additionally, the Swedish Road and Traffic
Research Institute started building VTI in 1984. What is more the driving simulators was built
some car companies and aerospace institution such as Daimler-Benz in 1985 [2], BMW, and
Katech and German Aerospace Institute (DLR) [1].
In Japan, research on driving simulator begun in 1960 by National Research Institute of Police
Science, Prince Motor Company and National Research Institute of Mechanical Engineering
Laboratory using analog computer and electronic circuits [4]. It was continued by Toyota using
3
Drum-type driving simulator. The more advance driving simulator later was introduced by
several car companies. These simulator includes Mazda driving simulator[5], Honda riding
simulator, and Mitsubishi Motor Flat-Belt driving simulator [4]. Currently, Mitsubishi Motor
has produced several driving simulators for driving training, rider training, helicopter, and train
[6].
4
1.3 Autonomous Driving
The outer space exploration brings human being to explore the universe using robots that can
works in the hostile environment. The exploration mission has been begun since 1960 in United
of Soviet Socialist Republic (USSR) by launching Korabl 4. After that, there are many efforts to
performs the similar exploration programs during the cold war era [8]. There are several
successful missions. For instance, in 1996, NASA launched the Mars Path finder named
Sojourner, the first semi-autonomous vehicle that rolls on Mars planet [9, 10]. It is controlled by
earth-based center. However, the successful of the mission has low rate. Between 1980-2000,
among ten mission programs, both countries have launched only two robot successfully[8].
5
Figure 1-7 Mörri, Autonomous Robot in Military-ELROB 2006 and 2008 [15]
The environment of AutoSim consists of several visualization objects (e.g. terrains and objects)
that represent the real world entities. The road terrains, for instance, are visualized based on the a
open map data retrieved from OpenStreetMap, a free wiki world map [10] [16]. The advantages
is that users can modify the map interactively using Java OpenStreetMap (JOSM) Editor [17].
Other objects are 3D visualization entities that are placed in the environment such as houses and
trees. Special object (e.g. traffic light) also available to perform autonomously desired task in a
changing environment.
The AutoSim software is build in based on the client-server model architecture. The server
provides the simulation data and the dynamic environment to the client through a network and
the client visualizes the environment and provides interface for user‟s interaction. Chapter 3 will
present the AutoSim software in detail including its library and development tools.
6
1.5 The Problem
AutoSim is an active research project in automotive simulation in the University of Western
Australia [9, 10, 18, 19]. The project is developed using C++ object oriented language. This
project developing activities include adding new features, debugging, fixing software defects,
and maintaining system. Hence the evolving software‟s quality is declining and increase the
software complexity. With an increasing complexity and decreasing reusability, the development
progress has been slower than what is expected. On the other hand High code understandability
and good software design makes the subsequent development easier.
Observation on the AutoSim projects shows that code understandability, a key aspect in software
development process to enhance a human-readable code, has been deteriorated. In respect to
code understandability, Martin Fowler said that “Any fool can write code that a computer can understand.
Good programmers write code that humans can understand” [20]. Thus high quality code provides a good
medium of communication for a collaborative software development team.
Additionally, AutoSim also suffer of bad design as a result of continuing writing code without
up-front design which is a notion of design debt, a metaphor of software complexity that refers
to a financial debt [21]. This design debt was accumulated because software developers wrote
code without considering design such that the cost of adding new feature, later on, become
bigger than writing code from scratch.
7
2. Software Design Quality. A good design in advances can avoid a high costly
development and rework. People believe that at the beginning of software development,
they have to plan for a good software design. In fact, a good planning on design does not
guarantee a perfect design without any defect. Refactoring is a complement to design by
restructuring the code to achieve a better design. This involves restructuring a software
design by modifying set of class structure that correspondent to restructuring software
design. Moreover, in extreme programming development, refactoring is employed to a
achieved a well design software from a instant code that is written without any up front
design.
In object oriented programming, refactoring is applied on the code and has impacts to several
levels of software entities: statement, class, and software design. Based on those implications,
the refactoring can be classified into the following types:
Furthermore, refactoring also gives many benefits to software development process. Refactoring
activities can be done concurrently with coding activities. Subsequently, these activities will
improve the software process by introducing good practice to the software activities. Moreover,
refactoring also increases software testability by removing high coupling code and providing a
good unit testing to the software product. Since the code becomes easy to understand, it provides
so called a self documenting code and increases the program comprehension.
1.7 Challenges
Provided a good solution for legacy code, refactoring also have various challenges in its
implementation as follows:
8
refactoring. However, in reality, the complex system with high coupling like AutoSim
has low testability which means no testing availability to help behaviors preservation.
2. Version Control System limitation. To record the code changing, AutoSim employs
subversion, an open source version control system, managing the code evolution.
However the current subversion system only provides a line by line code comparison that
does not records the semantic meaning of refactoring. Hence, sometimes, the refactoring
activities are recorded manually with limited help of subversion system.
3. Limited Refactoring tools for C++ also provides other challenges in the refactoring
process. Many supports in refactoring are come from high object-oriented programming
language such as java and smalltalk but not C++. In AutoSim, the refactoring is triggered
by code smelling activity, an intuitive ways to detect legacy code.
Next chapter present the motivation of refactoring and describe design pattern and some works
on refactoring. Chapter three provide some low level refactoring implementation common used
in AutoSim restructuring. Chapter four describes some issues on singleton pattern overuse in
AutoSim application and provides a mitigation strategies using refactoring. Chapter five ans six
present the refactoring to achieve state pattern and creational respectively. Chapter seven
introduce the program restructuring in multithreading application. The final chapter provides the
conclusion and future works of AutoSim especially in program refactoring.
9
Chapter 2
In the beginning of computer era, the experimental development of OS/360, Software Change
was primarily known as program growth dynamic [22, 23]. This investigation pins down the
starting point for understanding that the software flexibility can be used as a vehicle for
addressing the dynamic real life problem. A computer program can control the underlying
hardware which is provided with basic functionality to solve the contextual changing problem
encountered in our life. However, software flexibility also becomes potential future problems.
Those three parts of code of main.cpp is taken from different version on the repositories: version
873 (8 February 2008), 105 (25 August 2008), and 1101 (6 October 2008). The version 873
shows the initial code that supports three types of arguments namely –Worldfile, -StepPerSec,
and –AutoStart.
10
873 8 February 2008 1050 – 25 August 2008
int main(int argc, char *argv[] int main(int argc, char *argv[])
{
) ...
{ int i = 0;
... while(i < argc)
int i = 0; {
while(i < argc) if(!strcmp(argv[i], "-WorldFile"))
{ {
if(!strcmp(argv[i], "-WorldFile")) i++; δ1 σ1
{ params->worldFile = argv[i];
i++; CTRL->m_WorldFile = argv[i];
guiParams->worldFile = argv[i]; }
} else if(!strcmp(argv[i], "-StepsPerSec"))
else if(!strcmp(argv[i], "-StepsPerSec")) {
{ i++; δ2
i++; params->stepsPerSec =
guiParams->stepsPerSec = σ2
RSSTRING::intFromString(STRING(argv[i]));
}
RSSTRING::intFromString(STRING(argv[i])); else if(!strcmp(argv[i], "-windForce"))
} {
else if(!strcmp(argv[i], "-AutoStart")) i++;
{ params->windForce =
guiParams->autoStart = true; RSSTRING::intFromString(STRING(argv[i]));
} }
i++; else if(!strcmp(argv[i], "-AutoStart"))
} {
... params->autoStart = true;
} } δ3
i++;
}
...
}
1101 – 6 October 2008
void printUsage()
{
std::cout<<"AutoSimServer ..."<<endl
σ3 if(!strcmp(argv[i], "-WorldFile"))
<<endl {
<<"Example"<<endl i++;
<<endl params->worldFile = argv[i];
<<"AutoSimServer-v0.03.exe CTRL->m_WorldFile = argv[i];
..."<<endl }
<<endl else if(!strcmp(argv[i], "-StepsPerSec"))
<<"Description"<<endl {
<<endl i++;
<<"-AutoStart\tThis ..."<<endl params->stepsPerSec =
<<"-Help\t\tDisplay this ..."<<endl RSSTRING::intFromString(STRING(argv[i]));
<<"-StepsPerSec\tPerformance ..." }
<<"-WindForce\tSpecifies ..." else if(!strcmp(argv[i], "-windForce"))
<<"-WorldFile\tIndicates …."<<endl {
<<endl; i++;
} params->windForce =
RSSTRING::intFromString(STRING(argv[i]));
int main(int argc, char *argv[]) }
{ else if(!strcmp(argv[i], "-AutoStart"))
... {
int i = 0; params->autoStart = true; σ5
while(i < argc) σ4 }
{ else{ //Default case
if(!strcmp(argv[i],"-Help") || std::cout<<"Invalid Argument
!strcmp(argv[i],"-h")) Exiting.."<<endl;
{ printUsage();
printUsage(); return 0;
return 0; }
} i++;
}
...
}
Figure 2-1 A Motivation Examples
11
Later the program was evolving by adding new code to program (σ1,2 ) and change existing code
(δ1−3 ) in version 1050. Both addition σ1 and σ2 on the code is to send the argument value to the
controller class (CTRL) and to accommodate a new argument support for wind force ( -
windForce). Last, the software developer made the three changes (δ1−3 ) as a result of object
renaming from guiparams to params.
The program continues to evolve and make another argument addition as shown in version 1101.
It introduces two new arguments to support the –help (σ4 ) and invalid parameter (σ5 ). When the
invalid parameter is detected, the application will display the usage information using a new
printUsage function (σ3 ).
In the software development, the software will evolve to meet to the new requirements. For
instance, after two consecutive revisions, the main.cpp code become more complex and it
decrease the code understandability. Thus the main.cpp „s has deviated from its original goals as
a core process.
Software design is essential at least as a model not only for the software implementation (e.g.
software program, coding, etc) but also for software specification. It act as a bridge between the
software specification resulted from the requirement analysis and the implementation of the
software. The software design will depicts how the software implementation will fulfill the
software specification. For instance, we can examine the software design to determine wheter the
software design has deviate from the original blueprint. Moreover, a good software design will
make the implementation easier and lead to produce high quality software.
12
The origin of pattern is came from the architectural discipline which describe repeatable problem
and the core solution to that problem that enable us to reuse the solution again and again [25]. In
Software Engineering, design pattern catalog developed by gang of four help us to provides
pattern catalogs of recurring design in object-oriented system [26]. A more friendly references on
design pattern is available from Eric Freeman and Elisabeth Freeman which describe pattern
using visual example and program code [27].
Software design also important part in documenting the software product. It serves a visual
figure that describes the abstraction of system process that is easy to be understood. In the
software documentation, design pattern will serve as an object-oriented architectural style that
provides strategic reuse [28].
The result of his doctoral work produces three high-level refactorings: creating an abstract
superclass, subclassing, and simplifying and five set low level refactorings listed on the figure 2-
2. In addition to those refactorings, the seven program properties which are essential in behavior
preservation is discussed.
13
Creating a Program Entity creating an empty class
creating a member variable
creating a member function.
Deleting a Program Entity deleting an unreferenced class
deleting an unreferenced variable
deleting a set of member functions.
Changing a Program Entity changing a class name
changing a variable name
changing a member function name
changing the type of a set of variables and
functions
changing access control mode
adding a function argument
deleting a function argument
reordering function arguments
adding a function body
deleting a function body
convert an instance variable to a variable that
points to an instance
convert variable references to function calls
replacing statement list with function call
inlining (ie inline expanding) a function call
changing the superclass of a class
14
5. Compatible signatures in Member Function Redefinition. A inherited function in a
subclass must be compatible with the original function in the superclass. This
includes all attributes of the class.
6. Type-Safe Assignments. In the assignment operation, a left-hand variable must be
assigned by a type or a sub type of the variable type.
7. Semantically Equivalent references and Operations. The Program produced by
refactoring must preserve semantically equivalent references and operations.
In the University of Antwerpen, Belgium, refactoring research is carried out by Bart D. Buis. He
studies the impacts of the quality improvement after refactoring. Several software quality aspects
that have impacts after refactoring is discussed [35]:
15
2.3.4 Refactoring Tools
The first refactoring tool is to support in smalltalk programming language written by Don
Roberts et all [36]. This application provides a refactoring browser that is used to restructure
smalltalk program automatically.
To support refactoring in java program, Danny Dig writes the JavaRefactor plugin, the first
refactoring tool for java, in JEdit Integrated Development Environment [37]. It provides a
catalog for automated refactoring such as class, field, method, and package renaming and
PushDown and PullUp of methods and fields in an inheritance hierarchy.
Furthermore, XRefactory, an open source refactoring tools, is introduced for Emacs and XEMacs
users [38]. This tool provides refactoring for both C++ and java programming language. More
sophisticated refactoring tools, Refactor Pro is available for visual studio c++ produced by
DevExpress [39].
16
2.4 Automotive Simulation
The section presents related work on automotive simulator.
The Open Racing Car Simulator (TORCS) is a automotive simulator that consists of two types of
robots namely, computer robot and user defined robot which can be programmed in C++ [43].
Figure 2-3 shows the snapshot of TORCS.
17
Another simpler automotive simulator is provided by Robot Auto Racing Simulation (RARS).
RARS is developer for a programmer competition and for practitioners particularly in artificial
intelligent[45]. Figure 2-4 shows the screenshot of RARS.
Moreover, VAMOS is another automotive simulator that has just been developed to provides
physical simulation using C/C++ [46]. Additionally, there are some other automotive simulators
such as GRacer, a 3D Motor Sport Simulator developed by Takashi Matsuda[47], CarWorld, a
small driving simulator developed under GNU license[48], T1 Car Racing Simulator[49], and
VDrift[50].
18
Chapter 3
AutoSim Functionalities
Figure 3-1 Graphical User Interface of AutoSim Server with Loading Dialog
19
The progress dialog is determined by steps of loading in ClientWorldBuilder class. At the
beginning of the Load process the dialog shows five percents. Next the AutoSim server loads
the client‟s objects by execute methods: buildWorld, buildGraphic, buildPhysics,
buildObjects, buildTerrain that worth 10%, 30%, 50%, 70%, and 80% respectively. Thus
from the figure above we know that the AutoSim server has finished load all objects. After that
the AutoSim prepares the graphic manager and closes the dialog window.
20
information exchanges. The connection is handled by RakNetClient class that is control by the
state pattern. The connection process is also displayed in the progress dialog shown in figure 3-6.
21
3.2 AutoSim Structure Overview
AutoSim is an event-driven system which detects, consumes, and reacts to the coming of events
from user‟s input and timer event form the system. Time event is a special event that is generated
automatically by the system when certain time duration has been elapsed.
22
client and server transform the data into bit stream and send them through RakNet engine [51].
Thus the data communication between server and client application needs data conversion.
ControllerState
ClientController
UserProgram
DataLoader
23
ControllerState
Controller
GUI
1 1
DataLoader
25
CPPUnit provides a framework that can be used to generate a unit testing for testing automation.
The following code shows a piece of code for test case for StartParameter class. The
CPPUnit_ASSERT is an assert function provided by CPPUnit testing that determine the testing
process.
26
Chapter 4
A computer program, a set of instructions from a man to a computer, must be able to tell the
computer what to do. But it must also communicate its intents to other stakeholders especially
other software developers to ensure the sustainability of software evolution [60]. This aspect of
program quality is known as program comprehension or program understandability. We defined
the smallest unit of program comprehension as code readability.
This chapter begins with programming language overview: its features and its challenges
especially related to refactoring for program understandability. Section 4.2 presents the most
aspects of coding. Section 4.3 presents some code readability issues in AutoSim. Finally, we
discuss some low level refactoring to improve code readability and finished with discussion
some other refactoring techniques for code readability.
4.1 C++
C++ programming language is a high level programming language that supports the modular
programming paradigm. It is a subset of C but better then C in term of data abstraction, object
oriented programming, and generic programming. The name of C++ was coined by Rick
Mascitti that means an extension of C that have no attempt to remove previous features [61].
Some undesirable C++ features that hinder the refactoring activities are:
1. C compatibility. The compatibility of C++ provides support to previous super set such
that an old C programmer can gain the benefit using C++ especially for migration to C
program to C++ [62]. However the features compatibilities also make the program is
difficult to understand (e.g. preprocessor directive).
2. Pointer and Cast Operation. Pointer and Cast operation is an important feature of C++
to support polymorphism. For instance, using a pointer variable we are able to hold a
27
pointer to inheritance objects and use cast operation to perform type conversion between
super classes to sub classes. But they make the program difficult to understand. For
instance, the casting operation on the statement makes the code statement unnecessary
longer.
Steve states that experimental prototyping by writing a small chunk of code to realize a
model is general used to addressing the software design problem. The coding should be
minimum that only try to improve our limited design [40]. A more extreme approach is
namely emergent design, evolve a design using refactoring [20, 63]. Originally, the term
emergent design, a new approach in system engineering, is coined by Cavallo [64].
Emergent design considers the concept that from the existing code we can improve the
design and in some extension, it can improve the software architecture.
28
4.2.2 Program Comprehension
The aspects of program contain a broad spectrum quality ranging from its syntax to its
documentation. This chapter will present some aspects of code quality that is related to
understandability of program in statement level. Here are several aspects of program that makes
a program is easy to understand:
1. Simplicity. A simple program is a short program. It is clear from unimportant part that
influences the program understandability. For instance, many unnecessary temporary
variables reduce its simplicity.
2. Completeness. When a program is simple, it does not means that it replaces or removes
its actual specification. On the other hand the completeness of a program must be
maintained.
3. Clarity. Clarity means is that a programmer can understand the code at the first time
reading.
1. Code Clone
2. Unstructured Statement Organization (unclear Statement)
3. Long Statement
4. Semantic Meaning of Code
29
4.3.2 Unstructured Statement Organization
Statement organization defines the structure of a program. Several possible statement
organizations includes:
1. Statement Order
Strict Ordering Statements. By strict, we mean that the statements orders cannot
be changed. If the statements order is modified, the meaning of the statement is
different. Figure 4-1 shows an example of that have a specific order
Arbitrary Ordering Statements. On the other hand arbitrary ordering statement
allows us to arrange the statement in any ways. Although the arbitrary ordering
statement can be arranged in several ways, it has an impact on code readability,
performance, and maintainability [40]. Figure 4-2 shows a fragment of code with
arbitrary ordering statements
m_pMessageLoggerThread = NULL;
m_pNetworkThread = NULL;
m_pServerParameters = NULL;
m_pSimulation = NULL;
30
this looping is for loop which not only need no internal control statement but also easy to
understand since the loop set up is defined at the beginning of the loop.
m_pCalcOffset[0] =
(m_pCalcOffset[0]/m_pAreaSize[0])*
(m_pAreaSize[0]/m_heightDataPerArea -1);
m_pCalcOffset[49] =
(m_pCalcOffset[49]/m_pAreaSize[49])*
(m_pAreaSize[49]/m_heightDataPerArea -1);
m_pMainWindow-> ui.robotNameLineEdit->text().toAscii().data();
m_pRenderTargetCamera =
dynamic_cast<GraphicNode*>(
m_pRootGraphicNode->findNode(cameraName)
);
Figure 4-4. Long Statement examples
31
Our exploration of AutoSim found various types of long statement as follows (see figure 4-5):
AutoSim has a low understandability in statement level because it neglects the important of the
self-documenting program, which provides a meaningful identifier to software developer
including identifier name, declaration statement, and symbolic naming using enumeration.
Figure 4-6 show a comparison between two pieces of code which have the same purpose but
different semantic meaning.
... ...
if ( robotName.CompareTo(“camaro”) == 0) if ( robotName.isEqualsTo(“camaro”) )
… …
Figure 4-5. Semantic Meaning in Program
32
Introduce Return Object
int GraphicObject:getVirtualCameraTextureHeight()
{
Return m_Height;
}
int GraphicObject:getVirtualCameraTextureWidth()
{
Return m_width
}
class Dimension{
m_weight;
m_height;
public:
Dimension():
m_weight (0),
m_height(0){}
Dimension getVirtualCameraTextureSize(){
return new Dimension(m_width, m_height);
}
33
Simplifying Conditional Statement
Conditional statement that comprises some comparison statement can reduce program
comprehension. Simplifying the conditional statement can be done in various ways [40] [20].
The following lists present some possible strategies to simplify conditional statement:
34
Replace Temp with Query
Many temporary variables can reduce the program comprehension. To simplify a program with
many temporary variables, we can employ Replace Temp with Query refactoring (see figure 4-
11) [20].
robotNameLineEdit->setText(robotName.c_str()); robotNameLineEdit->setText(
pParams->getRobotName().c_str());
Figure 4-10. An Example Replace Temp with Query Refactoring
Extract Method
Extract methods is the simplest and powerful ways to simplify the long statement, duplicate
code, and complicate statement organization. It has been already known as the most common
refactoring activities [20, 30].
The following code shows the example of extract methods (see figure 4-12).
} int main(
{
...
ExtractParameter ();
...
}
Figure 4-11. An Example of Extract Method Refactoring
35
Rename Method
The purpose of rename method is to communicate its intent to the reader. Figure 4-13 shows an
example of Rename Method refactoring.
Long method calls caused by chaining methods class makes the program difficult to understand.
AutoSim have a lot of long method calls. Figure 4-14 shows the example you have chaining
methods calls that make the code difficult to comprehend. We can introduce an intermediate
method to improve code comprehension.
m_pMainWindow->
ui.robotNameLineEdit-> STRING MainWindow::getRobotName()
text().toAscii().data(); {
return ui.robotNameLineEdit->
text().toAscii().data();
}
m_pMainWindow->getRobotName();
In the AutoSim Client Application, ClientController class has responsibility to control and
manage the whole process of the client application. During the process, the controller stores the
status of the process in the enumerated data types as follows:
enum Status{
CREATED = 0,
GUI_LOADED = 1,
LOADING = 2,
LOADED = 3,
CONNECTED = 4,
RENDERING = 5,
USER_PROGRAM_LOADED = 6,
STOP_RENDERING = 7,
RENDERING_STOPPED = 8,
QUIT = 9
};
The code above show the status data types in the client application. It allows expressing the
status in the English language. By replacing the status using enumerations, the code readability is
36
increased. For instance, the code If (controlStatus = 0) can be replaced by with If
(controlStatus = CREATED).
4.5 Discussion
Refactoring at the statement level is the most basic and the most important refactoring. There are
many ways to perform low level refactoring to increase program comprehension introduced by
several refactoring books such as “Working Effectively with Legacy Code” [41], “Code
Complete” [40], and Refactoring: Improving the Design of Existing Code[20].
Our experiences on working with AutoSim show that refactoring at the statement level allows us
to works with the higher level of refactoring. Moreover in many situations, the low level
refactoring can be the preliminary steps in software restructuring activities, when high level
refactoring is obscure. These low level refactorings can lead to big refactoring for design that
will be discusses in the chapter 6 and chapter 7.
37
Chapter 5
Bart Jacob et all found that writing multithread application in object oriented programming is
difficult for two reasons: nonlocal nature of object and race condition [68]. By nonlocal nature of
object, Bart means that there is no explicit mechanism to show if an object is shared among
multiple threads. Moreover, the implementation of multithreading programming in C++ is
38
operation system dependent. It means that multithreading application should consider the
operating system‟s thread management.
This chapter explores the AutoSim that comprises various threads to organize the AutoSim‟s
resources. Section 5.2 presents our exploration on the software design of multithreading
management in AutoSim and its fundamental issues. Section 5.3 provides the software
restructuring on AutoSim to remove the unused thread in order to mitigate the central issues of
multithreading management. In Section 5.4 we define the result of our program restructuring
activities and finally, in section 5.5 we summary this chapter.
m_pGUIThread
m_pNetworkThread
Controller NetworkThread
m_pSimulationThread
SimulationThread
GUIThread
m_pGUIThread
m_pClientNetworkThread
UserProgramThread Controller ClientNetworkThread
m_pUserProgramThread
m_pSimulationThread
GraphicThread
39
Whereas AutoSim Client consists of four threads: a GUIThread, a ClientNetworkThread, a
GraphicThread, and a UserProgramThread. In AutoSim client, a ClientNetworkThread
establishes the connection to the server and a SimulationThread is replaced by GraphicThread
that visualizes the simulation object in 3D-Visualization. To manage these threads, AutoSim
client employs a ClientController class, a façade class that provides central services to
threads. Additionally, AutoSim Client also has a UserProgramThread that execute a
customizable user interface such as Qt user interface, a cross platform application and user
interface framework developed by Trolltech [55] or steering wheel joystick. The state class
diagram of the AutoSim Client classes diagram is shown in figure 5-2.
Our observation on software design and code about the multithreading implementation found
that current AutoSim has the following issues:
1. Idle main thread. Every application must have at least a main thread, which is the main
process that has a memory allocation provided by operation system. Both AutoSim server
and client also have main thread that handles the life of other child thread. However,
AutoSim server and client implement the unnecessary busy waiting looping after they
have executed all necessary threads at the beginning. Figure 5-3 shows busy waiting
loops of AutoSim.
Int main(...){
...
/* status != Exit */
while(CTRL->getSimulationStatus() != Controller::QUIT)
Sleep(100)
return 0;
}
40
As a matter of fact, running on slow computer, this assumption sometimes is broken and
causes the program termination since the simulation tries to read and write on the GUI.
Int main(...){
...
CTRL->loadGUI(params);
Sleep(1000);
CTRL->loadSimulation()
...
}
Having the above issues, we decide to replace the busy waiting of the main thread with user
interface of the GUIThread such that the number of threads is reduced and the application‟s
efficiency is increased. This replacement is essential since the nature of user interface which is a
central of application is the main thread. Hence user interface, the main thread of application,
41
manages threads execution. In other word, it means that the GUIThread‟s contents is moved to
main thread and all the main thread will be added to the controller.
Figure 5-5 shows the sequence diagram of AutoSim client along with a fragment code that
represent the user interface calls. Other calling includes various methods calling such as
simulation thread, network thread, and delay.
int argc = 0;
char **argv = 0;
loadGUI()
m_pQApplication =
m_GUIThread->Start()
new QApplication(argc, argv);
m_pMainWindow =
run new MainWindow(m_pMainWindowParams);
m_pMainWindow->show();
m_pQApplication->connect(
m_pQApplication,
Other Calling SIGNAL(lastWindowClosed()),
m_pMainWindow,
Other Calling SLOT(on_actionQuit_activated()));
The refactoring activities to remove the GUIThread can be divided into three steps as follows:
MoveMethod Refactoring moves the run function and replaces the loadGUI. Figure 5-6
shows that the content of run function replaces the loadGUI function of main.cpp.
42
main.cpp Controller GUIThread
m_pQApplication =
new QApplication(argc, argv);
loadGUI()
m_GUIThread->Start() m_pMainWindow =
new MainWindow(m_pMainWindowParams);
run m_pMainWindow->show();
m_pQApplication->connect(
m_pQApplication,
SIGNAL(lastWindowClosed()),
m_pMainWindow,
Other Calling SLOT(on_actionQuit_activated()));
loadGUI()
show
Other Calling
Other Calling
Other Calling
43
5.4 AutoSim’s Structure
This section presents the AutoSim‟s class structure after refactoring on MultiThreading and
refactoring for State Pattern (see chapter 6). Figure 5-8 shows the static class diagram of
AutoSim Server along with its ControlState, which is a state pattern to control the
application‟s state transition. The detail description about the ControlState is available on
section 6.5.1.
ControlState
ActivateSimulation()
ActivateNetwork()
RunNetwork()
RunSimulation()
StopControl()
ChangeState()
m_pControllerState
m_pNetworkThread
Controller NetworkThread
m_pSimulation
Simulation
SimulationState
Load()
Run()
Pause()
Stop()
toString()
ChangeState()
m_pSimulationState
m_pSimulationThread
Simulation SimulationThread
44
5.5 Impact after Multithreading Resructuring
We observe that simple multithreading restructuring have various impacts. Firstly, it solves the
issues mentioned on section 5.2. It is obvious that the main thread is used as part of graphical
user interface and the GUIThread is removed such that the performance is increased. In addition
to that we can improve the threads synchronization since the number of threads is reduced.
The AutoSim application particularly the server class structure allows us to develop the system
without worrying about the synchronization. For instance, we can eliminate the time delay
between GUI loading and Simulation loading because Simulation Loading is done by GUI that
has been loaded before that as part of main thread.
Furthermore, the new implementation enables us to add new loading progress dialog that is
called by the main thread during the loading time. Every loading progress is conveyed to the
dialog such that users can monitor the progress. Among several improvement achieved after the
multithreading restructuring, we choose exception handler features that will be discussed in the
next sub section.
Having mentioned the difficulty to implement exception handler in section 5.2, AutoSim Client
cannot send an exception message that happened within a thread. However, the new design of
threading management makes the possibilities to handle message to users.
45
RakNetClient HandlerRequest QHandleEvent QApplication
HandleRequest(p)
new
QEvent
PostEvent(QEvent)
QHandlerEvent(int EventType);
~QHandlerEvent(void);
};
46
This event, which is posted using QApplication, can be caught by MainWindows by redefining
customEvent. Figure 5-11 shows the code of the event handling which is part of the
mainwindow. The event caught is a custom event that is declare in QHandlerEvent with a unique
user defined number.
5.7 Summary
AutoSim is a multithreading application that has some discrepancies in threading
implementation. But, multithreading implementation is the important construction that built up
the fundamental architectural level of both AutoSim server and client that have many
independent processes. Simple refactoring that is performed by removing unnecessary thread
allows us to improve the next development in AutoSim application.
47
Chapter 6
This chapter discusses our experiences in refactoring singleton pattern overuse in AutoSim
project. It starts with the overview of singleton pattern (section 1) and continues with the
example of singleton (section 6.2). In section 6.3, the singleton overuses exist on the AutoSim
will be discussed: their motivations, impacts and consequences. The last two sections include
refactoring activities to mitigate the singleton overuse impacts and other possible mitigation
strategies.
class Singleton
Singleton {
Static member static Singleton instance;
variable public Singleton(){...}
static Singleton instance public:
Singleton() ...
static Singleton *getInstance()
{
static getInstance() Static member
return &instance;
operations() function }
};
48
creation can only be done using a public static member function getInstance. In the real world
application, singleton pattern is frequently employed in the context that a general services is
needed for the whole application. For example, a printer spooler object or database connection
object should be defined as singleton pattern because most part of application needs to access a
printer and database.
ClientController.h
#define CC ClientController::getInstance()
class ClientController : public Singleton<ClientController>
{
public:
...
};
Main.cpp ClientWorldBuilder.cpp
int main(int argc, char *argv[]) ...
{
CC->pParams = new StartParameters(); void
ClientWorldBuilder::buildGraphics(BuildData
int i = 1; *BD){
while(i < argc) ...
{ if(params->Fullscreen){
if(!strcmp(argv[i], "-WorldFile")) ...
{ }
i++; else {
CC->pParams->worldfile = argv[i]; params->WindowId =
CC->m_WorldFile = argv[i]; CC->getIrrlichtWindowID();
} params->WindowSize.Width=
... CC->getIrrlichtWindowWidth();
} params->WindowSize.Height =
CC->loadGUI(CC->pParams); CC->getIrrlichtWindowHeight();
}
if(CC->pParams->starttype == 1) ...
CC->loadWorld(); }
else if(CC->pParams->starttype == 2)
{ ...
CC->loadWorld();
CC->startNetwork();
CC->startGraphics();
CC->startUserProgram();
}
}
ClientUserProgramAPI.cpp MainWindow.cpp
namespace ClientUserProgramAPI ...
{ void MainWindow::on_actionLoad_activated(){
int getImageHeight(){ CC->loadWorld(pQProgressDlg);
return ...
CC->getVirtualCameraTextureHeight(); }
} void MainWindow::on_actionRun_activated(){
int getImageWidth(){ CC->startAllThreads();
return }
CC->getVirtualCameraTextureWidth();
} void MainWindow::runSimulationAutomatically()
... {
void unlockImage(){ if (CC->m_pParams->getAutoStart()){
CC->unlockVirtualCameraTexture(); on_actionLoad_activated();
} CC->startAllThreads();
} }
}
Figure 6-2. ClientController class.
49
6.2 Example of Singleton in AutoSim
The ClientController class is a controller class that manages the interaction of objects in the
AutoSim client. As such, this class is defined as singleton pattern that exists during the
application lifetime (figure 6-2). In this example, the predecessor directive CC is used to get an
instance of this class (figure 6-2). The example of CC usage can be found in code with bold font.
This section will present the result of our finding on singleton usage in AutoSim, its impacts and
consequences. An example of debugging activities that caused by singleton overuse is also
discussed.
50
6.3.2 An Example: Debugging Experience in Singleton Overuse Design
This section discusses an example from our experience in debugging a system with singleton
overuse. Because the system occasionally cannot be started, we conduct debugging to find the
faulty location. Based on the debugging tools, the fault is located in loading module. Further
investigation found that the AutoSim Server calls the MessageList operator <<, which access
the graphical user interface (GUI) which has not been initialize (see figure 6-3). But, the
information about faulty location does not help us to find the cause since the failure is happened
occasionally and our code review shows that the GUI has been initialized before. After a few
week of searching for the exact location, we found nothing and the debugging activities is
postponed.
Later, during refactoring activities, the fault location is found in the main.cpp, which is located
far away from the loading module. The cause is software developer‟s assumption about the
thread‟s communication. It is assumed that the GUI loading process faster for 1 second than
Simulation loading process (see Figure 6-4).
CTRL->loadGUI(pStartParam);
Sleep(1000);
CTRL->loadSimulation();
51
6.3.3 Consequences of Singleton Overuse
The singleton overuse occurs when a software developer begins to employ singleton pattern so
deeply into the software design that it starting lording the entire design. Thus the global
accessibilities are found at any places of the software. The Singletonitis has several bad
consequences:
1. Re-entrant Code Problem. The code that over use singleton pattern has many ways to be
accessed. In multithreading application, the singleton is possible to be shared among different
process [42]. In this situation, the effort to keep the meaning of global singleton is tested.
And when this global singleton is used, it is difficult to detect whether it is has been modified
or accessed in some other place in the program. Thus it makes the program is difficult to
understand [41].
2. Low Reusability. Software engineering is different from other kinds of engineering. The
major is different lies on its flexibilities strike any other engineering disciplines that enable
software to modified easily. A industrial report shows that a systematic reuse can obtain cost
and time savings in some company such as AT&T, Brooklyn Union Gas, ericsson, GTE,
Hewlett-Packard, IBM, Motorola, NEC, and Toshiba [71]. Its flexibility can be employed
effectively by reusing the existing software system. To achieve good reusability, a software
system must be designed in such a way it provides abstraction by hiding the detail of the
implementation. However, the system with singleton overuse works in the opposite
directions. By introduction global access, the software system suffers from high
dependencies between classes relationships which focus on the detail of the software design
rather that the abstraction.
3. Low Readability. After software design is created, it is implemented by coding in the
particular programming language. Although having the same software design, two software
developer can produces totally different code. Coding is a creative implementation of
software developer based on their personal styles and taste. Several issues in the software
implementation such as indentation, coding line length, commenting styles in not important
to be standardized in to a common rules or standard [72]. However good code readabilities
are essential in software development. Failing to provide high readabilities can put the
software project in risk of failure. It becomes difficult to be changed, maintenanced,
debugged, and developed.
52
4. Low Testability. Human is not perfect and so is the software made by human. Because we are
not perfect, the software testing is essential to find the software defects. Knowing that no
silver bullet for software defect and get rid of our confidence about the perfect software is a
fundamental requirement for software testing [73, 74]. Realizing about the nature of software
and the need of software testing does not imply that software testing can be conduct easily. In
fact, software testability determines the degree of unit-test and system-test of a system can be
done. When software suffers from high coupling caused by singleton overuse, it becomes
dependent to many classes and thus the unit testing is difficult to be performed.
5. Difficult in Debugging. Debugging is important to find and fix the defect when the software
specification is violated. However when the software has many singletonitis (singleton
addition), debugging can be frustrated as it can jump from one class to another class in
unstructured way. Moreover, the effective debugging technique available is only an
“inserting print statements” since the debugging tools cannot be employed in unmanaged
multithreading [75].
6. Unsafe Message Sharing among Thread. AutoSim is multithreading and client server
application that need to share data. The data communication employed is global variable
using singleton.
53
6.4.1 Example
Suppose we want to remove singleton pattern from the Graphics class from our software design.
Firstly we need to explore any classes that use the graphic class. In the belowed example, we
found there are three classes namely, GraphicThread, ClientWorldBuilder, and
ClientController class has defined a Graphics class using singleton. The finding classes need to
be considered for the next step to determine in which class we might store our reference to
graphic.
public:
};
...
};
54
1. Show Method
Change the Singleton‟s constructor accessibility from private to public
Graphics Graphics
-Graphics() +Graphics()
Graphics(){
... public:
} Graphics(){
public: ...
}
static Graphics* getInstance(){
If (m_pGraphics == NULL) static Graphics* getInstance(){
m_pGraphics = new Graphics() If (m_pGraphics == NULL)
return m_pGraphics; m_pGraphics = new Graphics()
} return m_pGraphics;
... }
}; ...
};
2. Add Field.
Among many classes in our system, we have to select which class that should store
our references to the singleton class. The class selected should have some criteria
such as a Façade class or the parent class.
Suppose we choose ClientController and we need to declare a reference variable
that store the Graphic Object (σ1 ) and initiate on the init function (σ2 ).
ClientController ClientController
-m_Graphics
55
3. Add Parameter Object
Each call in classes that access the singleton class must be replaced. As a rule of
thumb, the replacement strategies depend on the frequency of the calls made. If the
number of singleton calling is few, the temporary parameter object can be used. By
temporary parameter object, we mean the parameter object that pass to a method and
is used temporality within a method. If the number of singleton calling is many, it is
preferable to store the parameter object passed to the method.
... ...
private: private:
... ...
}; };
Other consideration is when an object is passed as a parameter object. In the
temporary parameter object, an object is passed when the method is called. However
when an object references is stored as member of a class, the object can be passed in
various time. Most are passed on the beginning of class creation through its
constructor/. Some which do not exist at that time, can be passed as soon as possible
through a parameter object, when a method of the class is called.
int Run()
{
τ1 GraphicThread(Graphics *pGraphics):
m_pGraphic(pGraphics)
GRAPHICS->run(); {
} }
...
}; int Run()
{
pGraphic->run();
}
...
};
56
4. Replace Singleton Pattern with Class
The last treatment of singleton pattern overuse is to replace with an ordinary class. It
was done by deleting static member variable that hold its object and deleting static
member method that get its own instance. Moreover, the preprocessor directive that
represents the static member methods must also be removed.
...
public: public:
...
};
Kent beck report that after removing singleton overuse, the following result is achieved [42]:
6.6 Conclusion
Software design pattern allows us to communicate the design to other stakeholders during
software development activities. Singleton pattern also helps us to understand a software design.
However singleton overuse that is implemented incorrectly makes the system difficult to be
maintained and reused. This chapter has discussed the singleton pattern and singleton overuse
mitigation.
However we have not removed some singleton overuse in AutoSim application due to high
coupling problem. Future work, particularly related to singleton overuse, should be considered.
58
Chapter 7
In this chapter, we focus on the techniques for modeling and implementing simulation‟s state.
Modeling simulation‟s states transition will provides semantic information about the behavior of
the system, its elements, its interactions, and its transitions that represent the system‟s properties
changes.
Firstly, the finite state machine, a famous behavior model, will be discussed to provide a basic
theoretical aspect of this simulation model. After that several possible code implementations of
finite state machine in programming language is discussed. Finally, our implementation of
refactoring to state pattern to improve the current AutoSim design will be outlined.
The need of notation to represent the system‟s state transition is addressed by automata theory,
the theoretical computing discipline that study about a graph representation [76]. In automate
59
theory, finite state machine (FSM) provides a conceptual model describes as the number of states
and their transitions.
Statecharts helps software developers by documenting system behavior and allows them to
reason and to validate the systems‟ completeness and correctness. By completeness and
correctness, we mean that a system can be views as a holistic and complete system which needs
to be validated. In addition to that, a behavior model also acts as a communication tools for
stakeholders during the whole system development process [28].
Furthermore, statechart provides an effective modeling diagram that help us in modeling a state-
driven system by reducing the behavioral complexity [77]. In other word, it means that statechart
is suitable for modeling a dynamic aspect of a system that employed highly state-dependent [78].
Statechart notation consists of collection of states and input events that generate the transition
between states. A state is depicted as a circular or rectangular shape that determines the
recognizable situation of entity or system at a given time. An event is an atomic trigger that
happens at a particular time. Examples of events are Gas Pedal pressed or the break pressed. In
statechart, the transition depends not only to input event but also to the current state. Sometime,
the event has no impact to the current state and the system remains in the same state. For
instance, the gas pedal does not move a car when the current state is on engine off.
60
/ Initialize / Terminate
/ Stop Stopped
/ Run
/ Stop
/ Run
Paused Running
/ Pause
An event can be divided into two types: input events and special events called timer. Timer event
is event that happen every particular defined elapsed time (e.g. 10ms, 1s, etc). A timer that has an
elapsed time s = 10 second will send a trigger message after ten seconds elapses time has been
finished after started, the events is triggered automatically by the timer.
Figure 7-1 shows an example of simple statechart with three states: Stopped, Paused and
Running. Moreover, the system also has two special states: Start state (black circle) and End
state (black circle with line). The Start state determines the beginning of the statechart before
the system is started. After the system started, the state changes to the Stopped state immediately.
Whereas the End state is when the system is turn off. The above system also consists of transition
with the trigger name that determines the event that causes the transition. For instance when
currently the system is in the Stopped state and the Run Event is called or triggers, the system‟s
state move the Running state.
61
also represent the statechart or FSM. Moreover, Gamma et all also introduce more sophisticated
approach by applying so called state pattern where every states are represented as objects and the
transition is done by changing the a parent object hold an instance of particular object that
represent the current object [26]. The summary of the implementation of state diagram will
discuss in the following sub sections along with their advantages and disadvantages.
enum CLIENTSTATE_TYPE{
STOPPED,
PAUSED,
RUNNING
};
CLIENTSTATE_TYPE ClientStatus;
...
Switch(ClientStatus){
case STOPPED:
...
ClientStatus = RUNNING
break;
case PAUSED:
... // Client Load Function
ClientStatus = RUNNING
break;
case RUNNING:
...
break;
}
Figure 7-2 FSM Implementation using Nested State Switch.
FSM implementation using nested switch statement or if-statement has the following
benefit:
- Easy to implement and simple
- Program Comprehension achieves using enumeration.
- Efficient memory usage.
62
However the nested switch implementation also has some disadvantages as follows:
- Low Program Comprehension in complex FSM. Suppose an FSM consist of many nested
states, the code become difficult to understand because the code implementation consists
of many switch statement.
- No separation of FSM implementation and other Implementations. The nested switch
statement is part of the program which consists of not only FSM implementation but also
other system‟s implementation such as data structures implementation. Thus the code
become complex and also decrease modularity of the system.
- No type safety Support. Even though enumeration increase the program comprehension.
In C++ enumeration is treated as integer value which provides no type safety in
assignment operation.
- Low reusability. Variable implementation does not provides any modularity to the system
that increase the reusability of object-oriented system.
Transitions
63
void init(State *s){
...
setState(s, LOADING);
};
struct StateTable{
Transision *trans_table;
Int State;
Int n_state;
Int n_trans;
};
- State table provides a good structure to represent states and their transition.
- Better Type safety. The state is changed using a function which has two parameters:
current state and the event that generate transition.
- Better program comprehension by hiding detail implementation in table and function.
State and transition is implemented separately using variable and functions that stored in
state table.
64
However the state table implementation also has some disadvantages as follows:
- Medium Memory usage (compare with variable usage). The table size equals to the
multiplication between number of states and the number of transitions.
- The availability of Empty Data. When the number of transition varies among different
states, there will be a lot of empty data stored in the table since each row have the same
number of column.
- Low reusability. When a new state or a new transition is introduced. A original array size
must be change and the code must added by new function to represent a new transition.
- No type safety. The implementation of state is represented using integer value which can
hold any integer number.
- Intertwined Event Implementation. The if-statement sometimes must be used to check
several events that have the same name from various states. For example: both Paused
State and Running State have the same function Stop, the if-statement must be
employed to differentiate between those two events. Other solution, we have to define
different function name for those states.
Client m_status
Run() State
Stop() Run()
Pause() Stop()
Pause()
ChangeState()
m_state->Run
65
Figure 7-5 shows the class diagram of the state pattern. A client is a program or class that
declares a variable to store a particular state. Each state represent as an object such as Paused,
Stopped or Running. When an event occurs, an instance of class that represents the system state
will call an appropriate function and move to the next state.
1. Separated Event Implementation. The event implementation is unique for each state even
the name of the event is the same. For instance, the Paused and Running State inherits
Run function with different implementation.
2. High reusability. Each state is realized using a class. When a new state is introduced, we
can be derived from the abstract parent class.
3. Good Type Safety. Using class representation, a variable that hold the system‟s state is
type safe only to possible instance of inheritance class. Moreover this implementation
provide transition protection by specify different event. For instance when the current
state is Stopped and the function stop is triggered, the system will ignore the event.
4. Provide Abstraction for Communication among stakeholder. The design pattern can be
used to communicate the system behavior‟s implementation to stakeholder during the
system development.
However the state pattern implementation also has some disadvantages as follows:
1. Complicate Implementation. For a system with simple state transition, state pattern
provides complicated implementation.
2. High memory usage. Each state is realized using a class along with its implementation
and parent data.
66
void Controller::loadSimulation()
Class Controller:...
{
{
...
α2
... if( ... && m_SimulationStatus == GUI_LOADED)
Public: {
m_SimulationStatus = LOADING;
enum ... β2
{ m_SimulationStatus = LOADED;
INITIALIZED = 1, }
GUI_LOADED = 2,
LOADING = 3,
σ1 }
The figure 7-6 shows a piece of the code that implements the state transition. However the
FSM‟s is not clearly represents the state transition. For instance the enumeration represents
several different level of state such as state for the simulation and states for the application itself.
Thus the system becomes complicated.
The software developer declares the possible state using enumeration (σ1 ) and the application‟s
state is defined using a member variable, m_SimulationStatus with integer type (σ2 ). Before
using it, this variable is initialized with default state of the system, INITIALIZED (σ3 ).
Moreover software developer provides several functions that are called when an event is
triggered. When a function is called, first it validates the current state stored in the variable using
67
if statement (α1−6 ). When the current state is valid, the program continues by running the next
process and finished the process by change the current state to the next state (β1−6 ).
a. User Interface State. From the user‟s point of view, the graphical user interface should
represent the visible current state of system. For instance, when the system is stopped, the
stop button should be disabled.
b. Public Accessibility. The simulation‟s state variable, m_SimulationStatus, has public
accessibilities. It means that the software developer allows variable modification in any
classes within the system. The following question is difficult to answer: When does
AutoSim change from a state to another state? What object is responsible to change the
system‟s state? What happened to the system when the system‟s state is changed?
c. Exception Handling. During the integration testing, the system‟s stability is unpredictable
caused by unhandled exception during the state transition. When an exception is trigger,
the error is not caught. However exception handling cannot be realized since it is
occurred in various places across the system modules. What makes worse, the Qt
architecture does not allow displaying an error message dialog at any code
implementation except at main thread. Hence the state transition implementation will
influence on implementing exception handling.
d. State Transition Design. The application‟s state transition is difficult to understand. Front
enumeration declaration, we found nine states (σ1 ). Moreover, the state transitions are
complicate as a result of duplication and unclear intents. AutoSim should provide an
abstraction to represent the current nine states and their transitions for better program
comprehension.
68
Table 7-1 Refactoring Steps for State Pattern
Steps. Refactoring Name Description
Step 1 Add new Empty Class Add new empty class to represent the state of context class
Step 2 Move Field Move the enumeration type to the new class
Step 3 Extract Sub Class Extract sub class based on the new
Step 4 Replace Data Value With Object Replace the enumeration data value to the type safe object
Step 5 Add Methods Add new method (ChangeState) on both context class and
new Class for State Pattern
Step 6 Move Method Move the state transition implementation from the context
class to the appropriate inheritance class.
7.4.1 Example
Consider an example of Client‟s state implementation in figure 7-8 and its corresponding class
diagram in figure 7-7.
Client
+Run()
+Stop()
+Pause()
Figure 7-7 Client Class
This class is the code implementation of the statechart in figure 7-1, which consist of three event
functions namely, Run, Stop, and Pause.
69
class Client{
enum state_type{
STOPPED,
RUNNING,
PAUSED
};
state_type currentState;
public:
Client(){
currentState = STOPPED;
}
void run(){
if (currentState == STOPPED){
cout << "STOPPED to RUNNING" << endl;
currentState = RUNNING;
}
}
void stop(){
if (currentState == RUNNING){
cout << "RUNNING to STOPPED" << endl;
currentState = STOPPED;
}
else if ( currentState == PAUSED){
cout << "PAUSED to STOPPED" << endl;
currentState = STOPPED;
}
}
void pause(){
if (currentState == RUNNING){
cout << "RUNNING to PAUSED" << endl;
currentState = PAUSED;
}
}
};
Figure 7-8 A Piece of Original AutoSim Code
1. Add new Empty Class. Create a new class with name ClientState and Compile. This
class will be used as a parent of the state pattern.
class ClientState{
};
70
2. Move Field. Move Enumeration Type to new class and change all assignment to
enumeration to ClientState enumeration.
class ClientState{
public:
enum state_type{
STOPPED,
RUNNING,
PAUSED
};
};
public: public:
Client(){ Client(){
currentState = STOPPED; currentState = ClientState::STOPPED;
} }
71
3. Extract Sub Class. Create new inheritance singleton classes (class
ClientStateStopped, ClientStatePaused, and ClientStateRunning, are extends
from ClientState) that represent every possible states.
ClientState
Figure 7-10 UML Diagram of SubClasses after Extract Sub Class Refactoring
72
4. Replace Data Value With Object. Change the enumeration data value (unsafe-type) in
context class to object type (safe-type)
Client
currentState ClientState
+Run()
+Stop()
+Pause()
public: public:
Client(){ Client(){
currentState = ClientState::STOPPED; currentState = ClientStateStopped::Instance();
} }
73
5. Add Methods. Add new method both on Client and ClientState
Client
currentState ClientState
+Run()
+Stop()
+ChangeState(in pClient, in pState)
+Pause()
+ChangeState(in pState)
class ClientState{
...
public:
...
protected:
void ChangeState(Client* pClient, ClientState *pState){
pClient->ChangeState(pState);
}
};
class Client{
...
public:
...
74
6. Add event function both on the ClientState and the corresponding Inheritance class
Client ClientState
currentState
+Run() +ChangeState(in pClient, in pState)
+Stop() +run()
+Pause() +stop()
+ChangeState(in pState) +pause()
class ClientState{
class ClientState{ public:
... virtual void run(){}
public: ...
... };
};
75
7.5 AutoSim’s StateCharts
In previous section, the refactoring process is discussed. After several refactoring activities is
carried out to both AutoSim Server and AutoSim Client, this section summary the result of
refactoring to state patterns.
/ Initialize / Terminate
/ Stop / ActivateSimulation
ControlInActive
ControlSimulationRunning ControlSimulationActive
/ ActivateNetwork
/ RunSimulation
ControlNetworkActive
ControlNetworkRunning
/ RunNetwork
76
ControlState
ActivateSimulation()
ActivateNetwork()
RunNetwork()
RunSimulation()
StopControl()
toString()
ChangeState()
Figure 7-19 shows the state design pattern of the application statechart that have five states
represents as inheritance classes.
/ Initialize
/ Terminate
Stopped
/ Load
/ Stop / Stop
Loaded
/ Run
/ Run
Running Paused
/ Pause
Figure 7-20 shows a statechart that represent the simulation state transition. Initially, the state is
Stopped. When the Load button is pressed, the Load event is occurs and the state transitions to
Loaded. When users press the run button, the state Loaded transitions to Running State. From
state Running, a user can pause the simulation that makes the simulation‟s state transitions to
77
Paused or a user can stop the simulation that makes the state transitions to Stopped. When the
application is closed, the whole application will be terminated.
Simulation
Simulation() SimulationState
Load() m_pSimulationState Load()
Run() Run()
Pause() Pause()
Stop() Stop()
ChangeState() ChangeState()
run()
This simulation statechart is realized using state pattern shown in figure 7-21. The key idea of
this implementation is the SimulationState that provides an abstraction for the Simulation‟s
state stored in the m_pSimulationState.
/ Initialize
/ Terminate
/ Stop
ClientStopped
/ Load
ClientLoaded
ClientUILoaded
/ Stop
/ Connect
/ LoadUI
/ ReConnect
ClientRakNetConnected
ClientIrrllitchRendering
/ StartNetworkThread
/ StartGraphicThread
ClientRakNetEstablihed
78
the Load button is pressed, the Load event is occurs and the state transitions to ClientLoaded.
When users press the run button, the state Loaded transitions to ClientRakNetConnected State.
Before entering the ClientRaknetConnected, the system will validate the network connection.
If the client cannot connect to the server, it will ask the user whether the reconnection process
should be established. The user can stop the connection process and change to stop or continue
connection process.
ClientController ClientState
loadWorld() Load()
quitApplication() -m_pClientState Connect()
Connect() StartNetworkThread()
startGraphics() StartGraphicThread()
startNetwork() 1 * LoadUI()
startUserProgram() Stop()
ChangeState() ChangeState()
ClientLoaded ClientRakNetEstablished
ClientUILoaded
Instance() Instance()
Stop()
Connect() StartGraphicThread()
Instance()
toString() toString()
79
Some state implementation on AutoSim has not been finished. For instance how to replay the
loading state. By replay, we mean that it is possible to reload the simulation objects. Our attempt
to learn about the loading process has not finished such that the state transition has not been
implemented fully particularly in which we cannot change from state to other state for a
particular reason.
As a matter of fact, our works shows that the state pattern has benefit in increasing the software
desing quality. We have provided the underlying design to implement state transition of the
application that need to be extended in the future. For instance, we can improve the state
transition of AutoSim by including the reloading simulation or replaying running simulation.
80
Chapter 8
This chapter will present some practical aspect of refactoring to achieve good creational pattern
which is used to manage the objects creation. In addition, an example on creating a builder
pattern, a type of creational pattern that has responsibility for constructing objects, will be
discussed using the real code found in the AutoSim application.
8.1 Overview
AutoSim application has a lot of simulation objects that represent various entities of simulation
or parts of entity such as physical objects, graphics object, and networking objects. Objects, in
object oriented programming, play an important role to represent the entities that build up an
application system. In addition, these objects can be an abstract and a concrete object that
represents the real-world entity.
Creational pattern is a set of pattern that is used to organize the object creation in an application.
Applying creational pattern also allows us to create a flexible application especially in objects
creation process: when it is created, and how it is created [26].
81
world file, an XML file type, is employed to document simulation world properties (e.g. graphic
engine, screen default value, etc).
Using XML to store the information about the simulation properties offers several benefits:
To retrieve the data element from the XML file, AutoSim employs the BuildData class. In this
class, the data retrieval is done by reading, extracting, and storing XML data to data collection.
BuildData
+m_StringMap : map<std::string,std::string>
+m_DoubleMap : map<std::string,double>
+m_MultDoubleMap : map
+m_MultStringMap : map
#m_type : string
#m_name : string
+BuildData(in h : TiXmlHandle*)
+toXML()
+getType() : string &
+getName() : string &
+getDouble(in tagName : string) : double
+getDouble(in tagName : string, in attribName : string) : double
+getString(in tagName : string) : string &
+getString(in tagName : string, in attribName : string) : string &
+containsDouble(in tagName : string) : bool
+containsDoubleArray(in tagName : string) : bool
+containsString(in tagName : string) : bool
+containsStringArray(in tagName : string) : bool
#fromXML(in h : TiXmlHandle*)
#getAttributeCount(in e : TiXmlElement*) : int
Figure 8-1. BuildData Class Diagram
Furthermore, Buildata class also employs four MAP data collections namely, m_StringMap,
m_DoubleMap, m_MultDoubleMap, and m_MultStringMap to store various data type. Both
82
m_StringMap and m_DoubleMap are collections that are used to save the data element with
double and string values respectively. Additionally, the variable m_MultDoubleMap and
m_MultStringMap are collection that used to save a collection of type double and type string
data value respectively. In other word, both m_MultDoubleMap and m_MultStringMap are a
collection of collection.
The advantage of MAP data collection is not only that this allows us to store data elements, it also
provides searching capabilities to retrieve data element using a string index. A client class of
BuildData, given a string index value as function‟s parameter, can use the MAP searching
services by calling either getDouble or getString function, which is used to get single data
element. If the data consists of a collection of data elements (e.g. a collection of double type or a
collection of string type value), a client class must provide two parameters, the string index for
the collection and the string index for a particular element of the collection.
In additional to retrieve data, BuildData also provide fromXML functions to extract the data
elements from XML file and store them to the Map collection. The fromXML function is essential
function that maps the reading data to the MAP collection.
<Graphics name="graphics">
<Driver type="DIRECT3D9" />
<FullscreenResolution width="1280.0" height="800.0" />
<Fullscreen value="false" />
<AntiAlias value="false" />
<Stencilbuffer value ="false" />
<Vsync value="false" />
<Detail value="100.0" />
<Debug type="OFF" />
<RenderTargetTexture width="512.0" height="512.0"/>
</Graphics>
This element consists of seven elements with their attributes. Some of the elements has only a
value. For instance, Driver Elements has only an attribute type with value DIRECT3D9. Some
others have several attributes such as FullscreenResolution has two attributes width and height.
If the element consist of multiple attributes, the elements and its attributes is stored into
83
collection of collection MAP. Those data values are stored to appropriate data types, double and
string data type.
84
Table 8-1 Refactoring Steps for Builder Pattern
Steps. Refactoring Name Description
Step 1 Extract Method Decompose long methods into small piece of methods that
is easy to understand and provides self documenting.
Step 2 Replace Hard-Coded with Enumeration Replace hard-coded statement can give us semantic
meaning to a variable
Step 3 Extract Class Decompose big class that have many functions into
several classes
Step 4 Introduce Builder Pattern Replace the object construction with a Builder Pattern
which is a simple creation pattern.
BuildData consist of fromXML function which will be the first target of refactoring because this
function is long and have a lot of logical statement that is difficult to understand. By employing
Extract Method several times, we can decompose this function into several simple functions.
Figure 8-3 shows the fragment of fromXML function that is used to extract the XML data values
and stored them into collections. Refactoring this function must consider two types variable
unmodified variable and modified variable
85
void BuildData::fromXML(TiXmlHandle *h) void BuildData::fromXML(TiXmlHandle *h)
{ {
... for ( ... ) // For Each Element of XML
for (...) // For Each Element of XML {
{ int ac = getAttributeCount(pE);
// count the number of attribute of an if ( ac == 1 )
element XMLExtractSingleData(pE);
int ac = getAttributeCount(pE); else if ( ac > 1 )
if ( ac == 1 ) // an attributes found XMLExtractArrayData(pE);
{ else
double d; {
if (...) { cerr << "tag doesn't contain
... information" << endl;
} else { }
... }
} }
}
else if ( ac > 1 ) // more than an
attributes void
{ BuildData::XMLExtractSingleData(TiXmlElement
... *pE)
if (...) { {
... double d;
for ( ... ) if ( ... ) {
{ ...
... } else {
} ...
} else { }
... }
for (...)
{
... void
} BuildData::XMLExtractArrayData(TiXmlElement
} *pE)
} {
else double d;
{ if ( ... ) {
... ...
} for (...)
} {
} ...
}
} else {
...
for (...)
{
...
}
}
}
The Extract Method Refactoring is done by extracting the content of if-statement that is used to
extract xml data value for a data value and a collection of data values. Figure 8-3 shows the side-
by-side the code before and after the first Extract Method.
86
The next Extract Method can be seen in figure 8-4.
BuildData::BuildData(TiXmlHandle *h)
BuildData::BuildData(TiXmlHandle *h) {
{ for ( ... ) // For Each Element of XML
fromXML (pE); {
} XMLExtraction(...);
}
}
void BuildData:: fromXML (TiXmlHandle *h)
{
for ( ... ) // For Each Element of XML
{
XMLExtraction(...);
}
}
87
void void
BuildData::XMLExtractArrayData(TiXmlElement BuildData::XMLExtractArrayData(TiXmlElement
*pE) *pE)
{ {
double d; double d;
if ( /* is Array of Double */ ) { if ( /* is Array of Double */ ) {
... XMLGetArrayDouble(pE);
for ( /* Each Array of double Element */ ) } else {
{ XMLGetArrayString(pE);
... }
} }
} else {
... void BuildData::XMLGetArrayDouble(TiXMLElement
for (/* Each Array of string Element */ ) *pE)
{ {
... for (/* Each Array of double Element */ )
} {
} ...
} }
}
void BuildData::XMLGetArrayString(pE)
{
for (/* Each Array of string Element */ )
{
...
}
}
Figure 8-6 The Extract Method Refactoring on XMLExtractArrayData function
At this point we have a code that is simpler since each part of function has already defined in
such as way to have clear intents. We continue this refactoring until each function in the class
become relative small. The figure 8-7 shows the growing number of function after the
ExtractMethod finished.
88
BuildData
m_StringMapData
m_DoubleMapData
m_DoubleArrayMapData
m_StringArrayMapData
m_type
m_name
BuildData()
getType()
getName()
getDouble()
getDouble()
getString()
getString()
containsDouble()
containsDoubleArray()
containsString()
containsStringArray()
XMLExtraction()
XMLExtractSingleData()
XMLExtractArrayData()
getElementSize()
doubleSetData()
stringSetData()
isGetNumberValueTo()
XMLGetArrayDouble()
XMLGetArrayString()
Figure 8-7 BuildData Class Diagram after ExtractMethod Refactoring
However some piece of code still difficult to understand as the result of hard-coded program that
needs to be restructured. The next steps involve some effort to add semantic meaning by
replacing hard-coded with enumeration.
1. Add Enumeration to the BuildData class to represent three data type for collection for
Single data type (DMT_SINGLE), Collection data type (DMT_MULTIPLE), and undefined data
type (DMT_UNKNOWN).
class BuildData
{
...
private:
enum DMT_DATATYPE{
DMT_UNKNOWN,
DMT_SINGLE,
DMT_MULTIPLE
};
...
};
89
After providing enumeration, we need to change the getAttributesCount function to
return the enumeration data type, temporary variable, and we also need to change the
getAttributes Function.
90
3. ExtractMethods
4. Rename Method
91
At this point, we already have a piece of code that has better semantic meaning. This code has
several advantages as follows:
One of the disadvantages is the performance decreasing. Performance is decrease because of a lot
of calling on methods. On the other hand, refactoring indeed make the software slow during the
refactoring, but refactoring makes the software easier to optimized later because the program is
easy to understand and program optimization is easy to be done [20].
Refactoring also deals with organizing the coding into good design. Thus the decomposition
activities must be changed its direction from simplifying the coding into organizing the coding
toward good design which is simple. There are several refactoring catalog can be used to
organizing the coding such as extract class, pull up methods Pull Up constructor Body, and
providing abstraction.
We choose Extract Class refactoring to organize the BuildData class into several classes that
have clear intends. The result is shown in figure 8-8. These four classes, StringMapData,
StringArrayMapData, DoubleMapData, and DoubleArrayMapData, is corresponse to those four
member Map datatype of BuildData class, m_StringMap, m_StringArrayMap, m_DoubleMap,
and m_DoubleArrayMap. Also some methods in BuildData can be simplified and eliminated.
For instance four methods of BuildData, stringSetData, doubleSetData,
XMLGetArrayDouble, XMLGetArrayString can be pull to the wrapper class (see figure 8-9).
92
BuildData
StringMapData m_StringMapData
m_DoubleMapData
m_StringMap
m_DoubleArrayMapData
getString() m_StringArrayMapData DoubleArrayMapData
setData() m_type
containsString() m_DoubleArrayMap
m_name
getIteratorStart() BuildData() getDouble()
getIteratorEnd() getType() setData()
getName() containsDoubleArray()
getDouble() getIteratorStart()
getDouble() getIteratorEnd()
getString()
getString()
containsDouble()
containsDoubleArray() StringArrayMapData
DoubleMapData containsString()
containsStringArray() m_StringArrayMap
m_DoubleMap
getElementType() getString()
getDouble() getAttributeCount() setData()
setData() XMLExtraction() containsString()
containsDouble() XMLExtractSingleData() getIteratorStart()
XMLExtractArrayData() getIteratorEnd()
isGetNumberValueTo()
getElementSize()
Figure 8-9 BuildData class before and after Extract Class Refactoring
93
8.3.4 Introduce BuildDataCreator
When a Client Class needs to create the BuildData object, it has to call the constructor of the
particular XML elements. For instance, It want to create a BuildData object for Graphics Data
then it has to call a BuildData constructor and pass the appropriate XML element as parameter
that is appropriate to Graphics. Here is the piece of code:
new BuildData(m_pWorld->getTiXMLHandle("Graphics"));
Now suppose a client class needs an array of BuildData Object, it has to call the following
statements:
To simplify the creational process, we wrap the BuildData class using the BuildDataCreator
class. This class responsible to construct a complex objects. Figure 8-10 shows the
BuildDataCreator implementation. This class helps us to create an abstraction in creating
BuildData.
BuildDataCreator
VECTOR<BuildData *>* ObjectsBuildDataVector =
-m_pWorld : XMLFileLoader *
new VECTOR<BuildData *>();
+BuildDataCreator(in pWorld : XMLFileLoader*)
+createBDGraphics() : BuildData *
TiXmlHandle *hSection =
+createBDPhysics() : BuildData * m_pWorld->getTiXMLHandle("Objects");
+createBDObjects() : vector<BuildData*> * for (TiXmlElement *epElem =
+createBDTerrain() : BuildData * hSection->FirstChildElement().ToElement();
epElem != 0;
epElem = epElem->NextSiblingElement() )
ObjectsBuildDataVector->push_back(
new BuildData(
new TiXmlHandle(epElem)));
return ObjectsBuildDataVector;
94
8.4 Discussion
1. Replace data structure to store the XML data such that improve the searching
performance. This also includes the replacement on string comparison in current MAP
searching with other optimal searching strategies.
2. Replace how the data is retrieved. The current implementation does not change how the
client of BuildData retrieves data. Suppose we can change how to retrieve data directly
to data structure, it would simplify and increase performance.
3. Introduce other creational class, a BuildDataCreator class, that provides an abstraction
to the BuildData creation.
95
Chapter 9
Conclusion
1. It adds some new graphical user interface features to the AutoSim Clients such as
dashboard, gear number, loading progress, and connection progress.
2. It introduces the automatic code documentation generation using doxygen [57].
3. It introduces the unit testing for testing automation.
4. It introduces exception handler to the AutoSim client particularly to handle the
networking failure. By implementing state pattern on the AutoSim, we can handle any
exceptions thrown.
5. It identifies some important problems in AutoSim project especially in software design
and program comprehension. Most of the fundamental issues of AutoSim are the
software design that hinders the software development.
6. It shows how to perform refactoring to improve the software design. We provide a real
world example of refactoring activities on the AutoSim.
7. Our experiences in refactoring produce several refactoring catalog. This refactoring
catalog includes: Refactoring to State Pattern and Refactoring to introduce type-safe
value.
96
9.2 Lesson Learned
The following list shows some lesson learned from our refactoring activities:
1. Refactoring is difficult to be performed and costly. Given a complicated and legacy code
such as AutoSim. Design is hard, design in object oriented in harder [30]. Refactoring
that has a goal of good software design is the hardest. It has many challenges. The nature
of C++ and the absent of the refactoring reduce the efficiency of refactoring activities.
2. Refactoring is step by step activities. Our experiences show that step-by-step activities of
refactoring will work well. On the other hand, dramatic refactoring will not work. The
behavior of system becomes difficult to be maintained. If the system is too complex to be
understood, it is better for us to start with small step using low level refactoring. Only if
we are really sure about how to perform a big refactoring, we can perform the high level
refactoring directly.
3. Refactoring is continuous activities to improve the software design. Sometimes it is
difficult to determine the absolute design good of refactoring. However by continues
work on small step on refactoring enable us to, at some point when the code shows the
possible design solution, to determine what good design is.
4. Refactoring is an active code review. By active, we mean that refactoring can help us to
understand how the system works. The traditional approach of code review is time costly
and ineffective because the program comprehension is low.
1. Our activities of refactoring for good software design especially to reduce the singleton
overuse which has not finished should be part of concern in the development of AutoSim.
The singleton overuse mitigation is the fundamental issues to achieve design with high
cohesion and low coupling.
2. Some state transition implementation on AutoSim is not finished. For instance how to
replay the loading state. By replay, we mean that it is possible to reload the simulation
object. Our attempt to learn about the loading process has not finished such that the state
97
transition has not been implemented fully. However some fundamental state transition
has been introduced for further works.
3. The multithreading implementation can produce race condition. The locking mechanism
has not been implemented to ensure the safe multithreading implementation
4. Tools to automate the refactoring are needed to improve the efficiency and the
effectiveness.
5. The refactoring on the Graphic objects and other data structure has not been performed.
Refactoring in these part will allows us to improve the state transition discusses in item
number 2 and also allow us to improves the AutoSim‟s performance.
98
References
99
18. P.S. Ruud, “Evaluation of a Vision-based Driver Assistance System in Simulation,” School
of Electrical, Electronic, and Computer Eng., The Univ. of Western Australia, Perth, 2008.
19. N. Dike, “Physics Simulation for an Automotive Simulator,” School of Electrical,
Electronic, and Computer Eng., The Univ. of Western Australia, Perth, 2008.
20. M. Fowler, Refactoring:Improving The Design of Existing Code, Addison Wesley 1999.
21. DesignDebt, “Design Debt,” 2004; http://c2.com/cgi/wiki?DesignDebt.
22. M.L. Meir and F.R. Juan, “Software Evolution and Software Evolution Processes,” Ann.
Softw. Eng., vol. 14, no. 1-4, 2002, pp. 275-309;
23. H.B. Keith, et al., “Software maintenance and evolution: a roadmap,” Proc. Proceedings of
the Conference on The Future of Software Engineering, ACM, 2000.
24. J. Krauskopf, “Elemental Concerns (Software Design),” Potentials, IEEE, vol. 9, no. 1,
1990, pp. 13-15;
25. C. Alexander, et al., A Pattern Language: Towns, Buildings, Construction (Center for
Environmental Structure Series), {Oxford University Press}, 1978.
26. R.H. Erich Gamma, Ralph Johnson, John Vlissides, Design Pattern Elements of Reusable
Object-Oriented Software, Addison Wesley, 1995.
27. E. Freeman, et al., Head First Design Patterns, O'Reilly, 2004.
28. C. Paul, et al., Documenting Software Architectures: Views and Beyond, Pearson
Education, 2002, p. 512.
29. B.R. Donald, Practical Analysis for Refactoring, University of Illinois at Urbana-
Champaign, 1999.
30. F.O. William, “Refactoring object-oriented frameworks,” University of Illinois at Urbana-
Champaign, 1992.
31. T. Mens, et al., “Formalizing refactorings with graph transformations,” Journal of software
maintenance and evolution, vol. 17, no. 4, 2005, pp. 247-276;
32. T. Lance and B. Don, “Evolving Object-Oriented Designs with Refactorings,” Automated
Software Engg., vol. 8, no. 1, 2001, pp. 89-120;
33. G. Alejandra, “Program refactoring in the presence of preprocessor directives,” University
of Illinois at Urbana-Champaign, 2005.
34. D. Danny and J. Ralph, “Automated upgrading of component-based applications,” Proc.
Companion to the 21st ACM SIGPLAN symposium on Object-oriented programming
systems, languages, and applications, ACM, 2006.
35. B. Bart Du, “A study of quality improvements by refactoring,” Universiteit Antwerpen
(Belgium), 2006.
36. R. Don, et al., “A refactoring tool for Smalltalk,” Theor. Pract. Object Syst., vol. 3, no. 4,
1997, pp. 253-263;
37. D. Danny, “JavaRefactor,” 2002; http://plugins.jedit.org/plugins/?JavaRefactor.
38. “xrefactory,” http://www.xref.sk/xrefactory/main.html.
39. Devexpress, “Refactor! Pro,” http://www.devexpress.com/Products/Visual_Studio_Add-
in/Refactoring/.
100
40. M. Steve, Code Complete, Second Edition, Microsoft Press, 2004.
41. M. Feathers, Working Effectively with Legacy Code, Prentice Hall PTR, 2004.
42. K. Joshua, Refactoring to Patterns, Addison Wesley, 2004.
43. TORCS, “Welcome on The TORCS Racing Board,” http://www.berniw.org/trb/index.php.
44. TORCS, “About TORCS,”
http://torcs.sourceforge.net/index.php?name=Sections&op=viewarticle&artid=1.
45. RARS, “Robot Auto Racing Simulator,” http://rars.sourceforge.net/.
46. VAMOS, “About VAMOS,” http://vamos.sourceforge.net/about.html.
47. T. Matsuda, “GRacer - 3D Motor Sports Simulator,” 2002; http://gracer.sourceforge.net/.
48. CarWorld, “Car World,” http://carworld.sourceforge.net/.
49. T1, “T1 Car Racing Simulation,” 2003; http://t1-crs.sourceforge.net/.
50. VDrift, “Welcome to VDrift,” 2009; http://vdrift.net/.
51. RakNet, “RakNet Library,” http://www.jenkinssoftware.com/.
52. Irrlicht, “Irrlicht Graphics Engine,” http://irrlicht.sourceforge.net/.
53. B. Jasmin and S. Mark, C++ GUI Programming with Qt 4, Prentice Hall PTR, 2006.
54. A. Boeing, “Evaluation of real-time physics simulation systems,” School of Electrical,
Electronic and Computer Engineering, the Univ. of Western Australia, 2007.
55. Trolltech, “Qt - A cross-platform application and UI framework,”
http://www.qtsoftware.com/.
56. Y.B. Lee Thomason, Andrew Ellerton “TinyXml Documentation,” 2006;
http://www.grinninglizard.com/tinyxmldocs/index.html.
57. D.V. Heesch, “Doxygen,” 2008-12-12; http://www.stack.nl/~dimitri/doxygen/.
58. cppunit, “cppunit,” 2008; http://cppunit.sourceforge.net.
59. S. King, “Useful enhancements for Visual Studio .NET,” 2003;
http://www.codeproject.com/KB/macros/kingstools.aspx.
60. Fred P. Brooks, Jr., “The Mythical Man-Month (20th Anniversary Edition) by Frederi,”
UNIX review, vol. 14, no. 1, 1996, pp. 66;
61. B. Stroustrup, The C++ Programming Language (Special 3rd Edition), Addison-Wesley
Professional, 2000.
62. F.O. William, “Refactoring C++ Programs,” Lucent Technologies/Bell Labs, 1999.
63. M. Stephens, “Emergent Design vs Early Prototyping,” 2003;
http://www.softwarereality.com/design/early_prototyping.jsp.
64. D. Cavallo, “Emergent design and learning environments: building on indigenous
konwledge,” IBM Syst. J., vol. 39, no. 3-4, 2000, pp. 768-781;
65. H. Yoshiki, et al., “A metric-based approach to identifying refactoring opportunities for
merging code clones in a Java software system,” J. Softw. Maint. Evol., vol. 20, no. 6,
2008, pp. 435-461;
66. H. Leiserson C.E. and Prokop, “A Minicourse on Multithreaded Programming,”
Unpublished, 1998;
101
67. H.C. Richard and T. Kuo-Chung, Modern Multithreading: Implementing, Testing, and
Debugging Multithreaded Java and C++/Pthreads/Win32 Programs, Wiley-Interscience,
2005.
68. J. Bart, et al., “A programming model for concurrent object-oriented programs,” ACM
Trans. Program. Lang. Syst., vol. 31, no. 1, 2008, pp. 1-48;
69. “Debug: Widgets must be created in the GUI-Thread,” 2007; http://lists.trolltech.com/qt-
interest/2007-10/thread00643-0.html.
70. S.T. Andrew, Modern Operating Systems, Prentice Hall Press, 2007, p. 1104.
71. I. Jacobson, Griss, Martin L., Jonsson, P., Software reuse: Architecture, process, and
organization for business success, Addison Wesley Longman, 1997.
72. A.A. Herb Sutter, C++ Coding Standards 101 Rules, Guidleines, and Best Practices,
Addison Wesley, 2007.
73. F.P. Brooks, Jr., “NO SILVER BULLET: ESSENCE AND ACCIDENTS OF SOFTWARE
ENGINEERING,” Computer, vol. 20, no. 4, 1987, pp. 10-19;
74. M.W. Gerald, Perfect Software: And Other Illusions about Testing, Dorset House
Publishing Co., Inc., 2008, p. 200.
75. L. Henry, “The debugging scandal and what to do about it,” Communications of the ACM,
vol. 40, no. 4, 1997, pp. 26;
76. I.C. Daniel, Introduction to computer theory, John Wiley & Sons, Inc., 1986, p. 823.
77. D. Bruce Powel, Doing hard time: developing real-time systems with UML, objects,
frameworks, and patterns, Addison-Wesley Longman Publishing Co., Inc., 1999, p. 749.
78. G. Hassan, Designing Concurrent, Distributed, and Real-Time Applications with Uml,
Addison-Wesley Longman Publishing Co., Inc., 2000, p. 816.
102