Back Up Next

Chapter 10: Logical Design

Certification Objectives. 1

The Value of Logical Design. 2

Organizing Logical Structures. 3

Importance of Core Principles. 5

Identifying Objects. 7

Identifying Services. 7

Identifying Attributes. 8

Identifying Relationships. 9

The Three Service Layers of the Application Model 11

The User Layer 11

The Business Layer 12

The Data Layer 12

From the Classroom.. 13

Object Refinement 15

Risk Mitigation. 15

Triggering Events. 16

Coordination Requirements. 16

Timing. 17

Common Business Rules. 17

Performance. 17

Maintainability. 18

Extensibility. 18

Scalability. 18

Availability. 19

Security. 19

Certification Summary. 20

Two-Minute Drill 21

 

Certification Objectives

·       Logical Design Basics

·       Deriving a Logical Design from a Conceptual Design

·       Deriving the Components and Services of the Logical Design for a Business Solution

·       Distinguishing between Objects, Services, and Components in a Logical Design

·       Incorporating Business Rules into Object Design

·       Articulating the Purpose of an Interface Contract

·       Constructing an Interface Contract

·       The Three Service Layers of the Application Model

·       The Benefits of the Three-Tier/Three Service Layer Approach

·       Using Paper Prototypes and Metaphors to Design User Services

·       Identifying Dependencies

·       Assessing the Potential Impact of the Logical Design

Logical design encompasses all parts of your application, including the user services or presentation layer, business services, and data services. The user requirements and business rules gathered and established in the conceptual phase of development are now ready to be mapped to a logical model. However, progressing to the logical phase of development does not mean you’re done with the conceptual phase. As you progress through the logical phase you will often find yourself circling back to the conceptual phase to gather more facts and clarify requirements. As we will see, this is just one of the benefits of logical design.

In this chapter, we will examine the process of deriving our logical model from the conceptual model. We will look at the basics of logical design and see the important role a thorough design plays in the success of distributed applications. We will examine the steps required to transform our conceptual design model into a logical design model, while incorporating the business rules and user requirements gathered in the previous phase. In the next section, we gain an understanding of component interfaces; what they are and why we need them and the contractual relationships they require. We then take a look at the structure of the three-tier services model, what it is, and why you would want to use such an architecture. Next, we will explore the presentation layer or user interface and the benefits of prototyping. In the final sections, we examine object dependencies and then assess the potential impact of our logical design.

Logical Design Basics

Logical design is the process of taking the user requirements that we gathered in the conceptual design phase and mapping them to their respective business objects and services. In this stage of development we are not concerned with the physical aspects of our design, such as where certain components will reside or how many servers are involved. Our only concern here is to create a high-level abstract model, independent of any physical model. Mapping our logical model to a physical model is the next step in development. We saw that the progression from the conceptual phase to the logical phase was not a final progression. Similarly, the progression from the logical phase to the physical design phase is an iterative process. However, the physical design should not be started until we have a thorough understanding of the objects and services that comprise our application. A premature migration to the physical design phase without a solid logical design will only hinder the flexibility of our application later on.

This high-level abstract model allows us to distance ourselves from the many details we gathered in the conceptual phase and organize them without getting bogged down in the intricacies of each particular requirement. It allows us to focus on one requirement at a time while maintaining the vision of the application as a whole. This high-level approach provides us the opportunity to gain a deeper understanding of the relationships that exist between the requirements and objects.

The Value of Logical Design

A good logical design is a critical step in correctly identifying the components, objects, and their services that were established in the conceptual model. With proper analysis, a logical model will also facilitate the development of later phases, and improve the flexibility of the application model. Thoroughly breaking out the requirements into their respective objects will allow you to design the objects in such a way that they provide only the services they need to.

Exercise 10-1 The Value of Logical Design

1.     Think of an idea for an application at work or for a client. Imagine what it would be like to simply sit down at your workstation, with nothing more than a list of what you think the application should be able to do and start developing it. Where would you start?

2.     Using this same idea, now imagine what it would be like to be handed a logical design or class diagram with all the objects for the application outlined with the methods and functionality they will contain and the relationships between them. Now where would you start in your development process?

3.     Compare these two scenarios and think about which one would allow you to be more productive with a higher probability of satisfying the end user and why.

Organizing Logical Structures

Once your objects have been identified, you need to organize them in terms of the services they provide, and the relationships they have with the other objects. There are many questions that need to be asked of the objects based on their functionality and how they interact with the other objects. We will be exploring these issues later in the chapter. For now, just remember that even though some objects may not have direct relationships with each other, they all interact with one another in some capacity and are composed of certain functionality.

Exercise 10-2 Organizing Logical Structures

1.     Think of an application you’ve written where all of your code was contained in modules (referred to as monolithic application) rather than broken out into classes or objects. How would you apply some of the principles of logical design to modify that application so that the code could be based in classes instead?

2.     Which application do you think would be easier to modify as requirements change or are added? Which would be easier to subsequently debug and maintain?

On the Job: One tool that is extremely helpful in modeling an application is Microsoft Visual Modeler. Figure 10-1 illustrates the class diagram window of Visual Modeler showing a logical design view of a sample file that ships with it. Visual Modeler is a graphical object modeling tool  included with the Enterprise Editions of Visual Studio 6 and Visual Basic 5. Visual Modeler facilitates the entire process of creating your application model from designing and organizing objects and their relationships to creating classes and generating code. Note however, that in Visual Modeler the definition of data services is not quite the same as in a distributed application. In a distributed definition, data services usually refers to the database, whereas in Visual Modeler, data services refers to your data components that will reside in the middle tier or business services layer.

 

