Search This Blog

Friday, May 21, 2010

Release It! - 18.4 Releases Shouldn't Hurt

This might be my favorite chapter but executing what he proposes will take lots of practice.

Releases shouldn't be a big deal.  Frequent releases forces you to get good at deployments. Reduce the effort needed to release by automating the process as much as possible.

Zero Downtime Deployments
The key is to break up the deployment into phases. Instead of adding, changing, and removing stuff—such as database columns and tables, constraints, services—all at once, add the new items early, with ways to ensure forward compatibility for the old version of the code. Later, after the release is rolled out, remove stuff that is no longer referenced, and add any new constraints that would have broken the old version

The first step is to add new “stuff.” The stuff consists of URL-based assets, web service endpoints, database tables and columns, and so on. All the stuff can be added without breaking the old version of the software, under certain conditions. URL-based resources, such as style sheets, images, animations, or JavaScript files, should be given a new URL for each new revision. For web services, each revision of the interface should be given a new endpoint name. Similarly, for remote object interfaces, defining a new interface name (for example, with a numeral after the interface name) for each version ensures that the old version of the software gets the interface it wants while the new version gets the interface it wants. For socket-based protocols, the protocol itself should contain a version identifier. This definitely requires that the receiving applications must be updated before the senders. It also implies that the receiving application must support multiple versions of the protocol. If it’s simply impractical to support multiple protocol revisions, another option is to define multiple service pools in the load balancer on different ports. By far, the most conflicts—and the most troublesome conflicts—will arise in the database. Schema changes are rarely forward compatible, and they’re never by accident. Still, it is possible to break schema changes into phases. In the “expansion” phase, tables and columns get added. Any columns that will eventually be NOT NULL are added as nullable, because the old version doesn’t know how to fill these in. Later, in the cleanup phase, constraints will be added. This goes for referential integrity rules, too. They cannot be added during expansion because the old version would immediately violate the relationships.  You can use database triggers to bridge data meant for the old schema to fill in columns in the new schema.  It also works in the opposite direction.

With the preparations from the “expansion” phase in place, the actual rollout of the new software on the application servers should be trivial. This could take a few hours to a few days, depending on how cautiously you want to approach it.

After the new release has baked long enough to be accepted, it is time to clean up. This includes removing the bridging triggers and extra service pools. Any columns or tables that are no longer being used can be removed. Old versions of static files can be removed, too. At this point, all the application servers are running on the new version of the code. This is the time to convert columns to NOT NULL that need it, as well as to add referential integrity relations (though constraints enforced in the database can cause large problems for the ORM layer). This is also the time to drop any columns and tables that are no longer needed.

I wonder if something like dbDeploy can be used in this scenario?  Maybe not since it doesn't understand the notion of a cleanup phase.

No comments:

Post a Comment