The application server market continues to evolve. A number of strong players, including IBM, are leading the pack with offerings that provide support for the latest J2EE standards. At the same time, a larger number of one-time players in the application server market are taking a different route. Some application servers, like NetDynamics, are being phased out of existence. Others, like ATG Dynamo and Gemstone/J®, are changing their business model to provide services on top of existing application servers rather than support their own. The common thread is that there is a real need to migrate existing applications to a J2EE base.
Migration is not only about moving non-J2EE applications toward the J2EE standard. Very often, we are faced with a requirement to migrate J2EE applications between application servers. For example, Sun has recently dropped support for iPlanet on AIX®, which has left a large number of AIX aficionados scrambling for alternative solutions.
In my first article of this series, Migrating to IBM WebSphere® Application Server - Part 1: Preparing for Migration, I addressed the issue of preparing code for migration from another application server to WebSphere Application Server. Code migration is only part of the answer. In fact, code migration can be a small part of the overall migration process (this is certainly true for J2EE applications). In this second article, I discuss the different stages involved in migration, present a sample migration road map and offer some advice for estimating the overall migration effort. I also provide hints and tips and best practices gained from real-life customer scenarios.
The migration process is divided into stages, primarily because different sets of skills are appropriate at various points in the process. Setting up infrastructure is different from coding. Coding and performance tuning are also different processes requiring different skills.
Migration is divided into the following activities or stages:
- Scoping
- Skills Migration
- Code Migration
- Run-time Migration
- Run-time Performance Tuning
Figure 1. The stages of migration