Figure 1: The class diagram window of Visual Modeler

 

Importance of Core Principles

As you begin the preparation for logical design, there are several key considerations that also happen to be benefits of a three-tiered application design model. They are scalability, reliability, and efficiency. As you design your objects, let these factors be a driving force in the way you organize your logical structures. Although these concepts apply also to the physical design, they are equally important here, in the logical phase. How granular do you want to make your components? Will they maintain state, or will they be completely stateless to maximize scalability? What threading model will you use? How will you break your requirements into objects to maximize your object’s performance? Questions like this need to be considered here, but you must be careful not to overlap your thinking too much at this time into the physical design perspective.

Deriving a Logical Design from a Conceptual Design

Creating a logical design consists of mapping the business rules and user requirements identified in the conceptual phase, to objects. These objects, which can most readily be identified from the user requirements as nouns, also provide services. ese services in turn represent the rules and requirements of the business domain that you are modeling. It’s important to note that in the logical design phase, we are not defining technical requirements. The sole purpose of the logical model is to translate user requirements and business rules into objects and determine the type of relationships the objects have with each other.

As discussed in Chapter 9, "Conceptual Design," conceptual design is the phase of determining the functional requirements and usage scenarios for the application. The outcome is a set of documents outlining the applications background, requirements, and implementation plan. It provides the basis for the logical design phase. The logical design on the other hand will result in diagrams such as the Visual Modeler diagram in Figure 10-1. It will also include the definitions of the interfaces, or the interface contract that we shall discuss later in the chapter.

Exam Watch: Watch out for questions that try to confuse you on the differences between logical models and physical models. Keep in mind that the layout of your logical model does not correlate to a physical implementation of your application. It defines the relationships and interface contracts that exist between your objects and any external objects involved such as other systems. It does not imply any type of physical or technical implementation.

Deriving the Components and Services of the Logical Design for a Business Solution

When determining the objects necessary to support the user requirements, it’s important that you keep your objects as focused as possible. In other words, your objects should only provide services related to their intended purpose. For example, if you have a customer object it will be responsible for such services as adding new customers, updating customer information, deleting customers, and any other activities necessary to support the requirements specific to a customer as established in the conceptual phase. Therefore, the Customer object should not be doing other things such as updating inventory for a customer. Although the activity is customer-related, it should be the responsibility of, say, an Inventory object. The Inventory object, given a customer ID would in turn modify inventory data on behalf of the customer. It is vital to the flexibility of your application to keep your components as self-contained as possible. This has other benefits in that such a design will also facilitate code reuse. The Customer object, if kept modularized to performing only customer-related activities could then be reused in an entirely different application without modification. Another added benefit is that code can be developed by multiple developers in parallel, each working on separate self-contained units of logic. This modular or component-based design is easier to debug and develop since each unit can be tested for its own functionality independent of other code.

The functionality that you design into your objects is referred to as component granularity. The more activities or services that your objects support, the coarser their granularity. The fewer services your object provides, the finer its granularity.

Exam Watch: Be aware of questions concerning component granularity. Remember that component granularity refers to the number of services or methods a component has. It does not refer to a component’s properties. A component is referred to as either being coarse or fine. The fewer methods a component offers, the finer its granularity. The more methods it contains, the coarser it is. In addition, stateless components (that is components that have methods, not properties) in a distributed application are preferred. If you need to maintain component state, then you may want to investigate using the MTS Shared Property Manager as opposed to designing your components with properties to maintain the state.

Distinguishing between Objects, Services, and Components in a Logical Design

In this section, we will begin our review of the process of transforming our user requirements into their respective objects. These objects will contain services and properties, or attributes, which will represent the behaviors and characteristics of our objects.

Let’s review the basics of what we will be discussing. Objects are the things from our requirements that we are modeling. They are often identified in the requirements as nouns. For example, if you scan through the requirements from the conceptual design phase, you may notice items being discussed such as a customer, an order, or an invoice. These things (nouns) are objects. These objects will have services. Services are the objects’ behaviors, or more technically, methods of the object. They perform actions such as adding a customer, deleting an inventory item, or creating an invoice. The term component is not to be confused with object. An object and component are not the same, although you may see them referred to as such. However, an object is instantiated from a class, whereas a component is precompiled binary code.

Identifying Objects

Before we continue, let’s review a few more terms. User requirements is the list of items that the application needs to be able to accomplish. These were established in the conceptual design phase and are commonly identified by interviewing users to determine what they demand from the system. Another term is usage scenarios (also called case scenarios), which were established in the conceptual phase. Case analysis is the process of modeling how the user or users interact with the system. This can often be captured through careful observation of end users interacting with their existing systems, whether automated or manual processes.

The most common technique for identifying objects, is to pick out the objects from the usage scenarios. Although this may seem like a rather straightforward approach, it is quite likely that different people will come up with different, albeit similar, sets of objects or representations. It’s important to remember that there is no one correct set of objects. What is important, however, is to come up with a set of objects that accurately reflects the business problem at hand.

