Sept. 17, 2008, 2:45 a.m.
posted by oxy
Item 14: Make deployment as simple as possibleAt some point in the project's lifetime, you have to ship. It seems trite to say it, yet large numbers of enterprise software project teams, both Java and otherwise, never actually think about the process of putting the software into a production environment. If anybody actually spends any time on this, it's usually to the tune of "Oh, we'll just copy the files up to the server and restart the server, and that should about do it." J2EE projects, like most enterprise software projects, are a lot more complicated than that. At a minimum, not only do you have to deploy the software bits you've written into their respective containers (servlet and/or EJB) but you also have a database schema to think about. It gets even more interesting if the database already exists in some format but you've had to make a few schema changes—additions and not alterations or deletions, hopefully—that have to get pushed into the production environment at the same time the code goes into production. Things get even more interesting if you have to install any additional software on the production machines, such as the servlet or EJB containers themselves, punch holes in the firewall to allow communication against those machines, reconfigure firewalls on the inside of the DMZ to allow traffic on new ports from the HTTP server to the database on the other side, and so on. Guess who has to do all this? In most large corporate environments, it's not the development staff; in fact, in most large data centers developers are frequently not even allowed near the production servers, much less allowed to install software or make changes to the environment there. But before you breathe that huge sigh of relief at not having to deal with all the complexity and mess installing your software will require, take a second to think about who will be: system administrators. Think about the implications for just a moment. You, as a vetted and J2EE-savvy Java developer, know and understand what J2EE containers are for, why they're necessary, and more importantly, what that be wildering array of installation and configuration options means to your application. System administrators, however, typically have had no such training (or interest, for that matter) and won't have a real clue as to what "stateless session bean object pool maximum size" or "database connection pool starting size" are, much less what values they're set to. Unless you're very, very lucky, do you think they're even going to pay much attention? Most likely, they're just going to take the defaults offered to them (thereby potentially leaving in security holes; see Item 60 for details), and move on to the next item, so as to get this done as quickly as possible.[9]
My point here is simple: unless you really want either (a) an application that doesn't work at all, and/or (b) an application that performs poorly due to the settings configured for it, and/or (c) an administrative staff that's not very happy with you because they had to go through twelve hours and hundreds of pages of documentation to get everything installed correctly, you need to start thinking about how the system will be deployed much, much sooner than a week before it's supposed to ship. Unfortunately, there's not a lot of help here from the J2EE Specification; deployment is one of those tasks that's left as a vendor point of customization, where vendors can compete against one another for developer mindshare and money. As a result, aside from standardizing the ready-to-deploy file format in which Web applications and enterprise applications are expected to be stored, the Servlet and EJB Specifications (and others) don't talk about how deployment takes place. For example, the Tomcat open-source servlet container has at least three different methods of deploying Web applications: (1) you can manually unpack the contents into the webapps directory (or any other directory if you configure Tomcat's master configuration file to point to that other directory), (2) you can simply put the .war file in the webapps directory itself and Tomcat will unpack and install the application itself the next time it starts up, or (3) you can go through Tomcat's HTML-based "manager" Web application, which provides a GUI. The J2EE reference implementation EJB container supports two methods, a command-line utility, and a GUI utility. The Orion application server uses just one method, but it's a very convenient one: it establishes a "deployment directory," and any .war or .ear file copied into that directory is immediately deployed into the container, without requiring a server restart. Stop and think for a moment about the act of deploying the components into the container itself. To be more precise, particularly with respect to EJB deployments, think about the huge array of choices typically presented to the deployer during the deployment step. There's a reason why the J2EE Specification creates two roles for production-related activities, the Application Deployer and the System Administrator—deployment of a J2EE application is unfortunately a nontrivial task—but unfortunately for the rest of the world, not every company has a J2EE Application Deployer on staff, so that role gets relegated back to the system administrators. (Or, worse yet, back to the development team.) Just to compound an already bad day, take careful note that the deployment activities required by J2EE cover only those parts of the environment covered by J2EE itself—the J2EE Specification makes no effort to cover deployment activities as they relate to the database, for example, or configuring JMS Administrated Objects (Queues, Topics, and ConnectionFactories, for example), or configuring JDBC DataSource instances in the servlet and/or EJB containers, and so on. These activities are left entirely to the deployment/administrative staff. Couple all this with the fact that the system administrator's job is to keep the production servers up and running as long as possible, with little to no downtime, and you start getting a Real Bad Feeling about all this. (To make that feeling worse, imagine that you're the poor sysadmin expected to take care of all this as the developers head out the door to celebrate.) To save your application from failure right out of the gate and your relationship with the system administrators from an immediate sour downturn, once your application has reached a level where you can start thinking about testing it, start working on a deployment script to automate the task of pushing the application—and any associated support requirements—out to a production server. The script can either be the developers' notion of a script, as in a sequence of commands carried out by a software process (Ant works extremely well for this), or, failing that, a piece of paper with the exact sequence of instructions the system administrators need to carry out to install everything as you require it on the production servers. While we're at it, in keeping with Item 7, think about the possibility of failure during deployment—what happens if the deployment process fails halfway through? Or worse yet, after deploying, you come to realize that there's a huge bug that somehow slipped through your department and QA.[10] What then?
In many ways, we can think of deployment as its own form of transaction (see Chapter 4 for more on transactions). In this case, rather than a transaction done exclusively within the database, it's a transaction against the J2EE container and associated systems (like the database). It fits all the desired characteristics of an ACID transaction: we want the deployment to be atomic, consistent, and durable, and isolation in this case means (ideally) that nobody would see the changes to the application until we "bought off" on the deployment, by committing it. Unfortunately, since vendors don't yet support JTA for their deployment API, we can't just treat the deployment of a J2EE application as a standard JTA transaction. That means, then, we can't rely on a transaction manager to handle rollback for us; instead, as Item 28 points out, we have to be ready and willing to run compensating transactions—in other words, another transaction or in this case, another deployment—to undo what was just done and to bring things back to the state they were in when we started. In other words, for each deployment script, there should be an "undo" deployment script that brings things back to their original state. If you're thinking that this sounds like a lot of work, you're right. But before you start procrastinating on this, bear in mind that your application is going to go through a whole series of deployments long before it reaches the production servers. I'm speaking, of course, of the need to deploy the application to the QA servers so the QA testers can test the application before it sees a production server—you can use the various QA releases you'll hand to the test team as practice for your deployment script. You're going to want to automate that process anyway, because if you don't, both the QA team and the system administrators supporting the QA team are going to get tired of going through that deployment step on each release candidate. Anything you can do to automate the deployment process for the system administrators is going to pay off, not only in hours of saved effort for both you and the QA team but also in a much better relationship with the system administrator group. |
- Comment