Contents
1. Architecture
The development of Publishers' Assistant products will adhere to what has become a fairly traditional "n-tier" architecture. The major "tiers" or modules of this architecture are the presentation, business, and data tiers. Work done to date has shown the necessity for an additional sub-presentation tier. More about that later.
One common characteristic that defines each tier is that it has a well-defined interface that is interchangeable. For example, we should be able to replace the presentation tier, without effect to the business or data tiers. Likewise, we should be able to replace the data tier without effecting the business or presentation tiers.
It is generally accepted that these tiers will be implemented using an object-oriented-programming approach. In work done to date, this approach has worked well to clearly define the interfaces between tiers and components within those tiers.
1.1. The Presentation Tier
The presentation tier is concerned solely with the user interface. It presents data for the user's review and accepts user input for the processing of that data. Processing of data should be avoided in the presentation tier. In the n-tier development in Foxpro, the presentation tier consists of forms. A concerted effort has been made to minimize the logic in these forms to the presentation of data retrieved via the business tier. In PAWeb, the presentation layer is primarily implemented in ASP. Again, an effort has been made to minimize any logic in this layer. Some VBScript has been employed, but it is generally concerned with retrieving and sending data to the business tier for processing.
1.1.1. Exceptions
There are two notable exceptions which add logic to the presentation tier. The first has to do with a need to show the user progress while processing. For example, in the import and export wizards, the routines that process through a collection of titles or contacts will cycle through them using lower level logic in order to present progress on the screen.
The second exception is in the web development platform. In order to retain state, while minimizing logic from VBScripts and particularly to avoid supplying any sort of SQL at the ASP level, we found it advantageous to create a sub-presentation tier. This module groups business tier components into classes that are helpful in maintaining context in a web server environment. Some logic is provided in this module to facilitate common operations that take place in a web application. This development model may extend to other platforms as well.
1.2. The Business Tier
This module is where all of the business logic for the application resides. Assuming object-oriented programming, the business tier interface looks like a series of class definitions. These classes are, of course, instantiated by the presentation tier to execute the application. What is important is to make sure that the implementation we choose will work across platforms. Typically, these classes are implemented for each major transaction that is supported in the application. In ?PubAssist, these transactions are invoices, returns, purchase orders, receipts, payments, title definitions, etc. Each of these major transactions may cause several lower-level transactions to be executed as well. For example, an Invoice transaction may save an order to the database, but that invoice may trigger a series of both inventory and financial transactions.
1.3. The Data Tier
The primary objective for separating the data tier is to allow the database to be implemented using any database product that works in the desired platform. The data tier also concerns itself with the location of the data.
Again, the interface for this tier is a set of classes. These classes tend to focus on typical database operations. Examples are:
- Add a new record
- Find a record
- Search for multiple records
- Update a record
- Update a collection of records
- Delete or recall a record
- Delete or recall multiple records
This is not a complete list, and there are many supporting functions or methods that are part of the data tier.
1.4. Moving Data Between Tiers
1.4.1. Resources
Some mechanism is needed to transport data between tiers. The current Foxpro implementation uses a class which is designed specifically to hold a record as well as other attributes that preserve the context of that record. This class is called a "Resource". The term comes from documentation on proposed n-tier implementations that was published by Flash Code. This has proven to be a very useful device which allows the business logic to be completely separated from both the database technology as well as it's location. (The data tier worries about the location and database product in use.) In the current implementation, the same physical image of the application (business and data tiers) will work in multiple threads to allow simultaneous access to multiple and separate databases. The context retained in the resource is what allows this to happen.
The resource is structured to hold a collection of records from a single database table or view. An ADO record set is similar in concept to a resource. An effort has been made to keep any logic out of the resource class. This makes the object extremely transportable.
1.4.2. Resource Clusters
Looking back at the transactions mentioned above, it's clear that each transaction requires interaction with multiple tables. For example, an invoice transaction will require data from the following tables at a minimum:
- Orders
- Contacts
- Ordered Items
Similarly, saving a title may effect the following tables:
- Title
- Contributors (Contacts)
- Promotions
- Subject Codes
In order to process a complete transaction, it makes sense to provide a mechanism to group resources together into a structure that represents that transaction. The current implementation refers to this mechanism as a "resource cluster" or "cluster" for short. Clusters are also implemented as class definitions and an effort has been made to avoid the introduction of any logic to these classes.
1.5. n-tier vs. MVC
Since we are considering re-implementing PubAssist software using Python and Django, and Django is considered by many to be a framework implementing the "model-view-controller" (MVC) pattern, it's worth sorting out the terminological and conceptual differences between an "n-tier" and "MVC" architecture.
First off, we should note that there are varying interpretations of MVC. Django employs one such interpretation (see their FAQ). In Django, MVC's "controllers" are called "views", and MVC's "views" are called "templates." (Rather confusing, but it's what they do, so I'm going to adhere to their convention here.) So you could call Django an "MTV" framework, if you're not afraid of the trademark police.
Anyway, the basics of MTV/MVC and Django are as follows:
-
Models are the "domain-specific representation of the information on which the application operates." In other words, they are a data abstraction layer. The database (or other data storage mechanism) is understood to be below the model layer. The same models may use different backends in different implementations. Like any data abstraction, models have contracts specifying how to interact with data; in an object-oriented setting like Django's, this means that data are objects with methods.
-
Views make up the application layer responsible for directly interacting with models, processing events from the user interface, executing business logic, and so on. In Django, views are Python functions which have a very specific interface: they accept an HttpRequest object, and return some sort of HttpResponse object. They can do anything else in between.
-
Templates are the user interface layer. Similar to the way that models are data abstractions, they are presentation abstractions; as their name indicates, they're forms that need to be filled in with actual data. In Django, templates are typically a mixture of HTML code and template-language directives. Views render templates with the data they get from models.
In both n-tier and MTV architectures, then, there are three layers, which correspond to the user interface, the application logic, and the data container. How do they differ?
1.5.1. Differences
Conceptually, I don't believe there are any large differences. MTV, as Django implements it, has strongly decoupled layers, communicates between those layers by passing data objects (model instances, ?QuerySets, and others), permits swapping out one kind of presentation for another (e.g., one can have both HTML, XML, or any other plain text-based template), permits swapping out one database backend for another (e.g. MySQL vs. SQLite vs. PostgreSQL), and so on. On some interpretations of MVC, "views" (templates) can update models directly, making the interaction pattern triangular instead of linear (see this Wikipedia article on MVC vs. n-tier). This would constitute a major difference between the two architectures, but Django doesn't follow this interpretation: templates don't even contain executable code until they are rendered, and it is views which do the rendering. For all intents and purposes, then, the n-tier architecture of the current VFP application and a Django-based MTV application are equivalent on a conceptual level.
Practically, the differences between MTV and n-tier designs lie in the settings in which the two architectures are used, and thus in the domain-specific problems they are designed to solve. MVC/MTV is the darling child of the Web development world, and self-proclaiming MVC frameworks like Django or Ruby on Rails are often focused on making it easy to build dynamic Web applications. N-tier is a broader concept more frequently used in the realm of "enterprise" applications, and as such, its implementers are often more concerned with things like performance, physical separation of servers, "scalability," and so on. The languages and software used to implement non-Web n-tier systems emphasize solving these problems.
The VFP-based n-tier architecture of Publishers' Assistant occupies some middle ground here, since it is not specifically web-focused, but neither is it overly concerned about the problems present in an "enterprise" environment. This makes sense, since PubAssist's architecture is entirely the product of in-house development, and was designed to solve a subset of the problems in both worlds. As we choose a new framework, it is unlikely that anything readily available is going to provide all the same functions of the VFP code "out of the box." We're going to have to choose an architecture/framework that gets us most of the way, and makes it easy to make up the rest.
1.5.2. Why choose Django?
In my mind, the benefits to be gained from a high-level, dynamic language (Python) and Django's solid data abstraction layer far outweigh the costs of either needing to write a non-Web presentation layer for Django, on the one hand, or working with an "enterprise" n-tier framework that is not specifically Web-based (e.g., one written in Java or C++) on the other.
The Publishers' Assistant software is almost exclusively run today by small publishers on one or a few computers. It has no current need for the performance gains that a Java or C++ n-tier framework would lend us. And, if and when it is necessary to run Publishers' Assistant software in an "enterprise" environment, Django is up to the task. It's simply not worth the development pain and time to use C++, especially in a one- or two-man shop, and other languages and platforms which would give us similar benefits are nastily tied to proprietary systems (Java, C# and .NET, etc.), which would defeat the whole purpose of leaving VFP for a platform-independent language and tools.
Moreover, a Web-based platform is increasingly important for us to support, and Django (naturally) excels in this arena. Using Django will mean being able to offer people dynamic websites which are quick to set up, easy to customize, and easily maintained by their owners. MTV is the current architecture of choice here, and Django is an excellent choice among MTV frameworks because it is actively developed, has a lively community using it, and has excellent documentation.
Using Django does mean getting a bit creative when it comes to putting out a desktop product. I don't see this as a problem. There are a wide range of choices for GUI toolkits for Python, at least three of which are (or aim to be) fully platform-independent: wxPython, PyQt, and TkInter. A development plan which separates views into two layers — a general business logic later and an interface layer on top of it which contains modules specific to either Web-based or desktop-based user interfaces — would preserve the decoupling of the MTV layers, be DRY, and allow us to use Django to its full extent while adding the additional pieces we need rather quickly.
2. Sub-pages and categories about Architecture
The following pages contain discussions specific to the PubAssist application architecture:
2.1. Django-related
-
Django application tier: how to implement the business logic tier of this architecture using Django
I think the idea of a resource — i.e., a data abstraction — is a useful one that we should continue to use. However, I'm not sure we should think of resources as a vehicle for transporting data between tiers. Both the data tier and the presentation tier should not be concerned with knowing how to translate resources into a format they can work with. Presentation-level data is almost always strings; data-level data is almost always one of a few primitive types. Converting from strings to resources to primitive types, or vice versa, should always happen inside the business logic, in my mind, albeit in isolated (and replaceable) "translation modules." The reason for this is that the conversion from one type to another can involve semantics that are only found in the business logic.
For example, if a field in a table stores a floating point value representing a dollar amount, it's the business logic's job to know that there should only be two significant decimal places. The database should be indifferent to the meaning of that floating point value vs. another (say, one representing a precise measurement). Similarly, the presentation layer should be indifferent to the meaning of the string of the form "$xxx.xx" that it displays for a dollar amount vs. a string of a different form that it displays for a title.
I think Django holds true to this thinking. One of the really nice things about the framework is that it does much of the "translation" for us in the background. Model instances (resources) have attributes that can be a variety of Python types. Conversion to the appropriate front-end type occurs during template rendering (whether explicitly or implicitly) and conversion to the appropriate back-end type occurs when an instance's save() method is called, but both of these processes are explictly invoked in the business level. (Templates do not render themselves, and databases do not accept Python objects to save.)
Thus, to me it makes more sense to think of resources as existing solely in the business tier. The boundaries between the different tiers, where translation to and from resources occurs, should still be thought of as part of the business tier, for the reasons of semantics discussed above. In my mind, it makes sense to think of a "super-business layer" instead of a "sub-presentation layer," and a "sub-business layer" instead of a "super-data layer."