Clearly, one could get carried away and start identifying every noun as a potential object. This is not the point. In order to qualify as an object, it must posses two characteristics. It must have behaviors and attributes (that is, methods and properties). The object must also either generate information or receive information.

Exercise 10-3 What’s in a Name?

1.    Think of an application that you’ve been involved with in the past. How did you pick names for code modules or classes?

2.    In hindsight, if you could rename these modules or classes, would you name them differently? Why?

Exercise 10-4 Identifying Objects

1.     Think of something that you use and depend on every day. What are the objects associated to using this object? What are the methods and properties? For example, think of your car. It has an Engine object with methods such as accelerate and decelerate. It also has properties such as temperature and fuel level.

2.     Think of some other ordinary objects you interact with every day and try to break them down into objects.

Identifying Services

Services are an object’s behaviors. These behaviors are the actions that they perform and are executed through the use of methods. The process of identifying services is very similar to the method we used to identify the objects in the previous section. Here again, we’ll look through our usage scenarios. However, now we’ll be looking for verbs instead of nouns. Verbs will help identify the actions that our objects need to perform. These in turn will be translated into methods or services. Again, as in identifying objects, one could get carried away with picking out all the verbs. What is important is to focus on the business-related actions. In addition, not all objects will have services or perform any actions. Some will simply be providing data. We’ll discuss this in the next section when we look at identifying attributes.

When identifying services, keep these points in mind: Is the action initiated from within the application or is it the responsibility of another system? Make sure that the action can be associated to an object. In other words, will this action be performed by an object you identified or will it be the recipient of data from this service? And lastly, use only active verbs.

Exercise 10-5 Identifying Services

Using the object or objects from Exercise 10-4, list the services that they provide. For example, using our Car object, we said that the Engine object had accelerate and decelerate methods. What else do these objects do? What other actions do they perform?

Identifying Attributes

Attributes, also known as properties, are things your object knows. It’s the data that’s associated to the object. Attributes, which I’ll refer as properties, are also things that other objects need to know about and that help establish the relationship between objects.

For example, a Customer object will have properties such as name, address, and customer ID. These are things it knows about itself. It may also have a property that allows another object to know about it. For example, this customer may have multiple addresses. The Address object that stores addresses for all customers will need to associate its address data with a customer and will therefore need to know the customer ID of the data it’s storing.

To assist in identifying these properties, we return to our usage scenarios and list of requirements. What items need to be tracked? These will be the things that our objects need to know about and remember. Each item that needs to be remembered will become associated to an object as a property or attribute.

Exercise 10-6 Identifying Attributes

1.     Continuing with our car example, identify some of the properties it has. For example, our Engine object has properties such as fuel level, engine speed, and temperature. What other properties might it have?

2.     In preparation for the next section on object relationships, think about what properties our Car object might have that other objects may need to know about.

Exam Watch: Remember, we’re designing distributed components and these components should be stateless. In the context of a distributed environment, attributes, which are nothing more than properties of an object, become arguments to a method call. You no longer set an object’s properties by making property calls. Instead, you pass them as arguments to a method, which in turn updates the object’s properties all at once. Not maintaining state increases scalability.

Identifying Relationships

The objects you have identified thus far in the logical design phase have certain types of relationships with the other objects in the logical model. Identifying relationships between your objects involves once again reviewing your usage scenarios and user requirements. Pick out the nouns and/or objects you identified and note the verbs and other connecting phrases between them. Table 10-1 lists the three major types of relationships objects can have and provides a question to ask to assist in identifying the relationships. The relationship types may have more than one name, as noted in the first column of the table.

Relationship

Description

Question

Ownership/Container

Commonly referred to as a parent-child or one-to-many relationship. This is where one object owns or contains another type of object. This is perhaps the most important and common type of relationship. They are used to implement object collections. For example, an Invoice object will contain or own InvoiceItem objects. Therefore, the Invoice object has an InvoiceItem object, and the InvoiceItem object is owned by the Invoice object.

Does this object belong to another object or is it owned by another object? Does this object own or contain any other objects?

Generalization/Subclass

In this type of relationship, an object is a specific type of another object. These are often identified when different objects have similar properties. Often they can be combined, and one general object can be developed. For example, you may have a Server object, a Workstation object, and a Laptop object. They all share similar properties and can therefore be combined into one Machine object. Then, you can implement a Workstation object that uses only the properties specific to a workstation.

Is this object a type of another object?

User/Collaboration

This is where objects employ the services of other objects. They aren’t a specific type of another object nor are they owned by another object. They simply rely on some other object’s specific functionality or service. For example, a Car object might use a Fuel object to refuel. This Fuel object could also be used by a Truck object. Using our previous example, the Car and Truck objects could themselves be a type of MotorVehicle object.

Does this object use another object? Is this object used by another object?

Table 10-1: The Three Major Types of Relationships Objects Can Have

Exercise 10-7 Identifying Relationships

1.     Using the Car object example, recall the objects you identified in Exercise 10-4. What objects have relationships? Do they all have relationships?

2.     List the object relationships and identify the type of relationships they have. Don’t forget to combine similar objects when possible into one general object. Refer to Table 10-1 if necessary.

Incorporating Business Rules into Object Design

Business rules define the logic of how data is manipulated by your components. These rules mirror the way the business domain you are modeling operates or does business. Implementing the business rules and processing in business objects has three major benefits. Objects designed this way have the following characteristics:

