Sunday, May 23, 2010

Lugaru - Part 5

In my previous post (Lugaru - Part 4) the first problem I identified was the role and responsibility of the Weapons class. Namely, a single instance of Weapons represented 30 weapons when it should only represent one. The refactoring exercise to correct this started off as a philosophical one, but ended up being VERY beneficial. I'm very happy I did this before tackling the implementation details of Weapons. Here are the major steps I took.
  1. Renamed Weapons to Weapon.
  2. Globals.cpp holds the global instantion of Weapons. It went from this:
Weapons weapons;
to this:
const unsigned int max_weaponinstances = 20;
Weapon weapons[max_weaponinstances];
unsigned int numweapons;
The max_weaponinstances constant comes from Weapons.h.
  1. With max_weaponinstances moved out of Weapons.h, all of the Weapons' attributes that were arrays become single instances. This is because the class is no longer maintaining the state of multiple weapons, just one. There were 44 places this had to be done.
  2. The Weapons class has four class operations - a constructor, destructor, and two others. One called "doStuff" that updates the game state of all the weapons. The other is called "draw" which pushes the weapon illustration down the graphics rendering pipeline. At the top of these two operations are for-loops that iterate over all the weapons in use (stored in numweapons). Those are gone. Instead, they now appear in GameDraw.cpp.
    There were 823 instances of referencing the loop counters in Weapon.cpp
  3. Classes that are dependent on weapons have a slightly different syntax. As an example, in Person.cpp it used to read:
  4. if(weapons.type[weaponids[weaponactive]]==knife) ...
    but now reads:
    if(weapons[weaponids[weaponactive]].type==knife) ...
    I find the new way much more readable since it puts the weapon attribute closed to the thing its being compared to.
  5. Weapons used to contain texture information. In the original design, these would only be registered with OpenGL once. In the new design I didn't want 50 weapons registering the same textures 50 times. To get around this, I made the texture id's global, (*GASP*). I rationalized that refactoring is about going from bad to better, and this let me move on quickly. I have no intention of leaving it this way long term.
Overall, I think this left the code MUCH more readable and improved some design aspects of Lugaru weapons. Next up will be getting some unstanding on the Weapons implementation.

Tuesday, May 18, 2010

Lugaru - Part 4.1

As a quick addendum to Part 4, I realize that enumerations can't be used for every constant since enum values can only be integer types. The gravity constant example I used in the previous post would need to be represented as a const float.

Also, for further reading on this, I'd point you to Scott Meyer's "Effective C++ Third Edition" Item 2, "Prefer consts, enums, and inlines to #defines"

And for you eager beavers that want to start reading on the polymorphic weapon heirarchy, check out "Refactoring - Improving the Design of Existing Code" by Martin Fowler. Specifically, the section on Switch Statements in chapter 3 "Bad Smells in Code" and "Replace Type Code with Subclasses" in Chapter 8.

Monday, May 17, 2010

Lugaru - Part 4

I'm excited to announce that by my fourth post on Lugaru, I have doubled my subscribers! Now in addition to my sister, I have the creator of Lugaru following. Hopefully my mother will subscribe and triple my readership in a single month...

Well, after spending a weekend tinkering with the code, I finally have a running version of Lugaru for Windows. Having a running application will allow me to do two things:
  1. Experience Lugaru as a player with the benefit of stopping the game any any point I choose to look at the game's state in code.
  2. Verify any changes I make don't cause unintended consequences in the game. Remember, refactoring is about improving the design of software without changing its outward functionality.
After poking around, I've fallen in love with the file containing the game's logic of weapons. In the CodeCity, the yellow building below is the "Weapons" class.



Why start with weapons? Well, think about how you can take a human being and decompose it into mind, body, and soul. You can then decompose the body into systems (nervous, digestive, circulatory, etc). Decompose circulatory to heart, arteries, veins... all the way down to the point of cells and molecules and atoms. Object Oriented programming does the same thing - takes a complex problem and breaks into into manageable pieces while also defining the interactions between those pieces. If you were going to redo the human body (lawl) you'd either want to start by identifying problems at the macro- or micro- level. "Weapons" to me is the micro of Lugaru.

Okay, so enough intro to programming. Let's dive in to Weapons...

Unfortunately, we break our necks because we hit the shallows! Let's talk about the file name "Weapons." It's named that because it contains the class "Weapons."
Design Smell #1: Class name is plural

A golden rule of OO programming is that classes represent a single representation of something. If you need multiples of that something, you instantiate multiple objects of that class. As it stands, a single instance of "Weapons" handles 30 weapon objects. When we get further into the code, we'll see the issues that creates.

Code Smell #1: Favoring #defines for constants

Some quantities in a game never change, for example the downward pull of gravity as 9.81. That quantity could be reproduced all over the game's files. If you want to change that to a more precise number or change it from metric to imperial units, however, you'd have to go hunting for every single place you typed "9.81". Heaven help you if you over-look a place! That's why you use a constant. A constant says, "I am defining this word to represent this quantity." You can then use that word all over your game, and if you need to change the quantity down the road, you only have to change it in one place, the word doesn't change!

In C++ there are multiple ways to create a constant. The Wolfire team chose to use #defines.
#define max_weapons 30
#define max_weaponinstances 20

