"When designing an application, you first have to determine the specific business problems you're trying to solve. When you've identified these problems, you have to determine the functional requirements. For example, you might create use cases and scenarios help clarify what an application needs to do from a user's perspective.
"You also need to outline the business objectives and non-functional requirements associated with your application. Business objectives are often the priorities you need to focus on. You must also support an expanding number of clients and have systems in place to handle the growing number of calls. The business objectives can give you performance information and requirements that tell you what you need to do to satisfy the customers who will use your application. You might also be faced with significant financial constraints in running your application; for example, customers with fewer resources might have to use their existing computers or be able to upgrade only to less-expensive systems rather than more costly ones. You might also encounter platform conflicts between client and server; for example, an organization might be running Windows 2000 on server computers and Windows 98 with Internet Explorer 5.0 on client computers. Operating system conflicts such as this one could heavily impact your application design. Your application's development could also be affected by your customer's choice of Web browser; for example, Netscape Navigator or Internet Explorer.
"The primary non-functional requirement is performance. Often developers want fast, optimal performance in their applications, so they set high performance requirements. In reality, it's a good idea to consider the specific response time that users expect. Also, you should gauge the number of clients needed and the amount of time the system needs to be available for the application. This information should have actual numbers, so the system performance can be tested against the build requirements. In this way, particularly with components, you can build a prototype application, do some testing, determine the location of bottlenecks, and then selectively tune or optimize the application's implementation to meet performance requirements, rather than blindly optimizing everything.
"Other constraints or requirements that you need to watch for concern deployment. You rarely have the opportunity to build an application completely from scratch. Usually, you need to communicate with an existing database or even multiple databases and existing applications. These databases and applications are going to operate on certain computers and communicate in certain ways with the computers. In most cases, you may not be able to change them.
"Topology constraints may also hinder an application's development. What type of network do you have? You may not have the flexibility or control to change the network or Internet connections to accommodate your application. Rather, you must make your application accommodate the topology.
"Security is another important non-functional requirement, involving protecting access not only to a particular program, but also to data. For example, are there certain types of data or certain rows of data in a database that no one should have access to? If so, you want to say that these particular user accounts and the detailed information in them can only be accessed by the account manager for those accounts. If you're the account manager for some other account, all you can do is get a summary of the information—perhaps the name of the account and who the account manager is. But you can get detailed information about your own accounts. Another way to restrict access is to say that a particular person is not allowed to modify information, but they are allowed to read it.
"Another question you need to ask yourself is whether the data needs to be protected in some way, such as with encryption. Are there any constraints on passing the information around in the normal, human, readable form? For example, you might not want to pass credit card numbers around as plain text. Instead, you might want to encrypt it in some fashion. The system can do that at a low level—for example, using RPC packet encryption—but those methods have a high overhead, and it's difficult to specify them with a fine granularity in the COM+ programming model. At the application level, you can specify that, for this interface, this particular method will be encrypted, and here's what you have to do to un-encrypt it before you can use it. So in some cases, it's much better to do this type of data protection at the application level, where you can define it as part of the contract between a client and a component, than it is to rely on the underlying infrastructure to just blindly protect all the data that's going across the network.
"You should also think about how the work of the application is divided up into transactions and workflows. Does a particular sequence of things have to happen in a particular order? What triggers the end of one operation and the beginning of another? Do some things need to happen as a unit? For example, if I'm making a withdrawal or transfer from my account in my bank, I want to make sure that, when I make a payment, money both comes out of my account and goes into the payee's account. I don't want money to be taken from my account and not to go anywhere. If it doesn't make it to the payee, I want to make sure it doesn't come out of my account either.
"It's important to think about the information that has to be treated as blocks, even when you are at a high or abstract level of design. Why? Because you don't have ultimate flexibility when it comes to specifying some of these constraints on a per-method or a per-method call level. So you need to think about the transaction requirements of particular methods, and about how they group together, when you're figuring out what methods go in a particular interface, what interfaces go in a particular component, and what components get packaged together. Even though these requirements aren't directly tied to any particular scenario, they end up impacting your design.
"After you've defined functional and non-functional requirements, you can begin modeling. You can also start to consider which logical objects you will include in your system, how these objects will fit together, which objects you can store, and which services you'll use to build your application. When you've got an idea of the core concepts and how they work together, you can refine them until you have defined components that you can implement.
"I know that many of you use object technologies, as well as object-oriented analysis and design, to logically model a problem. Although these techniques are perfectly acceptable, object-oriented analysis and design are not always ideal for designing components. Typically, when you perform logical modeling from an object perspective, you focus on the concepts and elements of your system. You also determine how these concepts and elements operate.
"When you examine your model from a component design perspective, you're typically performing a more service-oriented analysis. It's not always easy to judge exactly which objects ought to own a service. Several objects can work together to determine how to implement a particular service. So when you're doing a pure object-based design, you can lose sight of how certain objects might be grouped into components. In other words, you shouldn't always try to elicit a pure object-based model, because you will have to change it when you begin to build your COM components.