·       easier to maintain

·       easier to enhance

·       easier to reuse

The majority of this business logic should be implemented in the middle tier or business

layer tier more specifically as we will explore later in the chapter. The reasons for this are simple. Implementing the business logic in the middle tier allows developers to easily change and update the components as the needs of the business change without impacting the database or client application. Things such as validation edits can be placed in the presentation layer to make the client application more dynamic. In addition, some rapidly changing rules. for say a web-based application. may be more appropriately implemented in the interface itself to facilitate updates to changes.

What objects you place the business logic in depends on the purpose of each object. For the most part, objects should be as self-contained as possible. By keeping an object’s functionality limited to specific services, it allows the component to specialize and therefore be more reusable, both on a code level and component level.

Articulating the Purpose of an Interface Contract

The COM (Component Object Model) establishes a standard by which objects communicate with one another. It describes a format in which COM servers expose their interfaces and how clients locate and use them. Interfaces are the methods that the object exposes and are the gateways of communication between objects. They are what allow objects to communicate with one another and exchange data. Without these interfaces, objects would not know how to request or provide services to one another. An interface therefore represents a contract between a client component and a server component.

Once the interface for an object has been established, and other objects rely on the known interface, it must be immutable. Changes to an object’s internal implementation can occur as long as the interface to access this functionality remains unchanged. If the interface is changed, then client components that use the existing interface will break. If new functionality is needed in the component, it is usually best to implement it by adding an additional interface to the component.

Constructing an Interface Contract

An interface contract is a declaration of any preconditions for using the service, and the calling conventions. Preconditions are conditions that must exist prior to using the service. For example, a database with certain tables may need to exist in order for the service to return the requested data. Calling conventions consist of the syntax to employ the service, the input parameters it accepts, and the output parameters the service will generate.

The definition of the interface should be published before implementation of it has started. This allows development against this interface to proceed as a black box, without having to know anything about the internal implementation of the services. This provides a consistent standard to develop against. Once this interface is published, it becomes a contract between the client and the service and cannot change even though the internal implementation of the service may change.

The Three Service Layers of the Application Model

In this section, we examine the three service layers. These layers are based on the services model, which is a way of designing an application as a set of specific functionality that is used to fulfill client or consumer requests. By modeling the application this way, a higher level of reuse can be achieved through better code and component reuse. The service’s definition is the contract between the service and the client. It is this contract that allows for increased reuse and a more consistent development environment.

The three categories of services in the typical three-tier application are shown in Table 10-2. We will explore them in further detail in the remaining sections.

Service Layer

Description

User Services

Also called the presentation layer. It is where the user interface is implemented.

Business Services

Where the business rules and logic are implemented.

Data Services

Where data is stored. Defines the storage and retrieval of persisted data.

Table 2: Categories of Services in a Three-Tier Application

Figure 10-2 below, illustrates the relationship of the three service layers.

 

Figure 2: The three service layers

The User Layer

The user layer is the interface of the application. It provides the visual representation of data collection and display. In this layer, the interface is divorced from any implementation of

the business logic with the exception of perhaps some validation edits. Although these edits could be implemented solely in the business layer, duplicating this logic in the user layer can make for a richer and more interactive interface. The user layer will provide for immediate feedback of the validation. If this logic is implemented only in the business layer, the user will not receive any feedback until the data is saved via the appropriate service.

By excluding business logic in the user layer, we allow our business layer components to be more self-contained and therefore more reusable and maintainable.

The Business Layer

The business layer is where all of our business logic and rules are contained. They are encapsulated in the business components and are responsible for servicing the requests from the user layer. They act as the liaison between the data layer and the user layer. When the user layer executes a business task, the business layer is responsible for accessing the data layer and retrieving or saving the data with the appropriate business rules being applied or enforced.

Because business rules can change, encapsulating them in components that reside in this layer allows for changes to occur without affecting the user layer or data layer. In addition, business rules that are subject to frequent changes could also be placed in scripts, for example, in the case of a web-based application. However, this implementation does not provide the protection that compiled components do from prying eyes since you could view the script’s source code in the browser window. For example, say you have a service called “Calculate discount” which determines the discount provided to a customer depending on various factors such as buying patterns and the amount of revenue this customer has generated. If the decision is made to change the rules or logic that determine the amount of the discount, only the component needs to be updated. The user layer remains unaffected since this logic is encapsulated in only this one component. Now, the next time the “Calculate discount” method or service is called by the client application (user layer) it will receive the newly modified service. This is also an example of where the interface or interface contract remains static, but the service’s internal implementation changes to either improve performance or adapt to changing business rules.

The Data Layer

The data layer is responsible for maintaining, accessing, and updating data based on requests from the business layer. These services may consist of one single data store such as SQL Server or some other database, or they may be comprised of a variety of sources. For example, to fulfill a client (user layer) request, the business layer may be requesting data from the data layer that actually resides in a database, a mainframe computer, and a collection of other non-heterogeneous databases. However, none of this is important to the user layer; all it’s concerned with is using the business layer to request services.

By separating the data layer from the rest of the application, it allows changes to be made to the data layer without affecting the user layer or business layer.

Exam Watch: Remember, the data layer is not where your components will reside. Your components will reside in the middle tier, or business layer. The data layer is concerned with the storage and retrieval of your data into some sort of data storage device such as an RDBMS like SQL Server. Also, recall from earlier in the chapter that Microsoft Visual Modeler will display your components in a data services section, but this is not the same as the data services (layer) in a distributed application model.

