At a higher level, the architecture of an application results from the process of building a system from a variety of disparate components (some of which may themselves encompass design patterns) and making sure that those components come together in a flexible, maintainable, scalable, secure, and efficient way. In framework applications, architecture typically comes together through answering questions such as the following:
Should I use DataSets or DataReaders?
Should I use XML Web Services or .NET Remoting?
Should I use Windows or Forms authentication in ASP.NET?
Is multithreading necessary for this application?
Should I store data in DataSet objects or custom classes?
Where should I place domain logic?
Do I need to support multiple database back ends?
Should I use a Web or Windows UI?
How should I validate data?
How do I handle exceptions?
The answers to these questions and many more like them aren't always obvious, and the nature of the questions implies that there are multiple possible solutions and no "best way" in all cases.
Just as with design patterns discussed previously, these decisions (and parallel decisions made on non.NET platforms) are ones that have been made many times over. As a result, you can benefit from the work of others who have collected architectural patterns and best practices that encapsulate many of these decisions. Two primary resources for framework developers include Patterns of Enterprise Application Architecture, by Martin Fowler (Addison Wesley Professional, 2002), and Application Architecture for .NET: Designing Applications and Services, posted on the MSDN Web site. In addition, Microsoft has collected a variety of architectural resources, including reusable code, Webcasts, and articles on its .NET Architecture Center Web site. I highly recommend that you obtain these resources if you're designing framework applications.
The Fowler book, in particular, is very helpful in fostering a common design vocabulary; it includes code examples in a variety of languages, including C#. In all, Fowler documents 51 patterns and, like the GoF, collects them in 10 higher-level groups:
Domain logic patterns. Define common approaches for organizing business logic, such as Transaction Script and Domain Model.
Data source architectural patterns. Patterns used to represent data within an application, such as Table Data Gateway and Data Mapper.
Object-relational behavioral patterns. A set of patterns that address the behavior of objects, including Lazy Load and Unit of Work.
Object-relational structural patterns. Patterns that deal with the structure of individual objects, such as Identity Field and Foreign Key Mapping.
Object-relational metadata mapping patterns. Patterns that address how relational data is mapped to objects and include patterns such as Metadata Mapping and Query Object.
Web presentation patterns. Patterns that implement the presentation for a Web site and include Front Controller, Page Controller, and Template View, among others.
Distribution patterns. Patterns that address how objects can be used remotely and include Remote Facade and Data Transfer Object.
Offline concurrency patterns. Patterns that are concerned with how multiple users update the same data. Several of the patterns are Optimistic and Pessimistic Offline Lock.
Session state patterns. Patterns that deal with how session state is handled in a Web application, including Server Session State and Database Session State.
Base patterns. Patterns that are used throughout the other patterns and include such ubiquitous patterns as Layer Supertype and Service Stub.
As an example of how these patterns are related and how they differ, consider the diagram shown in Figure 2. This diagram depicts four of the seven Web presentation patterns and shows how they are implemented in ASP.NET. Each of the patterns specifies a different way of presenting a Web front end, and each has its advantages and disadvantages, depending on the aims of the application. For example, the Transform View pattern is useful when developing against XML data sources or when multiple disparate markup languages need to be rendered; the Front Controller pattern is useful when preprocessing needs to be done on Web requests before domain logic and data access logic can be executed.
Figure 2 Web presentation patterns.
The application architecture for .NET document is also quite helpful because it identifies many of the key architectural decisions and places them in the context of a layered architecture using a common vocabulary. For example, the document uses consistent definitions for code (components) written in each of the layers, as shown in Figure 3. It then goes on to discuss key issues within each component type and how operational concerns such as deployment and security can be addressed as well.
Figure 3 Component layers in distributed framework applications and services.