#define knife 1
#define sword 2
#define staff 3
Using #defines for constants are not good for several reasons. First, a #define is a pre-processor directive. It's a very low-level command that literally replaces every instance of the token with the quantity before processing the file. If something about the quantity causing a compile error, there's no way for the compiler to acknowledge the #define macro. Let's pretend a clumsy programmer fat-fingered some extra characters into the knife macro:
#define knife 1dkf
The next time the program was compiled, he'd get a slew of errors (I got 145 when I tried it.) The first three errors I got were against the following line of code:
if(type==knife)
and the errors were:
  1. syntax error: 'bad suffix on number' [ed. I see no number here]
  2. syntax error: missing ')' before identifier 'dkf' [ed. I see no dkf here]
  3. syntax error: ')' [ed. I don't even know what this means!]
Yes, I realize the IDE you're developing in might give you some tips, but there are other problems with this approach. Second, #defines do not offer compile-time type checking - a big feature of C++. Since #defines are token replacements, the compiler has no problem with the following:
int weapon_type = max_weaponinstances;
weapon_type = rabbittype;
weapon_type = tracheotomy;
All of which are macros in Lugaru that are associated with integers, none of which are associated with weapon types. This, coincidentally is why using
static const int knife = 1;
Is better than a #define but still has problems. That's why I like enumerations. They allow you to group constants and get compile-time type checking. The weapon constants we saw above are re-written as:
enum Weapon_type
{
knife = 1,
sword = 2,
staff = 3
};

And that means the 'type' attribute in the Weapons class can go from an integer to a Weapon_type. That gives a reader a much clearer idea about what the valid values of 'type' are.

Of course, the penultimate solution is to replace these type codes with polymorphic classes, but refactoring is about going from 'bad' to 'better' one step at a time (as opposed to 'bad' to 'perfect' in one giant leap.) Are there better ways to define constants? What advantages do the alternatives have over my proposal?

Thursday, May 13, 2010

Lugaru - Part 3

Several months ago I was introduced to CodeCity by Richard Wettel. In his words:
CodeCity is an integrated environment for software analysis, in which software systems are visualized as interactive, navigable 3D cities. The classes are represented as buildings in the city, while the packages are depicted as the districts in which the buildings reside. The visible properties of the city artifacts depict a set of chosen software metrics, as in the polymetric views of CodeCrawler.
It's been a fun little program for visualizing applications. Here is the code city for Lugaru, (I added the class names to the two largest classes!)
The length and width of the buildings are scaled according to the number of attributes in the class. The height is scaled according to the number of operations. I don't have the application available to me as of this writing, but I seem to recall the Person class having ~250 attributes to give you a sense of scale.

So the question is where to start. Some would say start at the highest level class, some would say start with the 800-pound gorilla in the application (i.e. "Person").

According to the paper in my previous post, before any code changes start, I should have test cases in place to ensure that the behavior before the refactoring is the same afterward. How am I going to test this thing?! And before testing, I've got to get the thing running. I'm curious if it's working out of the box for anyone else. Wolfire IRC says no.

Lugaru - Part 2

So before I jump into Lugaru code, I feel like I need to make sure the foundation is laid for what I'm doing. I intend to refactor portions of Lugaru in order to increase the ease of extending it. For those unfamiliar with refactoring, here is a paper I wrote with Mark Ward for a class we took in the spring on OO Analysis and Design.

A Framework for Effective Refactoring
Abstract
Refactoring is a method of applying a series of small transformations to existing code—without affecting its external behavior—in order to make the code as a
whole more understandable and thus more maintainable and less error-prone. The decision to refactor can be controversial—especially to management—given that resources are being expended for reasons other than adding revenue-generating functionality. Our position is that periodic refactoring is an effective means to improve the long-term viability of a software system by ensuring that the code remains fresh and readily adaptable and extensible to changes in requirements or the addition of new functionality. As such, refactoring makes sense from both a technical and a managerial perspective. We briefly introduce the topic of refactoring and discuss opposing viewpoints, and we then propose a five-step framework defining the high-level process that we believe is essential to ensure successful refactoring. We conclude with two case studies to illustrate the application of the five-step framework.

1. Introduction

Software systems evolve over time as requirements change and new features are added. During this period of evolution, the quality of the code can degrade as changes are made that the original design may not have foreseen and thus may not accommodate cleanly. Other times changes are made under schedule pressure without time to consider design impacts on maintainability, extensibility, testability, and other quality considerations. Such code can become difficult to understand, increasing the likelihood of injecting defects during future updates. Even the most carefully-conceived initial system designs are susceptible to these problems as the system evolves in unforeseen ways. Just as the highest-quality cars require tune-ups, so too do the best software systems. The process for “software tune-ups” is known as “refactoring.”
Refactoring is a method of applying a series of small transformations to existing code—without affecting its external behavior—in order to improve the qualitative characteristics of the design. In doing so the code as a whole becomes more understandable and thus more maintainable and less error-prone.

2. Why Refactor?

Refactoring asserts that the design of a software system is not a single event [1]. An engineer that regularly refactors his code is continuously reassessing the design of the system and asking if it is still has acceptable characteristics of quality software (e.g. “Can I easily extend the system to include next month’s feature list?”). When software no longer has those levels of quality, it is wise to revisit the design of the software.
When software is not refactored, those classes with design issues become more change-prone [4]. As a result, they can create bottlenecks in development (since multiple developers will need to modify the same class) and the risk of error injection increases.

3. When to Refactor

Fowler [1] does not recommend scheduling time to refactor. It’s something you do “all the time in little bursts.” He also argues that “not having enough time” is usually a sign that you need to refactor; the reason you don’t have enough time is likely because the code is not as maintainable or extensible as it should be, causing your current effort to take longer than it should.
In addition to code smells, other indicators have been proposed to help drive the decision to refactor. One such indicator is change smells [3]. Change smells are not visible in the code, but are detected by analyzing change dependencies mined from the software’s change history to predict areas that would benefit from refactoring.
Another proposed indicator is architectural smells [6]. This technique is intended to complement existing techniques identified for addressing code smells by looking for “high-impact” (i.e., high benefit) architecture-related refactoring opportunities based on “architectural violations.”
The authors of Code Complete remind us that, “The number of refactorings that would be beneficial to any specific program is essentially infinite” [7]. Consider the following guidelines when deciding which refactorings are most important:
  • Modules that are difficult to read
  • Modules with complex conditional logic
  • Modules that are error-prone
  • High-complexity modules
4. When Not to Refactor
There are times, however, when refactoring is not a prudent course of action. One instance is when the software becomes so bug-ridden that it should be rewritten rather than reorganized. Fowler suggests working through this by encapsulating the components of the system and then examining each one to see if it needs to be rewritten.
Another inopportune moment for refactoring is near an impending deadline. Recall that the motivation for refactoring is to increase quality characteristics without changing functionality. It serves no purpose to do this right before the system is shipped. This isn’t to be confused with “not having time to refactor” which could be an indication that a lot of time and energy is being exerted to further a bad design.
Other situations that would prevent you from refactoring would be if the software is tied to components outside the engineer’s control. If the external interfaces are solidified with a sub-contractor or company data-base, the extent to which a refactoring can occur can be limited [8].

5. Opposing Viewpoints

Many references are made to refactoring being a controversial topic, yet there is surprisingly little formally-published literature offering a defense of opposing viewpoints – perhaps because most of the published work tends to be academic in nature, focusing on the technical merits rather than management considerations, where much of the controversy lies. Discussion of dissenting opinions can more readily be found in web-published articles and online discussion forums, however.
While not practical to address every criticism of refactoring that we found, we will briefly acknowledge several and present our viewpoint on the discussion.
  1. Managers believe developers should be adding features, not reworking old code [10]. It is easy to understand how refactoring can be a hard sell to management. A manager is concerned with trying to get their product delivered within schedule and budgetary constraints. Most projects overrun one or both of these constraints. Especially on a project that is projected to be late or over budget, refactoring can seem like a non-value-added task since time is being spent but no new revenue-generating features are being added to show for it. We have already discussed that there are times when refactoring may not be not appropriate, such as when a deadline is looming. However, for managers who frown on refactoring at any time in the project’s lifecycle, perhaps Martin Fowler offered the best suggestion: don’t even tell your manager that you are refactoring [1]. While certainly a controversial suggestion, his argument is that software developers are professionals who want to build effective software as rapidly as they can. Refactoring helps you develop faster, therefore it can just be integrated as part of the development process and not viewed as a separate activity for which you need to request specific approval from your management.
  2. Refactoring is nothing more than an act of “beautification” [9]. While in a sense this is partially true, the chosen term clearly implies a disdain toward refactoring. Similar – and harsher – criticisms suggest that refactoring is a “waste of resources and a get out of jail free card for incompetent developers” [11], and “basically a programmer’s ego trip and nothing else” [5]. Ouch. These criticisms seem to be based on the premise that “there is not much point doing afterwards what can be done from the start” [9]. We would argue that no one has suggested that code should initially be written poorly and later “beautified.” However, management pressures often force developers to release code as soon as it works rather than allowing time to optimize it “from the start” for understandability and maintainability [11]. Furthermore, ongoing updates to the code after the initial release are likely to have a deleterious effect over time—regardless of how well the code was initially written—that at some point must be dealt with through refactoring in order to keep the code understandable and maintainable.
  3. Any code change is an opportunity for error injection [9]. This is absolutely correct. However, the purpose of having a complete set of test cases that you run pre- and post-refactoring, and to refactor in small steps with testing between each step, is to mitigate the potential for undetected error injection to the point that it is almost negligible.
  4. Refactoring leads to considerable extra effort in adapting the unit test suite [9].
  5. Refactoring is nothing new – all the techniques have been around for years [8] [3]. This is largely true, but it is still immensely useful to give this set of best practices and techniques a name and catalogue them with examples and guidelines for when they are and are not applicable in order to efficiently disseminate this collective body of knowledge to developers.
While some refactoring techniques (e.g., moving a method from one class to another) will require at least some unit test rework, most do not. If you have a complete suite of unit tests already in place, which should be the case even if you are not planning to refactor, then the impact due to most refactorings is likely to be minimal. In some cases, however, this criticism is justified (see case study 2, section 7.2); however, we do not believe this is a valid across-the-board criticism.

6. Five-step Framework for Refactoring

To ensure refactoring has a methodical and intended outcome, the authors have created a five-step process for carrying out a refactoring exercise. It is very important to note that during a refactoring exercise, several design issues may need resolution. Follow these steps for each issue in series rather than trying to redo it all at once, that way if a step in the process changes the system’s behavior, the injected error will be easier to locate.
6.1. Identify the Need for Refactoring
No journey can begin without a charter and no refactoring can begin without a cause. As software engineers, we have all come across code that met the requirements and wasn’t “wrong”, but it certainly isn’t “right.” Kent Beck introduced the concept of code smells – any symptom in the source of a program that possibly indicates a problem. These code smells are often the first indication that a refactoring is in order. Martin Fowler [1] popularized the term and catalogued several code smells.
6.2. Establish Test Cases
If the goal of refactoring is to correct issues in software without altering its external behavior, test cases must be in place to ensure that the behavior of the system before the refactoring is the same afterwards.
Having self-verifying tests (i.e. tests that check the software’s output against expected or “truth” values) ensure that the engineer can execute the test suite rapidly and repeatedly.
6.3. Develop a Plan for Design Changes
Just as an engineer would never launch into coding without a design, an engineer engaged in refactoring should never begin without a plan. The plan should be a concrete list of steps to implement a desired change in the software. This plan is especially important when the engineer is attempting to increase the encapsulation of a class since the class’s data will be tightly coupled to the rest of the system.
6.4. Implement the Plan
With a plan in place, begin executing it in the order it was laid out. If an unforeseen problem arises, consider retreating back to Step 3 and see if the overall plan needs to be revised.
6.5. Re-run the Test Cases
Now that the refactoring is complete, the test cases that were established in Step 2 must be rerun. If the test cases still pass, the refactoring exercise is complete. If however they fail, the software must be reexamined.
Note that some forms of refactoring such as moving methods from one class to another will break the test environment. Van Deursen [2] observes that this ideal scenario cannot always be carried out without having to update the tests.

7. Case Studies

In this section, two case studies regarding refactoring are discussed. The first is a story of a theoretical software application that encounters a dead-end when its developers attempt to extended it. Refactoring allows the application to become easily extendable. The second case study involves a software application for an aircraft subsystem and discuses how the designers used refactoring to solve several issues they saw with the software.
7.1. Case Study 1: Burgertime!
A small fast-food store once had a software package that was designed by the store owner’s son. The software was responsible for tracking all the ingredients used by the store and their various information– purchase date, expiration date, quantity, price, etc. Given that the store only sold one thing – hamburgers – the number of ingredients was very small. The owner’s son, not knowing better and having no appreciation for the future, implemented all these as enumerations in a list, as shown:
enum Ingredients
{
buns = 0;
ground_beef = 1;
cheese = 2;
lettuce = 3;
pickles = 4;
mustard = 5;
onions = 6;
};
Referencing information on the ingredients was done in switch-statements where each ingredient was a case. In all, there were perhaps a dozen switch-statements in a dozen files throughout the application.
The software worked, and the business prospered to the point where the wanted to expand their menu – whole wheat buns, five kinds of cheese, and a complete dessert menu. Assuming this did well, there was even talk of breaking out and doing more than just hamburgers!
7.1.1. Step 1: Identify the Need for Refactoring.
The owner’s son was commissioned to update the software. Right away he knew there were problems. To add a single new item to the application, he had to reopen and modify each switch-statement. Even if he wanted to hire an additional programmer to help add ingredients to the software package, he couldn’t because they’d be constantly asking each other for file control. The son also realized that his manageable switch-statements were getting rather long. While they compiled just fine, he became increasingly uncomfortable looking at a two-page switch-statement and dreaded the day when another programmer would see them.
This unease with the direction of his software was the son’s growing awareness of a code smell. At a high level, the son failed to encapsulate what would be changing. As a result, he’s faced with the task of repeatedly modifying the same files with the addition of every new ingredient. Assuming that he did this in an object-oriented language, he also failed to leverage polymorphism and instead opted for switch-statements.
7.1.2. Step 2: Establish Test Cases.
Resolved to set things right, the son quickly wrote some test scripts that queried the ingredient’s information and compared them to values that he new to be right. When he’d run the test script, a debug window would simply display a “Tests Pass” message assuming everything was correct.
7.1.3. Step 3: Develop a Plan for Design Changes.
With his test suite in place, the son sat and thought about how he would correct his design. The simplest approach he came up with would be to have a class called Ingredient. All the data about an ingredient would now be attributes of the class rather than scattered throughout the software in switch statements. The array that held an enumeration of ingredients in stock became an array of Ingredient objects. The blocks of switch-statements became single line calls to the Ingredient’s attribute’s accessor.
7.1.4. Step 4: Implement the Plan.
With a plan in place, he implemented it in only a few hours.
7.1.5. Step 5: Re-run the Test Cases.
When he was done, he reran his test scripts to verify that the external behavior of the software had not changed.
7.1.6. Benefits Achieved.
The new software design allowed him to encapsulate what would be changing in future updates. Adding a new ingredient was as easy as instantiating a new Ingredient object with its unique details completely contained within the object.
7.2. Case Study 2: Aircraft Subsystem Software
A software application controlling an aircraft subsystem is the subject of our second case study. This software system is written in C++ and is composed of approximately 650 .cpp (implementation) files and 50 .h (header) files. An extensive number of attributes are required to be initialized upon application startup. These attributes are scattered among dozens of classes. The original implementation involved initializing each object’s attributes in the class’ constructor. Many constructors also required references to utility objects. Additionally, the software design is such that only one object of each concrete class is required, yet no safeguards were in place to ensure that additional objects were not inadvertently created. We will discuss how this application was refactored according to our five-step framework.
7.2.1. Step 1: Identify the Need for Refactoring.
The design described above had a few inherent problems that the software design lead desired to address:
  1. Each of the approximately 650 .cpp files has its own unit test, each of which requires the creation of a dummy object of the associated class to use for testing. Any change that affects the signature of the constructor or any of the attributes initialized therein has the potential to cause all unit tests associated with that class to fail. This leads to the potential for excessive rework of multiple unit tests for trivial code changes where only one unit test should have to be updated.
  2. While the original design never instantiated more than one object of each class, there was no safeguard in place to prevent instantiation of multiple objects against the design intent.
  3. The software design lead felt that refactoring the code to address the issues described above would increase its understandability and more clearly convey the design intent. According to Fowler [1], this on its own is a perfectly legitimate reason to refactor.
7.2.2. Step 2: Establish Test Cases.
Per the established software development process, a complete suite of unit tests was already in place for the application.
7.2.3. Step 3: Develop a Plan for Design Changes.
The software design lead analyzed the problems outlined in Step 1 and settled on the following set of refactorings:
1. Instantiate objects through an instantiate() method that calls the default constructor for the class. The visibility of the constructor will be made private to prevent instantiation of objects except through the public instantiate() method.
2. Implement the Singleton design pattern to avoid instantiation of multiple objects of any class. This is enabled by the addition of the instantiate() methods. Within each instantiate() method, a check will be made to determine whether an object has already been created. If not, an object will be created and a pointer to the object returned. If an object does exist, a pointer to the existing object will simply be returned without creating a new object.
3. Move initialization of attributes out of constructors and into an init() method for each class. As a result, each class’ constructor will now be an empty default constructor by design. Updates that would formerly have affected the constructor and potentially all unit tests associated with the class will now affect only the init() method and its single unit test. References to utility objects formerly required as parameters to the constructors will now be implemented as calls to the utility class’ instantiate() methods within the init() method of the object being initialized. In the refactored code, objects will now be instantiated and initialized in a single statement of the form Class::instantiate()->init();.
7.2.4. Step 4: Implement the Plan.
With the plan in place, the software design lead implemented the changes in the code. The required updates were straightforward and did not take a substantial amount of time to implement. In an attempt to minimize the impact to ongoing updates for planned releases, the code changes were initially made in parallel with formal changes targeted to the next planned release. Because the modules affected by the refactorings were not affected by any upcoming formal changes, the refactoring updates could be held out of the formal release baselines until a convenient implementation point could be determined.
7.2.5. Step 5: Re-run the Test Cases.
As mentioned previously, unit test rework is unavoidable after certain refactorings due to the nature of the code changes involved. In this case, due to the fact that the object instantiation technique was changed, each individual unit test will require superficial—although not necessarily trivial—updates before it can be re-run. This makes it impossible to follow the ideal process of running the exact same suite of unit tests without modification before and after refactoring to ensure that no functionality was affected. Fortunately, however, only the “framework” surrounding the overall sequence of test cases for each unit test is affected; the individual test cases themselves are not affected, thus preserving the integrity of the unit test suite as a means of validating that the refactorings have not altered the externally-visible behavior of the code.
Another deviation from the ideal refactoring process is that due to the need to rework all unit tests (approximately 650), it was impractical to re-run the unit test suite after each individual refactoring technique was applied. Instead, all code changes were incorporated at once and the unit tests subsequently updated and run against the complete set of code changes.
7.2.6. Benefits Achieved.
Several benefits are expected to result from the refactoring effort:
1. The code will be more understandable and more clearly convey the intent of the design.
2. The code will be more maintainable as a result.
3. Unit test maintenance will be simplified as changes to attribute initialization will no longer have a ripple effect through multiple unit tests.
4. Implementation of the Singleton pattern will add robustness by insuring against inadvertent creation of multiple objects of a given class.
7.2.7. Drawbacks.
While the benefits are expected to be tangible, several drawbacks call into question whether proceeding with these refactorings was the right decision at the right time.
1. At the time of this writing, the process of updating individual unit tests has been ongoing for over two months, with a significant number of tests still remaining to be updated. Developers have been borrowed from other teams to help with the unit test updates. It is anticipated that all unit test rework will be completed by the certification deadline, but the amount of effort that will have been expended is substantial. It is late in the development cycle of this application with relatively few significant changes expected in the future, so it remains to be seen whether a net time savings will be achieved over the product’s remaining lifetime due to the improved unit test and code maintainability.
2. The time required to rework the entire unit test suite took away significantly from time that could have been used to implement requirements changes desired by the systems engineering team in the release in which the refactorings were incorporated. This delays the deployment of fixes to the aircraft and ultimately to the customer.
3. Due to the relocation of attributes from the constructors to init() methods, integration test cases (separate from unit tests) were also significantly impacted since they reference each variable through a fully-qualified identifier. In an attempt to minimize the impact to the integration test team, the software design lead worked with the test lead to help update the suite of integration tests. However, until the integration test suite is successfully run against the updated code, there remains a risk that additional test case rework could be required to make the test suite compatible.
4. Current policy does not require ALL unit tests to be re-run for each release; only unit tests associated with units that have changed in a given release must be re-run (this policy does not apply to integration tests). As long as this policy is in place, the payoff will be diminished because the “ripple effect” eliminated through refactoring would not have been realized since the additional unit tests that would have been affected are not required to be re-run. The only benefit would be slightly reduced effort to update the unit tests for units that were updated in a given release.

8. Summary

In this paper we introduced the subject of refactoring and presented our viewpoint that periodic refactoring, done wisely, is an effective strategy to keep one’s code understandable and maintainable, allowing future updates to be made more quickly and with less effort, for a net time savings benefit over the product’s lifecycle. We summarized several criticisms of refactoring and offered our rebuttals. We then proposed a high-level, five-step framework for planning and performing refactoring projects. We illustrated the application of our framework through two case studies, the first of which we consider an example of when refactoring was clearly appropriate, and the second of which we deem more questionable given the timing of when the refactoring was performed.

9. References

[1] Martin Fowler, Refactoring: improving the design of existing code, Addison Wesley, Boston, 1999.
[2] A. Van Deursen and L. Moonen, “The Video Store Revisited - Thoughts on Refactoring and Testing”, Proc of the third International Conference on eXtreme Programming and Flexible Processes in Software
Engineering XP 2002, Sardinia, Italy.
[3] Danijel Arsenovski. “Debunking Common Refactoring Misconceptions.” 7/16/2008. InfoQ.com. Viewed 2/27/2010.
[4] F. Khomh, M. Di Penta and Y. Gueheneuc, “An Exploratory Study of the Impact of Code Smells on Software Change-proneness”, Reverse Engineering, 2009. WCRE '09. 16th Working Conference on, IEEE, 2009, pp. 75-84.
[5] Robert X. Cringely. “May the Source Be With You: Maybe One Key to Strengthening Open Source is Just Differentiating Between Work and Play.” I, Cringely. 5/1/2003. PBS.org. Viewed 2/27/2010. .
[6] F. Bourquin and R.K. Keller, “High-impact Refactoring Based on Architecture Violations”, Software Maintenance and Reengineering, 2007. CSMR '07. 11th European Conference on, IEEE, 2007, pp. 149-158.
[7] S. McConnell, Code Complete (2nd edition), Microsoft Press, Redmond, WA, 2004.
[8] J. Viljamaa, “Refactoring I — Basics and Motivation”, Paper, Seminar on Programming Paradigms, University of Helsinki, October 2000.
[9] G. Keefer, “Extreme Programming Considered Harmful for Reliable Software Development”, Proceedings of the 6th Conference on Quality Engineering in Software Technology, Germany, Dec. 2002, pp. 129–141.
[10] JB Rainsberger. “Refactoring: Where do I Start?” StickyMinds.com. Viewed 2/27/2010. .
[11] Tony Hopkinson. “Developers and managers. What does refactoring mean to you?” Tech Republic. 5/31/2009. Viewed 2/27/2010. .

Wednesday, May 12, 2010

Lugaru - Part 1

For the last several months, I've been following the progress of Wolfire Games - an independent game developer who is taking a different approach to game design. They maintain an active blog, detailing their progress with their newest game as well as articles on game design and theory. Yesterday they released their first game Lugaru as an open source project. For those reading this that don't comprehend what that means, (I'm looking at my sister - my only subscriber) it means that the foundational code that was used to create the game has been posted on the web with the intention that it be read, changed, improved, and used!! Normally, that is a closely guarded company secret, but some will release it for various reasons. The motivation for Wolfire releasing the source of Lugaru is a commitment to continue being awesome!!

I spent some time today reviewing their code. It was the first time I had looked at the source for a decently sized application. Opening a few files, I began to pick up on their coding style and design. Over the last year, I've privately studied the concept of refactoring, the process for improving the design of existing code. My hope is that I can use those concepts to improve the design of Lugaru and use this blog to document my thoughts and progress. Here we go...

Saturday, June 13, 2009

SOAP vs. REST

A quick apology to all the family members that are signed up to this blog. I promise to resume personal musings soon!

My class on Service Oriented Computing is discussing two paradigms of web architecture - SOAP (Simple Object Access Protocol) and REST (Representational state transfer).

REST is an architecture is a style that is used heavily throughout the web. Once we spent a lecture learning further about this and looking at examples, I was blown away at how often it's used. It would be like listening to a lecture on bricks and the types of bricks and the intricacy of brick laying and then stepping outside and look at a building. You're blown away at the new perspective you have for something that you took for granted your whole life.

REST is very simple. It's principles, (blatantly lifted from wikipedia) are:
  • Application state and functionality are abstracted into resources
  • Every resource is uniquely addressable using Uniform Resource Identifiers
  • All resources share a uniform interface for the transfer of state between client and resource, consisting of
    • A constrained set of well-defined operations (HTTP GET, POST etc)
    • A constrained set of content types, optionally supporting code on demand
  • A protocol which is:
    • Client-server
    • Stateless
    • Cacheable
    • Layered
Examples of RESTful web services include Flickr and Twitter.

At the time I read about SOAP in Chapter 4 of "XML, Web Services, and the Data Revolution," I thought to myself, "this seems very straight forward." SOAP uses the http transfer protocol with an XML payload. The payload, in turn, has a similar structure of an optional header plus a body - Easy (at least in theory.)

SOAP services require this structure for requests which isn't as easy to do as REST.

Big Design Lecture #6

I had intended to attend Ryan Plesko's lecture on "Designing for People and Machines" which might have led to some Web 2.0 discussion. Unfortunately, there was a mix-up in communicating the time or date to the lecturer and he wasn't there. Instead I went to Thor Muller's lecture on "Work Like the Network."

Everything about this lecture has already been said on my post about lunch.

Big Design Lecture #5

Lecture #5 was "Presenting Your Ideas in Highly Charged Political Situations" by Adam Polansky. He made it evident that the title of lecture was chosen by a third-party AFTER he put his presentation together. Whereas the title might lead you to think he'd be teaching you methods for making your boss think he came up with your ideas, this was nothing more than how to organize your presentations.

Although this was a flagrant abuse of false advertising, it was one of the most applicable tracks I attended. The most important thing I took from the lecture was minimizing the amount of information you put on a slide. I think all too often, people pack a slide with so much text that they just read the slide to the audience or could sit down and let the slide do all the talking for them. Either way, they miss the important detail that a slide show assists you the presenter. People came to hear YOU, not your slide show!

Big Design Lecture #4

I took a break during the fourth lecture to collect my thoughts and recover from the UX excitement. I used the time to create my Twitter account and then read the wikipedia entry on "Twitter" to try and understand what I got myself into. I still don't understand the hype (which coincidentally is my 6 word summary of Big D).

I caught the last few minutes of "Future Prood Designs + Presentations for THIS Generation" with Robert Wiseman. The only points I took from there was the idea of allowing your customers to decide your design. He used the image of employees walking across a grass field to work (what kind of business are we talking about?!) and then paving the rabbit trails that emerge. He didn't have an example of an application doing this, though.

Big Design Lecture #3

It's interesting how otherwise innocent words can have profound meaning in professions. "Code Pink" for example comes across as almost a playful alternative to it's more serious big brother "Code Red." You don't see many medical dramas declaring Code Pink - imagining it is kind of silly. Yet if you walked into a hospital and ran up and down the halls yelling "CODE PINK!" you'd scramble the entire building. Code Pink in medical jargon means an infant has been stolen. Pretty serious...

Likewise in embedded programming "Design Patterns" holds a very reverent meaning due to the book of the same name written by the Gang of Four. Noone casually sits down to read it - they meditate on it!

Therefore when I saw the third lecture at Big Design would be on "Latest Design Patterns That You Should Know" by Bill Scott I penciled it in as a must-see. It wasn't as profound as those words would have it seem. These patterns were not as hard to understand and visualize as say the Visitor Pattern. Bill had lots of them that you would think would be common sense, yet he had lots of real-life examples of websites implementing just the opposite resulting in 'anti-patterns.' This form of presentation ("Here's what NOT to do") really connected with me. I enjoyed the talk, though I don't know if it's directly applicable to work.

Some examples of his design patterns:

1. Make it Direct
2. Keep it Lightweight
3. Stay on the page
4. Offer an Invitation
5. Show transitions

I would have taken more detailed notes, but the lady sitting in front of me turned around and scolded me for, "Doing work during the presentation." When I explained I was taking notes, she said the typing was very distracted and that I was a VERY rude person, despite my repeated apologies.

Big Design Lunch

By this time I was ready for a break. As an embedded engineer I'm in the business of writing black boxes where numbers go in and numbers go out. There's no "user experience" and no customer I'm trying to pull in. I got to be honest, the first two lectures left me physically shaking after hearing how bad people are trying to suck me in to their product.

Needless to say, I needed a break. The Big Design conference catered boxed lunches. I grabbed one and set off to find a conversation to be a part of while I ate. The topic among my classmates was either how we finished up the last class or how Frailey's death-march of a project was wrapping up - neither one of which I had the stomach to sit and listen to. Feeling particularly brave I walked up to a table with two guys my age and asked if I could join them. They eagerly agreed and I sat down. Turns out these two guys were Garrett Dimon and Thor Muller - two speakers at Big D. If I was hoping for a light conversation that helped bring all this into perspective and let me digest the last three hours of lecture, it wasn't going to happen. At one point it occurred to me that these two (particularly Thor) talked really fast and non-stop. The conversation was all over the place. At one point I gathered Thor was a carear business starter - building a small company and selling it... starting another. He must be terribly important and very rich, but not much of a listener.

At one point he asked me what I thought of 'all this', (I assume he meant the last hour of hyper-babble) and I got the impression he was only using this as a launch pad to change the subject. I said I was an imbedded engineer who was on assignment at the convention. The look on his face made it look like something foul had briefly crossed his nose. Then realizing his face was showing his thoughts, he made a pleasant comment about me being the smartest person at the table and then resumed hyper-babble.

With the next track starting, I excused myself...

Big Design Lecture #2

The second lecture I attended was "The Art and Science of Seductive Interactions" by Stephen Anderson. This lecture really went hand in hand with the previous lecture even though they were in separate tracks. In fact, the lecturer user the first speaker several times as an example.


Stephen did, however, use lots of examples with his points. I was amazed at all these hot web-site everyone in the audience had heard of that I haven't. Examples: iLike, Sabre, Doppler

Again, this was a demonstration in how sausages are made.

Big Design Lecture #1

The first lecture I sat in on at Big Design '09 was "What Makes The Click" with Dr. Susan Weinchenk. She was a psychology expert that walked the audience through understanding several quirks of the human brain and how to take advantage of that in design web applications. A few points she made:

1. Fear of Loss - The most primitive parts of our brain are more concerned about losing something we have than gaining something we don't have. This can be exploited by offering a product with all the features and letting the buyer remove them rather than giving them a base model and letting them add features. In the latter example, they'd be reluctant to lose the money for the upgrade.
2. The Bystander Effect - When placed in an uncertain situation ("which item should I buy?!") people tend to become followers. This is leveraged with user testimonials and buyer reviews.

At the end of the talk, I felt (as a customer) like I was let in on a secret I wasn't supposed to know about. Like walking in on a butcher while he's making sausages. Knowing your being manipulated and pulled in is such a turn-off, even when it's the subject of a lecture.

I chuckled thinking about what it would look like if we used these principles in the UI for the F-35. "An unknown entity has been detected. Click here if you want to learn more..."

Big Design Intro

This summer I'm taking a course in Service Oriented Computing. As a cold opener to the course, my class attended "Big Design '09" at SMU. This was an all-day conference that had multiple tracks talking about UX as it relates to software. What UX was they never said, but 10 hours of context clues makes me think it stood for "User Experience"

I'll save my over-all impressions for the end. What follows will be my summaries and impressions of each seminar I attended.

The Keynote Plenary was given by Norm Cox on "The UX Landscape" (again, never said what UX was :P) Norm gave a very interesting autobiography on his work with early computers using bitmap displays with the operating system. His work involved creating what could be thought of as the first desktop with icons. One of his most profound comments was that IBM recognized early on that the user interface is the most valuable touch-point between a user (customer) and the product.

At one point he talked about contracting with PizzaHut to overhaul their back-office system that instructed employees on how to build a pizza. This was extended to ensuring that when an order is taken, it's taken correctly. Although he didn't touch on it, this new UI was so simple that PizzaHut used it when they developed a web-service for ordering a pizza on-line. I know because I did that very thing not 3 days before the show. I remember thinking at the time, "This is a great setup they have here!"

Take-away points from his speech:
1. Beware the limitations of titles.
2. Be a 'jack of many (ui) titles, master of some"
3. Elevate and think strategically
4. Take advantage of opportunities.

Monday, December 22, 2008

Striving for a Charlie Brown Christmas

One of the top five descriptions I'd use to describe my paternal grandfather is that he loved Charles Shultz's Peanuts comic strip. As such, I remember watching a "Charlie Brown Christmas" at an early age. As a child, there's always that initial excitement of watching a cartoon, (especially at the grandparents ;)) but I distintively remember being disappointed. The plot didn't make sense, the animation was horrible, and the humor was over my head. And that was probably the last time I watched it in its entirety until this week. It is quite possibly the best seasonal movie I've ever seen. If my mere recommendation of it now has your interest peaked, I found it all on YouTube.

For the last three or four years Christmas has been a really hard time of year for me. I feel wound up and anxious and trying to think of twenty things twenty people can get me is frustrating and feels somehow wrong. The cartoon addresses this in its opening line -
"I think there must be something wrong with me, Linus. Christmas is coming, but I'm not happy. I don't feel the way I'm supposed to feel. I just don't understand Christmas, I guess. I like getting presents and receiving Christmas cards, and decorating trees and all that, but I'm still not happy. I always end up feeling depressed."


Charlie Brown tries to busy himself with holiday activities in the form of directing a Christmas play. I wish they would have developed the story on this Christmas play since it included an inn keeper, a Christmas Queen, and easy jazz music... Charlie Brown takes his job very seriously and becomes a bit of a task masker - the rest of the kids just want to dance to the jazz. Charlie Brown then tries to make it better with the infamous "Charlie Brown Christmas Tree" to which he is richly chastized. At his wits end, he cries out for someone, ANYONE, to explain the meaning of Christmas to which Linus gives his epic monologue:



I hope if you find yourself striving for things or activities this time of year, you slow down and remember the reason for the season. ;)

Monday, October 27, 2008

The New Love of My Life!

I'd like you all to meet Jonathan Reagan Faulk! He's due a full month earlier than thought! March 11. The technician says he looks very healthy - perfect brain, perfect spine, perfect stomach, perfect liver, and perfect kidneys. He's got a perfect.... err.... something else too! ;)

In the shots below Jonny is laying on his back with his head on the right side.





In this picture he raised his hand to his mouth...



This final shot is looking up between his legs...



I'm going to have a son!!!

Tuesday, October 9, 2007

Got Change For a Million?

If you've been to downtown Fort Worth on the weekends, chances are you've encountered a Christian organization handing out leaflets with a million-dollar bill on the front. If I recall correctly, they tie the question of where you go when you die with 'the million dollar question.' In the half-dozen times I've been to Sun Dance Square, I think I've seen them 3 or 4 times.

Turns out someone in Pennsylvania tried to make change with one of their leaflets at a grocery store. Here's the link.

Any idiot knows you have to go to the Federal Reserve to make change with your Clevelands.

Tuesday, October 2, 2007

Honeycomb Chifon Pie

Recently I made a pie for our Bible study. Here are pics of it...







Wednesday, September 5, 2007

The Intersection of School and Work

This week I've become very aware of how much my college classes had an impact in my professional life. Not my lecture classes mind you. Everything I needed from lectures I learned in the first year-and-a-half. No, it's the five project labs I had in the final years that made the deepest professional impact.

For those not in the know, Project Lab began with the instructor organizing us into groups and assigning semester-long projects, (though in later years we got to choose our teams and projects.) Each project involved designing and building some electrical device such as an electronic blood-pressure reading gadget. The projects also had an attached professor that served as the customer/advisor. We would develop a semester-long schedule and budget and then execute it with the professor signing off on our weekly progress. The majority of our time, though, was spent making power-point presentations (how accurate is that to professional life?!) and present them to the course instructor and our peers, one after another for three hour stints which can only be described as the death-march of academia.

The toughest part by far, was the firing line that came at the end. Each presenter would end with the obligatory, "are there any questions" and then the real learning would begin. The instructor would typically ask the presenter to go back to the first slide and we'd work through the presentation nit-picking every fault in the presentation. Although in retrospect this taught me the most, at the time it was sheer torture.

"Blue text on a black background means only the first row of your audience can read that, Mr. Wetz."

"There's too much information on this slide"

"There's not enough information on this slide"

"You call that a voltage divider? What have you been doing for the last three years of your life that would make you think that?"

“So you’re going to use an unsigned integer to store an angle between -pi/6 and +pi/6?”

One time a person had a picture of red and green wires he had twisted together to reduce the impedance of some network device. During the 'question time' the professor released both barrels on him for using "two of the same colored wire". "By doing so, every time you pull this out to work on it you've got to ohm out both ends to make sure you've got the right ones. You should have used two different colors!" Like good sheep the presenter and the entire class of about thirty sat there quietly taking this. Finally the presenter, at his whit’s end, did the unspeakable and said, "but sir, these are two different colors - they're red and green!" to which the instructor replied, "Oh... I guess I should inform you I'm color-blind."

In the final two project labs, the instructor raised the ante by announcing part of our grade would be determined by our active participation during the question time. Rather than the presenter being thrown to a great white shark at the end of their presentation, he would now be thrown to a great white shark and a school of piranhas.

Again, I did the most learning here, but it turned you into a person that you didn’t want to look at in the mirror!

I bring all this up because this week groups at work have been presenting their results of a month-long development. During the times I was presenting, I found that I was calm during the moments I would speak, but the anxiety wouldn’t build until I’d get closer to the “Any Questions” slide. In addition, I find that anytime a manager asks a question, I find myself wrapping it in a ‘bail-out clause” in case I’m wrong – “Well, last time I checked…” or “I was under the impression…” Thanks to project lab, I think I’ve been conditioned to believe that any question from an authority figure is just to test me and bring me down a notch. I need to either become a resident expert (not a bad thing) on whatever it is I’m talking about, or at least have the gumption to assert myself with confidence.

In addition, yesterday a person posted an object model diagram that was riddled, I MEAN RIDDLED, with errors! After confirming that I hadn’t fallen into some twilight zone or I wasn’t the center of a prank of conspiratorial proportions, everything from project lab was screaming, “Be the first to say something! You’ve got this!” And yet the other, wiser half of me was saying, “You’ve got a half-dozen managers and another half-dozen senior developers in here, surely they’ll point it out.” Yet NOONE did. We sat there in complete silence looking at the biggest travesty to software engineering and didn’t correct this error!

I don’t think I like the idea of “a time and a place” to correct programming errors. Or things that are Worse Than Failure - things that technically compile and run, but do so in such a wrong manner that it self-induces a face-five.

Software Engineers and co-workers, what do you think?