The Benefits of the Three-Tier/Three Service Layer Approach

Encapsulating and separating the functionality of the user interface, business logic, and data services into their own layers provides several benefits. As we have seen so far, this separation allows changes to be made to the individual layers without affecting the other layers. There are other benefits. Due to COM standards, application components are language independent. In other words, they can be developed using any language as long as the language generates interfaces that adhere to COM standards. Components can be run on a central application server to ease development, deployment, and maintenance. Or, the components can be run on several application servers to spread the processing load to achieve better scalability. This is referred to as load balancing.

Database connections and resources are utilized more efficiently since the database is interacting with only the application components and not all of the clients. Typically in a two-tier application when a client connects to the database it connects early, when the user first logs on to the system and the connection is held until the client logs off. Conversely, in a three-tier application the component is responsible for the connection management and typically connects late or only when needed and then releases the connection. On this note, database drivers such as ODBC drivers are no longer required on the client workstation, reducing client setup and maintenance issues.

Security is enhanced and simplified since access is done on a component basis and not by all the client applications. The middle-tier components are accessing the resources and therefore can be controlled more easily.

Accessing resources external to the application also becomes simplified, as this can be encapsulated within an application component. Now, external resources become application components in the eyes of the client application. Such details are now transparent and can be modified with no impact on the other layers.

As we can see, there are many benefits to designing an application in accordance with the three-tier/three service layer approach. Although it may involve more up-front design and planning time, the long-term benefits of easier maintainability, reuse, and scalability far outweigh those costs.

From the Classroom

Logically Speaking

The transition from the conceptual phase of application design to the logical phase provides the basis for all development efforts that will transpire from that point on in an application development project. Developing a strong logical design will not only reveal potentially large development pitfalls which can then be successfully navigated past, but will also provide a roadmap for developers joining a project later on and needing to come up to speed quickly.

Designing components as both stateless and of a sufficiently fine granularity are highly recommended factors that should be design considerations established or initially supported during the logical design phase. Knowing that any components designed to run within MTS should be stateless, for example, should initially be enforced within the logical design phase. Establishing a sufficiently fine granularity in provided services on a per component basis starts with the logical design phase. Simplicity in component design can yield increased reusability, scalability, and extensibility.

In designing components during the logical phase, a strong correlation can be made between the process of denormalizing a database schema and the identification and design of components. For example, a customer's address can be simultaneously modeled logically as Customer and Address objects and in a database as Customer and Address tables, which are connected through a foreign key.

Following a proper three-tier distributed application development methodology can provide large increases in overall scalability and reusability of code components. It is important to understand the separation of user services, business services, and data services when designing an application. Spending the necessary time on the logical three-tier design aspects will be well worth the effort.

by Michael Lane Thomas, MCSE+I, MCSD, MCT, MCP+SB, MSS, A+

Using Paper Prototypes and Metaphors to Design User Services

The user interface is one of the most visibly important aspects of the application. This is the part that users can actually see and touch. They interact with it on a daily basis to perform their tasks. It doesn’t matter how technically advanced or sophisticated your application is or even how fast it is. If your users don’t like the interface and find it difficult to work with because it’s not what they wanted or expected, then your application is a failure. Fortunately, using a three-tier approach affords you much flexibility when it comes to designing the interface. By using a component-based architecture, you could potentially have multiple user interfaces developed using a variety of technologies. For example, you could have a Visual Basic- or Visual C++-based interface, a web-based interface using Active Server Pages (ASP) and HTML, or even a Microsoft Office-based interface using components like Word and Excel.

However, understanding what the users want and how they will interact with the interface is often difficult to ascertain. This is where using common metaphors that are readily understood, and prototypes come in. It’s possible to use the RAD features of development tools such as Visual Basic to design a quick and dirty prototype, but most often using a simple paper-based prototype and examples of screenshots is easier, at least for the initial stages. It’s easier to develop and it’s easier for the end users to understand and work with.

Designing paper prototypes does not have to get overly fancy. As long as it conveys the goals of the user identified in the usage scenarios, and the users are satisfied and everyone agrees on things such as screen layouts and application flow, then these paper prototypes can be converted into an interface design document and used as the basis for the real thing. Use common metaphors when working with paper prototypes. Don’t use computer jargon to explain application functionality to users. Use phrases such as “add an inventory item to the stock” and “add a customer to the customer list” instead of “create inventory item” and “add customer.” Users will have an easier time understanding and relating to tasks when explained in everyday terms.

On the Job: Depending on your tool set and the environment in you are developing for, whether it’s a traditional windows application, or a web-based application, you may find that it is often easier and more productive to do your prototyping with something other than the tool you are developing in. Fox example, Microsoft Excel makes screen mock-ups a snap. Also, they’re easy to distribute to end users involved in the design process and to most people are familiar with Excel. This facilitates the design process and can alleviate some of the burden from you as the developer because your end -users will be able to modify the mock-ups directly. This can often be an easier way for them to communicate their UI preferences as opposed to a verbal or textual description. As an added bonus, I find that one of the thorniest aspects to prototypes is reports. Users can’t always tell you what they want, but they can usually show you!

Object Refinement

