3-Tier design has been my standard design philosophy for years for database driven applications, and it has never failed me. For those who practice it, describe your layers.
I've found that many people muddle up the business tier and the data access tier, making it more like a 2.5-Tier design.
I prefer to move the data tier almost entirely into the database using stored procedures, and just have a very lightweight data tier in code that wraps sproc calls into business objects.
How do you approach it?
EDIT: If all you are going to do is define what 3-tier is, don't waste your time replying. I am looking for how specific people implemented it, did you use stored procedures or an ORM, how did you handle circular dependancies between the DAL and the BLL? Theres a lot of depth to this topic besides saying
I've been doing primarly web apps for a while now and have been following 3-Tier as well:
UI: Pure ASPX pages. It is actually kind of hard to push your business layer down from here at times because doing a quick calculation or something seems so easy to do here. However, I've gotten disciplined enough to make sure the code behind pages are doing nothing but showing/hiding panels, updating user input, etc.
DAL: All data access layer stuff. I have really enjoyed using the XSD/DataTable/TableAdapter classes that are available. I also use stored procedure based CRUD methods, so hooking up the adapters to the stored procs is easy.
BLL: The business layer tends to be the lightest of the three layers in most of my apps here, since they are primarily CRUD type apps with some reporting built in.
I practice 3-tier design much the same way you do in that I use stored procedures to handle most, if not all of my communication with the database. I approach the design of my classes so that each one has a specific purpose in order to reduce complexity and to allow for greater flexibility when it comes to change.
One of the biggest problems I come across in 3-tier design is where to put input validation. Often times I find myself duplicating validation in both the UI and business layer to benefit the user with quick validation checking and to ensure that the data going in and coming out of the data layer is valid. How do you handle validation?
More of a side note: never forget that the n-tier layering is a logical layering, not a physical separation of processes. I.e., there should be no need to have the business logic running in a different process (or on a different box) than the presentational code. The important thing is the keeping the code clean.
Physically separating presentational code and business logic has been advertised for some time, e.g., by using webservices to connect to a backend. There are cases where this is a good idea, but it's not necessary in any way, but will significantly complicate your architecture, deployment, design, and cost performance.
n-tier design
I think that layering works quite well. Take a look at the tiers in the OSI model. I've used the three tiers that you describe and that approach really helped. The abstraction of Model View Controller is often helpful in a large desktop application. You can keep splitting things down into smaller and smaller more manageable pieces. There is a point of diminishing returns. And, there are occasions when we want to remove the abstraction layers and perhaps talk directly to the hardware -- it depends on the goals of your application.
I have found that the 2.5 Tier design to work best for the new web applications I have created.
I typically start off with 2 class libraries and 1 web application.
Company.Data
(Class library)
Company.Web
(Class library) (Contains PageBase
, Custom Controls, Helper functions, etc)
Company.Web.WebApplication
(Web Application)
For applications that I have created, I only use stored procedures to access the data.
In fact, I have created CodeSmith templates to generate all of the stored procedures, data and business classes.
Company.Data
This assembly consists mainly of the entity data classes and collections.
For example, I typically have a table called Settings
in my web applications.
A class called Setting
and SettingCollection
will be generated.
So if I need to load a specific setting, I can do this..
Dim setting As New Setting(1) 'pass in the id of the specific setting
setting.Value = "False" 'change the value
setting.Save() ' Call the save method to persist changes back to the database
or to create a new setting, I just do not pass a value in the constructor
Dim setting as New Setting()
setting.Name = "SmtpServer"
setting.Value = "localhost"
setting.Save()
My namespaces in the Company.Data
assembly typically look like this..
Company.Data.Entites
Company.Data.Collections
Company.Data.BusinessObjects
( This namespace is used to create custom methods to access data)
I also generate custom methods based on primary keys, foreign keys, and unique indexes.
For example, the name column in the settings table has a unique index.
A shared method called GetSettingByName
will be generated automatically and this will return a setting object.
This method would be in the Company.Data.BusinessObjects
namespace
For the entity and business object classes, two files are generated. 1 that is generated each time and 1 that is editable and only generated
the first time. I use partial classes to allow me to add custom code with out it being overwritten.
For me, this methodolgy has worked really well. Codesmith generation saves me countless hours of coding. I can add 5 new columns to a table, regenerate
all of the new code in seconds. Stored procedures will be dropped and recreated.
The 2.5 tier design works well because my application is only going to use one database and that is Sql Server. The need to use access, oracle, mysql in the future wont happen.
We use about a 6 tier design.
Browser-side Javascript and what-not. This is pure visual sugar with little business value or processing. Any input validations here are redundant checks -- they can be bypassed, so we don't trust them.
Server-side HTML presentation. This is partially business-rule driven. But there's no processing in the template language we use.
Server-side view functions, business logic, "control". This is where navigation, validation and the "higher-level" application-oriented processing occurs. This where state-change occurs -- things are computed, updated, deleted, etc. This is the processing. This where authentication and authorization are enforced.
Model definitions (using an ORM layer). This is the object model. It maps to a relational model. It includes all of the model-level processing as object methods. This is where some calculations are done, filtering, counting, ordering, are defined here. This is our useful view of the data.
Access layer (some kind of database connectivity). Depends on the database product. It's managed by the ORM layer, so we don't do any coding, just configuring.
Persistent storage in the DB (no stored procedures, no triggers).
DI has replaced tiers for me. Yeah, you can still logically sort providers by tier, but the differences between the logic layer and the database layer have been blurred by other design concerns, IMHO. If you're not sure what I mean, check out the "anemic model" war.
We once approached it using the following:
- UI Layer (where all the UI is)
- Business layer (where all the business logic is)
- Data layer (where all the DB access is)