The starting point for package design is the physical design, as discussed in Chapter 7. During the application design phase, the primary goal was to document any constraints imposed by the application requirements, such as requiring authorization checks on calls into particular components or requiring certain components to run on a particular machine. It was not necessary, or even desirable, to have the entire physical design completed before implementing the components.
As you progress through the implementation of your application, you will refine the physical design, placing components into packages and documenting any constraints on how the packages should be deployed. Keep in mind these four main issues when you are deciding how your components should be packaged:
We'll look at each of these issues in detail in the following sections.
You can activate your application server's components in one of two ways: in the client's process or in a package-specific MTS-managed process. We've already seen that library packages are used to run the components in the client's process. Note that "client" in this sense is another component or application running on the same machine on which the library package is installed, not an end-user application. Library packages do not support declarative security, nor do they offer the benefits of process isolation. Thus, library packages are typically used for utility components that might be used by multiple applications. Library packages are also useful when the overhead of a separate process is undesirable and authorization checks are not required.
Server packages are used to run components in a separate MTS-managed process. Server packages support declarative security, resource pooling, and so on. Most packages are server packages. You group your application's components into packages based on common resource usage, security requirements, and fault isolation needs.
Deciding how many packages you need in your application is a balancing act. With many packages, system administrators have a lot of flexibility in deploying your application. However, each server process requires a certain amount of overhead to manage resource pools, shared properties, and so on. In addition, interprocess COM calls are much more expensive than in-process COM calls within a single apartment. And too many packages make system management tough. At this point in your application development, create the packages you think you need based on resource usage, security, and fault isolation. During performance testing, you can adjust how components are allocated to packages if you find that process overhead or interprocess calls are a bottleneck.
Components that use the same resources, such as databases, should be grouped together in a single-server package. Remember from Chapter 4 that MTS manages resource pools on a per-process basis. Each server package gets its own thread pool, database connection pool, Shared Property Manager (SPM), and so on. If two components using the same database are located in separate server packages, they cannot pool database connections. If the components are located in the same server package, they can pool connections. This capability can greatly improve the performance and scalability of your application. Similarly, components located in separate server packages cannot share properties by using the SPM. Components that need to share properties must be located in the same package to ensure correct application operation.
You should also consider the location of resources when you design your packages. In general, components should be deployed as close as possible to the resources they use, particularly data stores, to help reduce network traffic within your application. For example, if two data stores used by your application might be located on different machines, you should consider putting the data objects that use each data store in separate packages. This arrangement gives the system administrator the flexibility to install each package near the data store it uses. Any deployment recommendations or requirements, such as locating a package and a data store on the same machine, should be noted in the physical design documentation distributed with your application.
You might also want to consider separating components into different packages to ensure that a fault in one component does not cause other components to fail. Recall from Chapter 4 that MTS will terminate a process whenever it detects internal corruption. Exceptions within a component can also force a server process to terminate. Any transient state maintained in running objects or the SPM will be lost. If your application has components that maintain transient state, you might want to consider placing those components in a separate server package. You might also want to isolate components during quality assurance testing.
As we saw in Chapter 4, server packages are the units of trust for MTS. Calls into a package can be secured. Calls within the package are trusted. Thus, application security requirements have a big impact on your package design. If calls into a component must be authorized, the clients and the component must be located in different packages. Only components that can safely call each other without requiring an authorization check should be located in the same package.
MTS roles are defined on a per-package basis. If you have multiple components that use the same roles, consider placing them in the same package. Generally, this grouping is a safe thing to do. Since the components can be called by the same set of users, they should be trusted to call each other. Placing components that use the same roles in one package simplifies administration since the system administrator does not need to remember to populate the role in multiple packages.
In addition, a server package runs as a particular identity, and all components in the package run as the package identity. Components that need to run as different user identities should be located in separate packages. Components might need to run as different identities because they should have different access rights to some resource or in order to maintain an audit trail. Although you generally cannot define the exact identity each server package will run as during development, you should document any recommendations along with the permissions required by package components. For example, if a data object in a given package requires read/write access to a particular data store, you should document that the identity used to run that package must have read/write access to the data store.
In Chapter 7, we identified two likely packages for the components of the Island Hopper application, one for things controlled by the classified ads department and one for things controlled by the accounting department. Our original high-level component diagram is shown in Figure 10-2.
Figure 10-2. The initial Island Hopper component diagram.
During our initial design work, we had not yet identified a need for the two utility components, util_TakeANumber and util_WordCount. These are generally useful components, so they should be put in a separate library package. The remaining components are divided into customer service and billing-related components controlled by the accounting department and advertising-related components controlled by the classified ads department. The primary issue for the Island Hopper application is security isolation for database tables controlled by the different departments. In a more sophisticated example, these tables might be located in separate databases maintained on separate database servers. In this case, separating the components into two packages would give the system administrator some flexibility in how the application was deployed. The final component diagram for the Island Hopper application is shown in Figure 10-3.
Figure 10-3. The final Island Hopper component diagram.