As developers and end users work with the initial prototypes, it provides the opportunity to work through the usage scenarios developed in the conceptual phase. It allows the usage scenarios to be mapped to the actual tasks via the interface that users will be interacting with. This process will undoubtedly reveal changes that need to be made in the logical design of the business objects. This is not a sign of incomplete analysis, but rather a normal process because the whole application design phase is an iterative process.

This prototype phase allows us to validate and refine the initial set of business objects we developed from the usage scenarios and requirements list. In terms of validating our logical design, it’s important that for each usage scenario identified there is a corresponding object service that will perform the activity. Equally important is to make sure that every object and service listed in our logical design can be mapped back to a usage scenario. If they can’t, then they may be unnecessary.

As we mentioned, the first set of objects identified is usually incomplete and sometimes incorrect. There are some things to look for when refining your object design. Objects should be specific and unambiguous. If the object is irrelevant to our application or beyond its scope, it can be omitted. Look for redundancy. Sometimes objects will share similar properties and can be combined into one object. Some properties may actually need to broken out into their own business object.

Exercise 10-8 Object Refinement

1.     Let’s assume you’ve identified the following objects from a list or requirements: a Customer object, a Prospect object, and an Employee object. Which objects can be combined and why?

2.     While working with your end users on an initial prototype, you realize that there are several tasks they would like the system to be able to perform that were not identified in the usage scenarios you used to develop your initial set of objects. How do you proceed?

Risk Mitigation

Following a methodical and structured, yet iterative, approach to logical design is the best way to assure a successful logical design that correctly reflects the application’s requirements, and will allow a successful physical implementation.

Perhaps the major source of risk in logical design is usage scenarios that aren’t represented by an object and service, and conversely, objects and services that can’t be traced back to a usage scenario. When this occurs, the conceptual view and logical view are no longer synchronized. Other risk factors to avoid are a lack of coordination with corporate development standards and architecture. If your logical design does not adhere to or correspond to the corporate development standard, it may make it more difficult to integrate your application. If your logical design is dependent on external systems, it is likely to be impacted when and if those external systems are modified.

Exercise 10-9 Risk Mitigation

1.     You have integrated a feature into your logical design because it’s new technology and you think it’s cool. Do you think this poses any risk? If so, to whom?

2.     Your logical design relies on an external system for some relatively static data that will be used for monthly reporting. How might you design your application to eliminate the risk to your application if this external system is modified?

Identifying Dependencies

Dependencies can arise between your business objects as you progress through the logical design phase. Although it’s desirable to design your business objects so that they are as self-contained as possible, this is not always possible. Therefore, you must take into account these dependencies. Some dependencies are based on the nature of the relationship. For example, an Orders object would assume the existence of a Customer object, which would use the Orders object’s services. In this example we could say that the Customer object “has” an order or conversely, the Orders object is “owned” by a Customer object. We looked at these types of relationships earlier in the chapter. It’s important to identify these dependencies and redesign the object so that these dependencies are minimized by abstracting services that are likely to change often into their own object. Minimizing dependencies to the extent possible, will ease component maintenance when business rules change.

 In this section, we’ll examine various aspects of these dependencies. First we’ll take a look at how objects can trigger events in response to activities. Next, we examine the steps required to coordinate object dependencies and how timing can affect them. And lastly, we explore common business rules and how to best accommodate them in your design.

Triggering Events

Business objects have services and attributes (methods and properties). In addition, objects can also trigger events in response to certain conditions. These conditions may exist as a result of a particular method call or service being invoked, or they may be the result of a particular property being set.

Events provide a form of notification that lets the client application or calling object know that something has occurred or informs them that a service they invoked is now complete. For example, as a result of calling a delete inventory method on an object, the inventory level may fall below the minimum stock level. This may fire a trappable warning event notifying the calling object or the client application. It may even be an external system that could receive this event.

Coordination Requirements

Because objects can have dependencies upon one another, either through the type of relationship they have or more indirectly through events, it’s important to anticipate and account for these dependencies in your logical design.

These dependencies may be presuppositions of certain conditions. We saw this in our example in the previous section with the Orders object relying on a Customer object to consume its services. Taking this one step further, the Orders object and Customer object may both depend on the existence of a database table to persist their information. All of these dependencies, albeit somewhat implicit, must be accounted for and clearly documented in the logical design.

Timing

The subject of timing relates to how the order in which dependencies are invoked. Each dependency between objects that you have identified in your logical design will have an order of invocation. In other words, there is a logical path of dependency that must be adhered to in order for the objects to function as expected. Using our Order and Customer objects again, there is an issue of timing here as well. An order cannot be placed for a new customer until there is a valid customer. Likewise, a customer cannot be deleted if it has outstanding orders. 

Common Business Rules

There may be objects in your logical design that use the same business rules in their services. These business rules are prime candidates to be abstracted into their own encapsulated object or objects. By abstracting these common business rules into a common business object, you minimize the impact on your application when these rules change. As with the design of your other objects, try to keep these new objects as self-contained as possible and anticipate which rules will be the most dynamic or subject to change in the future, and put them in their own object.

By abstracting common business rules into self-contained objects, you can avoid having to make changes to multiple components when the business logic for a service changes.

Assessing the Potential Impact of the Logical Design