Breaking your migration into stages helps you to get the right people for each job. Larger organizations with pools of developers can leverage the heterogeneity of their skill base. With careful planning, stages can even be interleaved. One team might, for example, migrate vertical slices of the application code, while another team evolves these vertical slices toward the J2EE standard. It is important to note that every migration is different. The stages presented here are merely a guideline around which a migration can be effected.
On a recent migration project, the scoping session was skipped and our developers went right into the code migration phase. Sometime into the migration, it was discovered that the client's application code had taken a number of liberties with the EJB specification; another application server's implementation of EJB seemed to have no trouble with these liberties, but WebSphere did. From the client's perspective, WebSphere was flawed. However, the only "flaw" (and of course this is no flaw at all) was that WebSphere implements the EJB specification!
The initial estimate of two days to effect the code migration blew up into several weeks as workarounds, and architectural and code changes were made. As might be expected, this caused much grief with the customer who had difficulty understanding why their code would not run on our product.
If we'd done the initial scoping, everyone would have been better prepared for the actual effort required.
Purpose of the scoping session
The purpose of the scoping session is to determine the scope of the effort required to do the migration. This is a vital step as it sets the stage for the rest of the effort. During this time, you must work to:
- Understand the requirements
- Complete a design and code review
- Review the run-time environment
- Develop an education plan
- Develop an overall migration plan
This knowledge forms a base on which estimates can be made and risks can be identified.
What's involved
The scoping session should take about a week for a medium-sized application. An example agenda for a scoping session is presented below:
- Review application requirements (0.5 days)
- Design and code review (1.5 days)
- Run-time environment review (0.5 days)
- Migrate a single vertical slice of the application (2.5 to 5 days)
Before any effort, it is important to know what needs to be done; you must understand the goals well so that you know when you've completed the task. Requirements gathering includes such things as functional requirements, performance targets, scale and usability requirements. These requirements have an impact on the work that must be done and should be well-documented. Even if the application is already running on the other application server's platform, it is still good to have written requirements.
It is important to understand how the application is performing on the other platform with respect to these requirements. Is the current performance of the application acceptable? Is the current application able to scale to handle present and future demands? These are questions that should be answered to understand if the requirements are reasonable, and whether additional work beyond simple migration is required as part of this effort.
Performance is often cited as the reason for undergoing a migration effort. Unfortunately, when it comes to issues of performance, often a better algorithm is the best solution. That is, if the application code itself is inefficient, then changing to an alternative application server will likely only offer marginal (if any) gain. If performance is the driving force behind the migration, expect to spend time reviewing and reworking the application's design (which can take much time).
In the context of a migration, a design and code review is primarily concerned with identifying elements in the code that require work to migrate -- not overall quality of the code (that said, good quality code is generally easier to migrate). In particular, a code review should identify the use of technologies proprietary to the other platform and differences between different versions of supported standards. To that end, much of the code review is mechanical and can be done quickly. As part of this effort, you might identify the particular version of EJB in use, along with specific quantities of CMP entity beans, BMP entity beans, stateful session beans and stateless session beans. The quantities of each element type will be handy tools for estimating the total effort required.
Proprietary technologies are typically the source of most migration grief. In the early days of application servers, standards coverage was not as broad as it is with J2EE. First-generation application servers made up new technologies to fill the gaps. JHTML, for example, is a proprietary technology developed in the absence of the JSPTM standard. In many ways, JHTML is very similar conceptually to JSP, but there are enough differences to make migration between the two somewhat more than a simple mechanical process.
The configuration of the run-time environment has a significant impact on the scalability and reliability of the running applications. It is important to understand what effect the run-time environment has on the way that application code is written. Applications written to deploy on a single node may not scale well without extensive modification. You must factor these modifications into your estimate.
Setting up a run-time environment can be tricky. If you currently have dozens of servers working in harmony to host your application with another application server, chances are you will need a similar amount of hardware for WebSphere. While installing and configuring a WebSphere cluster is not necessarily difficult, it can be time consuming.
Understanding the deployment environment currently in place with the other application server is valuable. Be sure to include time in your scoping effort to design your WebSphere run-time environment and come up with a plan for migrating your existing run time with minimal cost and interruption of service.
The final part of a scoping exercise steps through the migration of a single "vertical slice" of your application. A vertical slice is a "top-to-bottom" representation of the application that touches on as many relevant technologies as possible. For Web application development, a vertical slice might start with a page that harvests information from the user, then uses a servlet to invoke a stateless session EJB that writes that information to the database, and then redirects the user to another page. The vertical slice does not necessarily cover every possible contingency; for example, a vertical slice may not provide error checking or may "stub out" various pieces of the technology. It is worth noting that the 2.5-day estimate for migrating a vertical slice does not include software installation time or testing.
Note: Two-and-a-half days doesn't sound like much time to build an entire vertical slice. In fact, it isn't. However, a migration effort is not concerned with building a vertical slice; it is concerned with migrating an existing one. As part of a migration effort (and this is most certainly true for the scoping vertical slice), the business logic of the application should not change. This means that it should be possible to migrate a significant chunk of the application code without changing a single line. Migration efforts tend to be very mechanical. Migrating EJBs and JSPs between different versions of their respective specifications generally doesn't require extensive changes to the existing design of the application. In some cases, however, subtle differences between versions of a specification can cause a lot of trouble. Differences between versions in the EJB specification with respect to the way the container handles application exceptions may require reconsideration of the design.
In any case, the vertical slice migration can help you to identify the problem spots and then plan accordingly.
There are a number of goals related to migrating a vertical slice. Perhaps the most important goal of this exercise is to determine a baseline measure to base an estimate on. Through the code review, the nature of the application code is understood, as is the quantities of specific elements. Combine this information with an absolute measure of the amount of time required to migrate a representative piece of the code (the vertical slice), and you can come up with a pretty good estimate (with appropriate padding for discovery and testing). Another important outcome of a vertical slice migration is that it provides confidence that migration will ultimately be successful.
Even if the vertical slice migration is unsuccessful in delivering a working prototype, it will still arm you with valuable information. At the very least, an "unsuccessful" vertical slice migration will identify the hard problems and allow you to adjust your development schedule accordingly. If you need help, get help and get it early -- it will pay off in the long run.
The education that your team requires to work with WebSphere Application Server depends on the nature of the application that WebSphere is displacing. There are a number of different skill sets to consider. In particular:
- J2EE architecture and coding
- WebSphere tools
- WebSphere Application Server installation and configuration
- WebSphere deployment
WebSphere Application Server, Version 4.0 is completely J2EE 1.2 compliant. If the application server that WebSphere is displacing is also J2EE compliant, then your application developers will likely already have the JavaTM coding skills they require. If you're moving from an application server, such as older versions of NetDynamics, which does not conform to J2EE, then you'll likely have to get your team the skills in the newer technology. Don't assume that your team members will simply "pick up" the new technology; you'll save time if you get proper training in the beginning.
Detailed knowledge of the other application server is not critically important. However, it is helpful to understand the versions of the specification supported by that platform. A broad understanding of the proprietary services provided by that platform is often enough.
Note: Early versions of BEA WebLogic Server made use of a Remote Method Invocation (RMI) replacement named "T3." T3 was created to work around flaws with the existing RMI implementation provided by Sun. Knowing that this RMI replacement exists is often enough (detailed understanding of T3 is not required to be effective in a migration role). T3 is used in the generation of EJB deployment code, which must be regenerated for WebSphere Application Server anyway. A small number of changes to the application code is often required to change the format of names used for EJB lookups.
Tools are another area of concern. If you are adopting WebSphere development tools as part of the migration effort, it is critical that you get proper training in the use of these tools. The WebSphere tools are very powerful, but will likely be different from what your developers are used to. It will take some time for your team to learn how to use them effectively.
The infrastructure and operations staff are the people who install, configure and keep the WebSphere production environment running efficiently. It is assumed that existing infrastructure staff are familiar with fundamental administrative issues, the operating systems on which their systems run, and have practical experience managing the day-to-day operations of a Web site. Infrastructure people need to learn how to install, configure, and maintain a WebSphere Application Server production environment.
The amount of training you need depends very much on your goals. If you're planning to get outside help for the migration, you may be able to forgo some or all of the training for the time being.
"Make it run, make it run right, make it run fast" is a well-known mantra in incremental development circles. This style of incremental development has a positive effect on morale. For the developer, having something that runs makes further development generally easier. For management, having something run early gives confidence that success is inevitable. This three-step philosophy for incremental development applies to a migration effort.
In the first step, get your application running in WebSphere Application Server in the shortest time possible with the smallest number of changes possible. This should be a relatively short-term process with the effect of demonstrating that success is inevitable. During the second step, refactor your application to work out bugs, make use of best practices and conform to the J2EE specification. The main purpose of this step is to improve the overall quality of the application and make the application more resilient to future change. With the application running "right," the final stage in code migration is to optimize the code as required.
Doing the code migration incrementally provides much value. While making your application code run, you may uncover problems not discovered during the design and code review. By discovering these problems early, you have a better chance of finding time to solve them or changing your priorities to accommodate for them. Another advantage of incremental migration is you can decide whether you want to back off the migration (perhaps to wait for a later version of a technology, or even to rewrite from scratch).
Get it running
The real danger in this step is in trying to do too much. If the existing application actually runs on the other application server, the best approach is to get it running in WebSphere Application Server with the minimal number of changes possible. That is, stick to making the existing application run in WebSphere Application Server; avoid making significant design changes to the application. It may be the case where the application doesn't actually run on the other application server. In this event, the effort becomes more difficult and may in fact become an effort of re-implementing the application.
Divide and conquer is an excellent strategy to adopt in this stage. If the application is well-written, then it should be relatively easy to modify and to test the parts as necessary. Even if the application is not well-written, it should be possible to employ some form of divide and conquer strategy. An enterprise application can be very complex with numerous interacting streams of functionality. These streams of functionality can be divided into vertical slices of the application. Start with one feature and migrate it completely. Additional features should be added incrementally with testing done along the way.
While doing the migration, test cases should be migrated along with the code. If no test cases exist, create them. You should run your test cases against the other application server implementation to validate their correctness. Creating test cases, especially for existing code, is very helpful in making the purpose of individual features more clear. These test cases will also be helpful later on when the time comes to update or upgrade the inherited application code.
This effort is very similar to that of any application development effort:
- Understand the requirements.
- Understand the existing design.
- Develop a unit testing plan.
- Implement unit tests on existing implementation.
- Select a vertical slice of the application, modify as necessary, test and deploy to IBM WebSphere Application Server.
- Repeat.
Extreme Programming [Beck] has a lot to say about the development process. Fortunately, "extreme" practices work well in this context. Extreme Programming practices do seem to be a little too "extreme" for some development efforts, but there is a minimum set of recommended practices that can be followed:
- Work on the important features first
- Tackle hard problems early
- Do one thing at a time
- Do the simplest thing that can possibly work
- Test, test, test
- Release often
- Divide and conquer
There are many reasons for migrating important features first:
- Migrating important features first helps the decision makers to feel more at ease with the process to see their key features implemented in a timely manner.
- In the end, if something has to slip, it's good to know that the important stuff is done.
- It is very likely that the "hard" problems are somehow related to the most important features.
- The hard problems will take the longest amount of time to implement.
- Hard problems are also very difficult to estimate, so taking care of them first can give you a little more time if you need it later.
Do one thing at a time. Choose one piece of functionality, and migrate it. It is far easier to migrate, test and integrate one small piece than to attempt to do the same with a larger set of functionality. Do the simplest thing that can possibly work (don't try to anticipate problems you're not sure you have; the code should be as simple as can be, but no simpler). Try to resist fixing architectural flaws in this stage. Get the migrated code to work and leave it at that. You should revisit the architecture in the "refactoring" stage.
Test, test, test and test some more. Before you migrate existing code, make sure it works as expected in the other application server. If you know how it works on that platform and you have results from test cases to prove it, you can prove that your migrated code functions as expected. These test cases will also be very valuable later when it comes time to reevaluate the architecture. Run your test cases frequently -- this will save you grief.
Release often. Make a WebSphere Application Server running on the deployment operating system (and hardware) available to the developers. The migrated application should be tested on the deployment test server periodically. Perhaps weekly or biweekly. There may be subtle differences between the development and deployment platforms. Attempt to determine any problems associated with these differences early.
Divide and conquer. During this effort, use a divide and conquer approach at all levels of granularity. Sure, you can divide the entire application into vertical slices, but each of these slices can likely be divided as well (and then divided again). For example, you may consider a slice of the application that uses the typical Model-View-Controller (MVC) pattern:
- Write your test code for the model.
- Confirm the results of your tests on the other application server.
- Migrate the model code.
- Confirm that the migrated code functions as expected.
- Write tests for the servlets and JSPs.
- Confirm the results of your tests on the other application server.
- Migrate the servlets and JSPs.
- Confirm that the migrated code functions as expected.
- Integrate with the collective migration effort.
- Repeat.
It is worth stating again that this effort should focus on getting the existing code to run in WebSphere Application Server with the smallest number of changes possible. Salvage as much of the existing code as possible. Unit tests should exist before the application development process begins. Unit tests may evolve during the migration process.
Get it running right
On a recent migration project, the client had a huge code base that took advantage of a number of violations of the EJB specification that the other application server happened to permit. It quickly became clear that updating the code to conform to standards would require extensive changes to the application's architecture and could take months. It was decided that it would be easiest to build workarounds rather than make significant changes to the application.
The workarounds (descriptions of which could -- and might -- produce a number of papers) took a number of different forms. In some cases, the other application server's behavior was "stubbed-out" or emulated; in other cases, the behavior of WebSphere Application Server was modified using documented hooks. Still, even with the workarounds in place, a relatively small number of code changes were required.
In the end, the workarounds allowed us to complete the "code migration" stage in a very short time-frame. At the end of the stage, the application did work; however, it suffered from stability problems and could not scale without more extensive modification (in all fairness, the implementation running on the other application server wasn't particularly robust and couldn't scale either). With proof that the application could indeed work in WebSphere Application Server, we started refactoring.
As part of the refactoring effort, a full review of the application's architecture was undertaken. Architectural changes were introduced into vertical slices of the application. Having a running application made making these changes much easier. It was very convenient to be able to test our changes within the functioning system. As we iteratively refactored the entire code base, we depended less and less on the workarounds until they were ultimately retired from service.
In the end, the two-stage code migration really helped. Being able to actually run the application made modifying it much easier.
Refactoring [Fowler] is a process of modifying code to improve quality without necessarily adding new behavior. In general, refactoring should be part of the normal development process (in fact, some amount of refactoring should naturally occur during the "Code Migration" stage). It is during this stage that the major surgery takes place.
"Major surgery" can take many forms. The application's architecture should be reviewed and updated. The MVC architecture is a well-known and generally accepted architecture. The work you do here to take advantage of such established practices will pay off in the long run. Maintenance will be easier, as will migration to future versions of WebSphere Application Server. Even if you're currently using MVC, this stage presents an opportunity to ensure that you're doing it right. By adopting standards, you can mitigate the migration pain you're feeling now on future efforts.
On a smaller scale, application of best-practices can yield significant improvements in robustness, scalability and performance. For example, existing JDBC code that depends on DriverManager or proprietary connection pooling solutions can be updated to make use of DataSources. "Classic" servlets that generate HTML output can be updated to make use of JSPs. EJBs might be updated to actually make use of EJB features. Old workarounds can be updated (or removed completely) to take advantage of standard features.
Having good unit tests in place makes refactoring that much easier. Unit tests allow you to make changes with confidence; if a change breaks something, this will be revealed by the tests. If you don't have unit tests, it might be a good idea to start introducing them in this stage (if you didn't get around to it in the "get it running" stage, for example). You don't have to go crazy and build thousands of tests providing full coverage; as you make changes, make tests. Over time, the number of tests will increase providing broader coverage. Testing, like refactoring, should be a natural part of the development process. Consider investing some time in a good unit-testing tool like JUnit.
Get it running fast
By this point, the application code should be running "right." That is, the application is a WebSphere application and the fact that a migration has taken place is no longer relevant. The skills required at this stage are no different than the skills required for any WebSphere application.
Even the most brilliantly written code depends on a properly configured application server to run. Setting up the production/testing environments is a key requirement for success. Of course, the configuration of the production environment can be quite complex. Starting from scratch, installation and configuration of a WebSphere run-time environment can take several weeks. Upgrading a production environment that must stay live during the process can take longer.
Installation of a single WebSphere Application Server node is a relatively easy chore that can be reasonably completed in about a day. Installing a more complex collection of nodes featuring load-balancing and fail-over can take considerably longer. Don't kid yourself into believing that a reasonably complex installation can be effected over the weekend. A proper migration strategy is required.
Given that migrating the run-time infrastructure will likely take some time, an alternative approach that interferes with the running system as little as possible is needed. There are a number of ways to upgrade a running system. The right approach depends on some factors:
- How much downtime is acceptable?
- How much additional hardware can you purchase?
- How is the existing environment configured?
- Does the existing environment provide load-balancing support?
- Does the existing environment provide fail-over support?
An obvious approach to migrating your run-time environment is to simply build the WebSphere environment and then "flip the switch." That is, replace your entire existing environment with WebSphere. This works well for small configurations; for larger configurations, the cost of duplicating a large amount of expensive hardware can be prohibitive.
Another approach might be to migrate branches of your run-time environment on an individual basis. This depends on existing support for load-balancing in the other application server. As shown in Figures 2 to 5 below, branches can be shut down, upgraded, and reintroduced into the environment. In this way, run-time migration is not all that different from code migration as "vertical slices" of the run-time environment are migrated to WebSphere Application Server. One key benefit of this sort of approach is that it is possible to estimate the overall effort of completing the migration based on the size of the configuration and the effort required to migrate a single slice.
Figure 2. A vertical slice migration may be possible if your application code and run-time configuration supports it. First, a "vertical slice" (in gray) is selected and removed from the cluster.

