A reminder on "Three/Multi Tier/Layer Architecture/Design" brought to you by my late night frustrations.
I was going over some C# code that was written for a non-profit earlier this year. It was fairly typical code and that's what disturbed me so. It consisted of a single ASP.NET Application with most of the work happening in the Page_Load. Although there was only one database, the connection string to that database appeared in at least a dozen places throughout the code. There were a few places where a SELECT * from WHATEVER occurred and they spun through a DataReader in order to set a boolean called "HasRows" to true.
So, I had to do something. I understand that not everyone cares, and that not everyone had (or chose to have) any formal Computer Science or Software Engineering academic life (not that there's anything wrong with that.)
Disclaimer: This post is just general advice. I know that reams of paper have been written on how to design software, layers, tiers, services, etc. This post is just to remind a few people that you can't have multiple layers until you start thinking about the responsibility of each layer - the contract and binding. Life has hierarchies and layers and responsibility - and so should most software.
That being said, here's little reminder about layers of abstraction. They are typically a good thing. Remember though, that in "Scott World" (which is hopefully your world also :) ) a "Tier" is a unit of deployment, while a "Layer" is a logical separation of responsibility within code. You may say you have a "3-tier" system, but be running it on one laptop. You may say your have a "3-layer" system, but have only ASP.NET pages that talk to a database. There's power in precision, friends.
- The Presentation Layer: For the vast majority of programmers who are doing ASP.NET, your pages live for one reason, to present an interface to the user. That is usually HTML/XML. (ya, ya, I know you might produce WML, CHTML, or GIFs with HttpHandlers but this whole post is a generalization)
- Things your pages shouldn't know about: Your pages shouldn't know that a physical data store exists. DasBlog does a lovely job of abstracting away the data store and presenting only an object model to the user. Your ASP.NET pages shouldn't know about connection strings, Connections, Commands, or anything like that.
- Things your pages should know about: Your pages should know about your Domain Model. Your objects, your stuff. If you're a librarian, I suspect you'll have a Book object. Perhaps a Librarian Service that knows how to Get and CheckOut books. He/She (the Service) no doubt knows how to Search for Books also.
- The Business Logic Layer:
- Things your BizLogic Layer shouldn't know about: Ideally your business logic layer shouldn't know there is a database. It shouldn't know about connection strings or SQL. It shouldn't know about much of anything except whatever format you choose to represent your objects in (preferably NOT DataSets.)
- Things your BizLogic Layer should know about: It should know about business rules (This payment will need 5 days of lead-time to be paid, or that book can't be checked out by two people at once) but not the details of storage. It might present public methods like "GetBookByISBN" or "CheckOutBook(Book b)" or "ReturnBook(Book b)."
- The Data Access Layer: Depending on how "purist" you want to get, you can merge the DAL with the Business Layer. At a minimum you should be able to perform CRUD operations. Create, Read, Update, Delete. Fundamentally most apps are just GETS of stuff and PUTS of stuff. Keep it simple. If your backing data store is XML files, or a Web Service or a Database, it shouldn't matter, and ideally your Business Layer (above) doesn't even know! It knows there's a DAL to talk to, but it's all about responsibility. If you are designing a layer, know your in's and out's and for Goodness' Sake know your responsibility. If you don't, back to the drawing board until you do.
- Things your Data Access Layer shouldn't know about: It shouldn't know about HTML, and it shouldn't know about ASP.NET. It should avoid knowing about business rules that don't related directly to how the data is stored (like cardinality.)
- Things your Data Access Layer should know about: It should know about accessing data in whatever form it's stored. It might have functions like "InsertBook(string name, string isbn)" or "InsertBook(Book b)" if you don't mind it knowing about your Business Objects (I usually don't). It should act as an Adapter between your Data Access Layer and your Data Store.
- The Data Store: This might be a SQL Server; then you'll need CRUD Stored Procedures to ReadBooks, UpdateBooks, etc.
- Things your Data Store shouldn't know about: Your Data Store shouldn't be generating messages in language. That means don't have your Stored Procs generate English messages. Sounds silly, but I've seen it before in the wild, so it bears repeating. It's your Data Store's job to get data to the DAL, and little else.
- Things your Data Store should know about: Storing stuff. 'Nuff said.
This may seem overkill, but believe me, once you've done it a few times, you'll appreciate it when you come back to mess with the code in the future. Remember also that much of this CRUD stuff can be auto-generated by CodeSmith or by Deklarit. Please, do resist the urge to open up a SqlConnection from your next ASP.NET page.
Why should you do this? Because of the 'ilities and because the simplest even-slightly layered design hides complexity.
- Flexibility: "The ease with which a system or component can be modified for use in applications or environments other than those for which it was specifically designed."
- Maintainability: "The ease with which a software system or component can be modified to correct faults, improve performance, or other attributes, or adapt to a changed environment."
- Reusability: "The degree to which a software module or other work product can be used in more than one computing program or software system."
- Scalability: "The ease with which a system or component can adjust to changing load."
[All these definitions are from the IEEE Standard Computer Dictionary.]
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
I constantly spend more and more time on this same topic when doing developer training. If I even see the use of System.Data.SqlClient, or even System.Data in the presentation layer I make them go back and redesign. There's a place for that stuff and it sure isn't there!
Manuel, you don't want to use DataSets in the business & presentation layers because that requires that code to "know something" about the data. For example, when building the business layer I would have to know that the DataSet contains a field named "fieldX" ie: mydataset.Tables[0].Rows[0]["fieldX"] instead of the simpler myobject.ValueX.
-Ryan
Andrew Lance
http://www.livejournal.com/~andrewlance
you say you dont like datasets, and while i agree, i dont care for them as i like the OO approach, you mention deklarit. Deklarit uses datasets :)
I actually am considering purchasing either Deklarit or LLBLGen Pro, i was wondering if you could comment on Deklarit?
Manuel Lopez:
Datasets are not all that great for web apps becuase they are very "heavy" and most of the time you dont need 90% the functionality provided by them. In a thick client (winforms) datasets are more useful for databinding, but this isnt really true for asp.net.
That said, C#/VB.Net/Java tend to be much better languages for writing business logic, IME.
There are far too many 1 or 2 page articles on this is what you should do and this is generally how it should work and very few putting your money where your mouth is examples. Then of course you ask for examples from these authors and you get “oh well, it’s all proprietary” or “it’s not 100% done” or “it’s very specific to a single solution, and it’s massive”. All of which are completely valid but now you’re asking someone that needs to get a working project out the door in 3 months to reinvent the wheel based on a pretty image of the various tiers.
It's also surprising how little a CS degree relates to quality code and architecture on a consistent basis. Having worked with a ton of developers over my career I've really stopped caring or using that as any basis for good programming practices. Sad but true. Their lexicon of programming terminology is usually greater but ask to see a solid, working example of the Observer pattern (even after you explain what it is) and you have a 50/50 chance of getting something that works.
So… great article but where’s the meat for those that want to see that diagram in action? Would make my life a lot easier when we get junior programmers. Right now I get a ton of "but how do we really do this?". Something like Test-Driven Adventures in C#, but for 3-Tier apps.
Your articles would become *much* more printer friendly.
and how cool are those XP-style icons in the image? "pure sex".
cheers
Leon
It might present public methods like "GetBookByISBN" or "CheckOutBook(Book b)" or "ReturnBook(Book b)."
One might say these methods really belong to the DAL, not the Business Logic Layer.
Having said that, there needs to be a relationship between the BizObjects and the DAL. In the example of GetBookByISBN, the BizObject layer eventually has to be able to ask the DAL for the results. This is where I am getting stuck.
My DAL has an interface that provides Retrieve, Insert, Update and Retrieve. Then, I can have whatever kind of data backend I want. I have a factory to create my DAL object for the Book. How do I then add the custom methods to Book, without having Book talk directly to the data layer?
I know this isn't the place for questions like this, but if you could point me to a good place for design-feedback questions, I'd appreciate it.
This practice is a little like test driven development, once you go there, you'll never look back. The nice thing about this type of app architecture is that you leave behind something 100% maintainable, and possibly extensible. Great examples of this type of architecture are found throughout Microsoft's newest .NET based technologies (SPS, Reporting Services, Microsoft CRM, Etc...).
Thanks for laying it out so plainly, Scott.
They are perfectly suitable IMO - the only problem is transporting the dataset over the net, however even for this problem there is a cure.
And people, go with CodeSmith as this is the best you can get - full control over everything (this also mean you might have to create a template or two :-) ) and there is a free version avaialable!
One question, if BLL should not, ideally, know the data access stuff - and perhaps, how or where the data is coming from - then does it make sense for the DAL to cover calling other webserives? Or perhaps there should be another layer between the BLL and DAL - in the traditional sense - that retrieves the data for the BLL whether be it from a webservice or a database?
Comments are closed.
Thanks for your vision on web application architecture. I agree with all your points, but i don´t undestand exactly the reasons for not using datasets in your business layer.
Does it really make sense to use objects in web apps, if I create a customer object and use it in asp, this object wont persist through the requests. Why not directly use the dataset. Instead of objects wouldn´t it be better to be more serviced oriented?
Manuel