In this section, we explore the potential impact of the logical design on various aspects of a distributed application and the characteristics that define a distributed enterprise application. These same attributes also determine the level of success achieved once the logical model has been implemented physically and the application is in use. In today’s business environment, it’s critical that a high level of success is achieved in each of these aspects.

We’ll begin by looking at the issues surrounding performance. Next we examine the areas of application maintainability, extensibility, scalability, and availability. Finally, we look at the issues of security and how they relate to a distributed component environment.

Performance

Forecasting the performance of a distributed application can be difficult. Therefore it’s necessary during the logical design phase to design your application with this in mind. It’s important to look at all layers of the three-tier model to ascertain the impact on performance. Some items to review would be the following:

·       What type of interface is being used? And are the target workstations capable of running this efficiently?

·       What language will be used to develop the components?

·       What type of data store is being used? Will it provide adequate performance?

·       How many users are anticipated? Can the network handle the throughput?

·       Where will the application components reside? On the workstations or on an application server in the middle tier?

·       Have all the objects been consolidated to remove any redundant objects and business rule processing?

Maintainability

Application maintenance is as important as any other part of the development cycle. A lack of planning can have serious negative implications later in the cycle when it comes time to modify the application. Designing objects that are well thought-out and as self-contained as possible will provide for easier modification when it comes time to change the implementation of a service or the logic in a business rule. This also applies to the user interface. Building a solid foundation of self-contained and well organized objects will allow for the development of multiple interfaces if necessary.

Extensibility

Does the logical design you’ve developed lend itself to being extensible? In other words, in addition to being maintainable, is it possible to add additional features to the application and its components without impacting other parts of the application? Remember from our discussion on interface contracts that your components will rely on other components and consume their services through their interface. Part of being extensible is being able to add functionality without breaking existing functionality. Depending on whether you are making changes to the internal implementation of an existing service, or adding additional services, will play a key role in how this functionality is added. If you are adding new services, it is best to add an additional interface to the component as opposed to changing an existing one and breaking any component that currently relies on it. If you’re simply modifying the internal implementation of an existing service, then all you need to do is update the component with the new one. That’s the benefit of a distributed component design.

To the extent possible, try to anticipate future needs and design them into your initial logical design.

Scalability

Scalability is how well an application performs as the number of users increases. Scalability is critical to handling the large volumes of requests made on a system in an enterprise environment. You can increase scalability to a limited extent by throwing more powerful hardware at a poorly designed application. This is limited however, and is by no means a substitute for proper application design. When an application is properly designed and the only change necessary to handle more users is to increase the capability of the hardware, the application is considered scalable.

There are several factors to keep in mind during logical design that will contribute to a more scalable application. Since this is a distributed application, chances are your components will be running within some sort of object broker such MTS (Microsoft Transaction Server). MTS provides several features that increase the scalability of your components. By using MTS you can take advantage of such features as connection pooling. This allows your components to connect to data sources using a previously established connection. This dramatically reduces the overhead and wait time associated with connecting to a database. This can also be taken advantage of further by making sure your components request a connection on an as-needed basis, only when necessary, and then release it as soon as it is done with it.

Object pooling (not supported in this version of MTS 2.0) will allow your components to be recycled. In other words, MTS will take the component from a pool of available objects, if any exist, saving the overhead of COM instantiation; otherwise it will create a new instance of one. Currently, MTS creates objects on a just-in-time basis when the component is requested by a client. When the client is finished accessing the components method(s), it calls the MTS interface IObjectContext method SetComplete or SetAbort to instruct MTS to deactivate the component. This resets the component’s internal variables to nothing and removes it from the server’s memory while the client still holds a pointer or reference to it. The client can then call another method on the object, in which case MTS reactivates the object. As far as the client is concerned, this is the same object it used before.

Your objects can further take advantage of MTS by developing stateless components. Stateless components do not maintain state between method calls and call either SetComplete or SetAbort after each method call. This will allow MTS to activate and then deactivate the component more quickly. This allows for fewer server resources to be consumed and for a shorter amount of time, contributing to overall scalability.

Availability

How well your components perform and handle unusual exceptions will contribute in some part to the availability of the system. In component terms, this would be referred to as its robustness. Your components should anticipate errors and other unexpected scenarios and handle them gracefully through error handling; ideally without affecting the state of the application or other components, and without corrupting data. As we mentioned in the previous section when we discussed scalability, MTS also provides protection against data corruption through the use of transactions. MTS provides full two-phase commit transaction services and handles the complexities for you. By enrolling your components that comprise a transactional unit into an MTS transaction, you are guaranteed that your components will either succeed as a unit in modifying the target data, or fail as a unit. MTS provides the transaction management infrastructure allowing you to focus on the business services and robustness of your component.

Security

There are many options when it comes to implementing security. The exact configuration you choose depends largely in part on the application and the environment in which the application will run. Your application must provide protection for the application components, the data store, and it must ensure privacy of data for your users.

In terms of securing your middle-tier components, you can use DCOM (Distributed Component Object Model) for authentication. If you decide to use MTS for any of the reasons we’ve discussed, then you can also use MTS to handle authentication of the middle-tier components. Connections made to a data store such as SQL Server will be made through your middle-tier components. Depending on the identity that these components are running under, you have several options for authentication with SQL Server.