Figure 3. The vertical slice is rebuilt as a WebSphere Application Server node and is reintroduced into the cluster (in blue). Note that the HTTP Server is also updated to make use of a WebSphere plug-in.

Figure 4. Additional application server nodes (in gray) are excused from the cluster and rebuilt as WebSphere Application Server nodes. The "WebSphere" HTTP Server is modified to recognize additional application servers.

Figure 5. HTTP Servers are also upgraded along with the WebSphere Application Server nodes. Over time, WebSphere completely takes over from the other product.

The run-time migration scheme shown in Figures 2 to 5 above represents a best-case scenario and depends on the other application server providing support for load-balancing. The way the application is written can also have an impact on the overall effort. For example, it is very unlikely that WebSphere could share HttpSession data with the other application server; if the application is written such that HttpSession data is required, and the run time is not configured to "pin" a user on a particular node, this style of migration may not work. In this case, some combination of approaches may be possible.
In any case, there are essentially two parts to a run-time migration effort. Before your staff can attempt to migrate the run time, they will have to learn more about WebSphere Application Server. Start by migrating a "System Test Environment"; this environment can generally stand extended periods of down time, and is an excellent place for your people to make mistakes as they learn how to best configure WebSphere Application Server to run your application.
Use the migration of a system test environment to learn the ropes and make mistakes. Based on the lessons learned through this migration, formulate a plan to effect the entire migration and test that plan against the QA environment. If it is possible, migrate your configuration as vertical slices, measure the time required to migrate a single slice and use that information to estimate the entire effort.
By starting with a system test environment and then moving into your quality assurance environment, you can formulate and evolve an effective plan and mitigate the risks of migrating your live production environment.
Corporate WebSphere Environment
In general, it is recommended that several environments be configured as part of your "Corporate WebSphere Environment" (this is true for other application servers as well). At a minimum, you should have at least one "System Test Environment", a "Quality Assurance Environment" and a "Production Environment."
The "Production Environment" is what is used by the end user. This environment generally has very strict availability requirements and is scaled to support your entire user base.
The "Quality Assurance (QA) Environment" environment is used to test the overall correctness of both the run time and the application. It is a scaled down version of your production environment with the same level of complexity. That is, the QA environment is configured similar to the production environment (same configuration of firewalls, load-balancers, backend systems, etc.) only at a smaller scale (the QA environment's cluster may contain fewer nodes, for example). Before changes are made in production, they are made to the QA environment. The QA environment can withstand generally longer periods of down time which makes it an appropriate environment to test your migration plan.
A number of "System Test" Environments may be configured, depending on your specific needs and budgetary constraints. System test environments are used by the administration staff to test patches and configuration changes before they are adopted by the QA and production environments. Software developers might use a system test environment to test their code in an environment that closely resembles the production environment. Performance testers might use a system test environment to do their work as well. A system test environment is generally configured to reflect the complexity of the production environment at the smallest possible scale. As such, a system test environment is relatively inexpensive to build and maintain.
Use the migration of a system test environment to learn the ropes and make mistakes. Based on the lessons learned through this migration, formulate a plan to effect the entire migration and test that plan against the QA environment. If it is possible, migrate your configuration as vertical slices, measure the time required to migrate a single slice and use that information to estimate the entire effort.
By starting with a system test environment and then moving into your quality assurance environment, you can formulate and evolve an effective plan and mitigate the risks of migrating your live production environment.
There is nothing special about performance-tuning a migrated application. By the time you get to performance tuning, your application should be a J2EE 1.2 compliant WebSphere application. This means that existing WebSphere Application Server performance tuning skills can be used (refer to "WebSphere V3 Performance Tuning Guide" [Ueno], an IBM Redbook on performance tuning).
Tuning the performance of the deployed application can take a number of different forms. Performance tuning can take place at the code level or at the run-time level. In any case, the goals of the application should likely be reassessed before starting the tuning process. Tuning code can be quite expensive when compared against the cost of purchasing additional hardware.
By dividing your migration into stages, you can leverage different skills bases. The "get it running" step of the Code Migration stage presented here, for example, may require some knowledge of the other application server and the services it provides. The "get it running right" step, which starts after the code is migrated, depends on skills required to upgrade an existing application to J2EE. By the time the "Performance Tuning" stage is started, the application is essentially a J2EE application running on WebSphere Application Server and standard (existing) skills can be employed.
When it comes to estimating the effort required to effect migration, a scoping exercise is your best bet. Through a code review, you can gauge the absolute size of the migration. By migrating a representative vertical slice of your application, you can measure the time it takes to complete (and identify potential sources of trouble). The product of these values provides a rough estimate of the total time required to effect the entire migration. By migrating the important and riskier parts of your application first, you mitigate some of that risk by allowing schedules and priorities to change early on in the effort.
Don't be afraid to get help. There are many of us out there who have done this before. You don't have to do this alone.
Special thanks to Paula McMillan and Kyle Brown for their help.
- [Beck] Beck, Kent. Extreme Programming Explained: Embrace Change.
Reading, Mass: Addison-Wesley, 1999.
- [Fowler] Fowler, Martin. Refactoring: Improving the Design of Existing
Code. Reading, Mass: Addison-Wesley, 1999.
- [Ueno] Ueno, Ken (lead author). WebSphere V3 Performance Tuning Guide,
IBM Redbooks, SG24-5657-00, 2000.
- Migrating to IBM WebSphere
Application Server -- Part 1: Designing Software for Change
- Migrating to IBM WebSphere
Application Server -- Part 3: Migration Assessment
Wayne Beaton is a Senior Software Consultant with Software Services for WebSphere, part of the IBM Software Group. Wayne's diverse role involves him in lots of interesting projects from the WebSphere Skills Transfer and Migration programs to general consulting. Wayne likes to spend his free time convincing people that Extreme Programming, Refactoring and Unit Testing actually work.