You can use SQL Server’s standard security, which will log the component in with a standard SQL login, or you can use integrated security and map NT logins to SQL logins taking advantage of the NT security model. In addition, MTS provides role-based security for the secure activation of packages. MTS packages are a group of related components. With role-based security or as the documentation refers to it, declarative security, roles are defined for the package through the MTS Explorer and allow you to assign various levels of access to components and methods within the package based on these roles. Roles are then assigned NT users and/or groups of users. When components within the packages are requested by a client during runtime, they are subject to the security granted to the role of the package.

Certification Summary

The process of logical design involves mapping the user requirements gathered in the conceptual design phase to business objects and services. This high-level abstract model allows us to focus on the overall vision of the application and see the many aspects of the application in a more organized fashion. A solid logical design is critical in correctly identifying the required objects and facilitates development of later phases.

The objects and services required in the logical phase can most easily be identified from the user requirements and usage scenarios by identifying the objects and verbs, respectively. When identifying the necessary objects, keep them as self-contained as possible. A component’s functionality is referred to as its granularity. It can be coarse or fine. If it’s coarse, it contains many methods. If it’s fine, it contains few methods.

The most common technique for identifying objects is to pick out the objects from the usage scenarios. There is no one right set of objects. What’s important is that they reflect the business domain you’re modeling. To identify the services of the objects, pick out the verbs in the usage scenarios. The properties or attributes of the object are what it needs to know and what information needs to be tracked. Objects have the following three types of relationships: ownership (owns or has), generalization (is), and user (uses).

Business rules define the logic of how data is to be manipulated by the objects in your logical design. Placing business logic in components allows the rules to be easily modified without impacting the rest of the application.

Interfaces are an agreement between objects or client and server as to how a service is to be consumed. Once defined and published, they become an immutable part of the service. An interface contract is a statement of any preconditions for using the service and the calling conventions of the service. The calling conventions detail the syntax, input parameters, and output parameters.

The three service layers consist of the user layer, business layer, and data layer. The user layer is responsible for the presentation of the application or user interface. The business layer is where the components that contain the business services reside and the data layer defines the storage of persisted data. Benefits of a three-tier/three service layer approach include component encapsulation. Business logic or services can be altered within one component without affecting other components. Middle-tier components can take advantage of pooling of database connections, can be run on a centralized application server to achieve load balancing, and ease maintenance and deployment. Security is enhanced and simplified, along with access to external systems.

Building paper prototypes allows developers to work through the usage scenarios developed in the conceptual phase and begin to validate the logical design. At this point, object refinements will be discovered. Logical design risks are reduced since there is a validation process of mapping the logical design to the conceptual design and vice versa. The major source of risk is when the logical design and conceptual design do not agree.

Some object dependencies are based on implicit relationships such as an ownership relationship. However, minimizing object dependencies to the extent possible will help ease component maintenance when business rules change, particularly in relationships with external systems. Consolidating common business rules into self-contained objects will help avoid making changes to multiple components when the business logic for a service changes.

There are many factors to weigh when assessing the impact of your logical design. To achieve success, your application must be efficient, maintainable, extensible, scalable, reliable, and secure. Taking these factors into consideration early in the development of the logical design phase will help assure that the application successfully meets these criteria.

Two-Minute Drill

·       Logical design is the process of taking the user requirements that we gathered in the conceptual design phase and mapping them to their respective business objects and services.

·       Once your objects have been identified, you need to organize them in terms of the services they provide, and the relationships they have with the other objects.

·      Visual Modeler is a graphical object modeling tool included with the Enterprise Editions of Visual Studio 6 and Visual Basic 5. Visual Modeler facilitates the entire process of creating your application model from designing and organizing objects and their relationships to creating classes and generating code.

·       As you begin the preparation for logical design, there are several key considerations that also happen to be benefits of a three-tiered application design model: scalability, reliability, and efficiency.

·       The functionality that you design into your objects is referred to as component granularity. The more activities or services that your objects support, the coarser their granularity.

·       Objects are the things from our requirements that we are modeling.

·       Services are the objects’ behaviors, or more technically, methods of the object.

·       The term component is not to be confused with object. An object and component are not the same, although you may see them referred to as such. However, an object is instantiated from a class, whereas a component is precompiled binary code.

·       User requirements is the list of items that the application needs to be able to accomplish.

·       Case analysis is the process of modeling how the user or users interact with the system.

·       Services are an object’s behaviors. These behaviors are the actions that they perform and are executed through the use of methods.

·       Interfaces are the methods that the object exposes and are the gateways of communication between objects.

·       An interface contract is a declaration of any preconditions for using the service, and the calling conventions.

·       Preconditions are conditions that must exist prior to using the service. For example, a database with certain tables may need to exist in order for the service to return the requested data.

·       Calling conventions consist of the syntax to employ the service, the input parameters it accepts, and the output parameters the service will generate.

·       The user layer is the interface of the application. It provides the visual representation of data collection and display.

·       The business layer is where all of our business logic and rules are contained. They are encapsulated in the business components and are responsible for servicing the requests from the user layer.

·       The data layer is responsible for maintaining, accessing, and updating data based on requests from the business layer.

·       Scalability is how well an application performs as the number of users increases. Scalability is critical to handling the large volumes of requests made on a system in an enterprise environment.

·       Object pooling (not supported in this version of MTS 2.0) will allow your components to be recycled.

·       How well your components perform and handle unusual exceptions will contribute in some part to the availability of the system. In component terms, this would be referred to as its robustness.