Practical Example?

Posts   
 
    
Cadmium avatar
Cadmium
User
Posts: 153
Joined: 19-Sep-2003
# Posted on: 15-Apr-2004 18:52:04   

I've been trying wrap my head around n-teir applications. I think I understand many of the concepts, but when it comes to applying them I'm completly lost! confused I see a lot of little pieces of code demonstrating a pattern, etc, but nothing showing how it all comes together.

Can anyone show a simple but practical application start to finish using llblgen? What I mean is an example that shows how to display, insert and update a simple table using a layer architecture (ui, bll, etc). I think that would help me (and probably a lot of other people) tremendously.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39619
Joined: 17-Aug-2003
# Posted on: 15-Apr-2004 20:11:40   

With the northwind example projects, you have 2 tiers, and you want a separated middle tier?

Could you please describe a bit what confuses you when you want to apply the n-tier concept? (as I've said before: don't see it as a strict set of rules, it's an idea which can be applied in a lot of ways)

Frans Bouma | Lead developer LLBLGen Pro
Cadmium avatar
Cadmium
User
Posts: 153
Joined: 19-Sep-2003
# Posted on: 15-Apr-2004 20:51:02   

Otis wrote:

With the northwind example projects, you have 2 tiers, and you want a separated middle tier?

Could you please describe a bit what confuses you when you want to apply the n-tier concept? (as I've said before: don't see it as a strict set of rules, it's an idea which can be applied in a lot of ways)

I know there's not one correct solution to every problem, or even the same problem. No example would demonstrate everything anyone needs to know, but it would at least give me (and others having problems trying to grasp enterprise architecture, I know they are out there) a practical example i could apply and learn from.

I have several medium sized asp.net apps (built with SelfServicing) right now that have all of the business logic in the code behind pages (basically how you have the northwind examples running). However, aside from the llblgen entities, there's nothing there I could reuse directly to build a windows form version of an application (which is something that I would actually like to do). Besides re-use, just having the bl in one layer would help with maintenance, which can be quite a pain on some growing apps.

If you are asking for what my dream example would be... wink I think an ideal example show a simple bll layer (in whatever techique) and two gui layers: one in asp.net and one in windowforms. Each gui would have 2 forms, one for displaying the records in a database and one for inserting a new record (or updating a record). Nothing fancy, one table, a few records, simple forms with some basic validation and business logic, etc.

I could ask 100 specific questions that depend on the answers of 100 other questions, but to see an actual working example would answer alot of those questions and at least let me ask better ones simple_smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39619
Joined: 17-Aug-2003
# Posted on: 15-Apr-2004 22:10:36   

I'll try to answer your question tomorrow simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Cadmium avatar
Cadmium
User
Posts: 153
Joined: 19-Sep-2003
# Posted on: 16-Apr-2004 00:25:07   

Otis wrote:

I'll try to answer your question tomorrow simple_smile

Thank you simple_smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39619
Joined: 17-Aug-2003
# Posted on: 16-Apr-2004 12:07:22   

I don't have an example here for an 'enterprise architecture'. What you should focus on is that logic related to rules in your application (that's not: fetching some rows, but that's: determine if this customer can have a discount) should NEVER be placed in the gui tier. If you create a separate library with classes which contain that kind of logic, you've set the first step to a more generic architecture: that library can then be shared among multiple gui's and multiple gui elements.

It's not a layer directly, as it might be that in your GUI tier, you fetch entities. It's wise to outsource that kind of code to a class library as well. So instead of fetching data (or calling save) in the GUI, you outsource it to a method in the class library. This has advantages, that you can blackbox the logic WHICH entities to fetch. Furthermore, you can re-use that logic among different GUI elements and gui's.

That's the main philosophy. You can stare at a thousand setups, but they all use the same philosophy.

So your GUI tier should contain the logic to control the GUI and call methods in a class library. The class library then calls other methods in hte same library and works with the generated classes.

Frans Bouma | Lead developer LLBLGen Pro
Cadmium avatar
Cadmium
User
Posts: 153
Joined: 19-Sep-2003
# Posted on: 16-Apr-2004 16:58:34   

Otis wrote:

I don't have an example here for an 'enterprise architecture'. What you should focus on is that logic related to rules in your application (that's not: fetching some rows, but that's: determine if this customer can have a discount) should NEVER be placed in the gui tier. If you create a separate library with classes which contain that kind of logic, you've set the first step to a more generic architecture: that library can then be shared among multiple gui's and multiple gui elements.

It's not a layer directly, as it might be that in your GUI tier, you fetch entities. It's wise to outsource that kind of code to a class library as well. So instead of fetching data (or calling save) in the GUI, you outsource it to a method in the class library. This has advantages, that you can blackbox the logic WHICH entities to fetch. Furthermore, you can re-use that logic among different GUI elements and gui's.

That's the main philosophy. You can stare at a thousand setups, but they all use the same philosophy.

So your GUI tier should contain the logic to control the GUI and call methods in a class library. The class library then calls other methods in hte same library and works with the generated classes.

Okay, that helps a bit. But I'm still confused about communcation between the gui and the bll (or service layer, etc). For instance, you have a form to enter a record of data, whats the difference between your gui setting properties on a bll object vs passing parameters into a static method? When do you you one over the other?

Another example is if you have a sortable datagrid, do you sort the data in the gui or do you pass that sort info to the bll and sort the data there?

Cadmium avatar
Cadmium
User
Posts: 153
Joined: 19-Sep-2003
# Posted on: 21-Apr-2004 17:15:49   

Okay, if I can post (another) follow-up question. I'm trying to write a manager layer. For multiple I am passing back datatables because that data is often coming from typedviews or storedprocedures, and I figure that's a decent way to standardize.

However for pulling back a single record/entity do you recommend passing back the entity itself or a datatable with a single record?

Also for updating or saving an entity, if I was to have the gui pass an entity back to a save() method how would I stop the gui from just calling the save method on the actual entity and bypassing any business rules or validation? Is this a case where it's best to stick with a static method with the data passed as parameters?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39619
Joined: 17-Aug-2003
# Posted on: 21-Apr-2004 22:15:37   

I hope to have some time tomorrow morning to answer your questions. simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39619
Joined: 17-Aug-2003
# Posted on: 22-Apr-2004 11:51:13   

Cadmium wrote:

Okay, that helps a bit. But I'm still confused about communcation between the gui and the bll (or service layer, etc). For instance, you have a form to enter a record of data, whats the difference between your gui setting properties on a bll object vs passing parameters into a static method? When do you you one over the other?

You often use a method when the data on the form has to be set in different objects. Your gui can have data from say 3 tables on the screen, the user manipulates them all or 2 of them for example and the gui doesn't know the data is from 2 objects or 3 or 1, it simply calls the BL with the new data. Perhaps all the data is used to generate 3 new objects, however that's the task of the BL. So as long as you keep that kind of logic out of the gui and simply make the gui call a method (either by passing arguments or by setting properties) it's ok. A method call is prefered over properties (I learned that with the old llblgen 1.x open source generator wink ) by a lot of people because it makes code easier: you just write 1 line of code instead of a lot of property set calls.

Another example is if you have a sortable datagrid, do you sort the data in the gui or do you pass that sort info to the bll and sort the data there?

Initial presentation can be easier when the data is sorted using a default sort clause, for example customers sorted on name, or orders sorted on orderdate. Once this data is initially presented, the user (or gui, via preferences settings for example) can sort the data as he/she likes in teh grid.

Okay, if I can post (another) follow-up question. I'm trying to write a manager layer. For multiple I am passing back datatables because that data is often coming from typedviews or storedprocedures, and I figure that's a decent way to standardize.

However for pulling back a single record/entity do you recommend passing back the entity itself or a datatable with a single record?

If you pass back an entity, you need a reference to the generated code in your GUI layer. It's up to you if you want that. (if you're the only developer, you probably don't have a problem with that, big teams probably don't want gui developers have access to raw entity classes). What makes your job more easy should be used. And don't forget what that 'easy' means: easy to develop NOW [b[and[b/] easy to maintain now and later. simple_smile Especially that last part is often the reason a tradeof for easy development now is made.

Also for updating or saving an entity, if I was to have the gui pass an entity back to a save() method how would I stop the gui from just calling the save method on the actual entity and bypassing any business rules or validation? Is this a case where it's best to stick with a static method with the data passed as parameters?

This is why Adapter was created, to separate that kind of logic from the data. simple_smile With IEntityValidator you can always plug in the validation before the entity reaches the gui. You can also override the InsertEntity/UpdateEntity methods in the two-class scenario in the derived entity class. In there you check for a code for example which is set by a property and set in the BL prior to the save call. A developer who calls Save() in the GUI tier doesn't have the code, doesn't set it and Save will fail.

Frans Bouma | Lead developer LLBLGen Pro
Cadmium avatar
Cadmium
User
Posts: 153
Joined: 19-Sep-2003
# Posted on: 22-Apr-2004 18:05:01   

Thank you for taking the time Otis, I've know I've asked a lot of general questions. I appreciate your help. Did I ever mention you're my favorite MVP? wink

So as long as you keep that kind of logic out of the gui and simply make the gui call a method (either by passing arguments or by setting properties) it's ok. A method call is prefered over properties (I learned that with the old llblgen 1.x open source generator ) by a lot of people because it makes code easier: you just write 1 line of code instead of a lot of property set calls.

Yes, it's a tough call. In my current application I've been playing around with both. My main issue with a static method call with the data being passed as arguments is that it defeats the convenience using a o/r mapper to a certain extent. If I make a change in the database I now have to change the signature of the method, which seems to make the application more fragile. But, like you said, when you have the ui interacting with multiple tables/entities, I don't know how to handle that without static methods or putting more logic in the ui.

Initial presentation can be easier when the data is sorted using a default sort clause, for example customers sorted on name, or orders sorted on orderdate. Once this data is initially presented, the user (or gui, via preferences settings for example) can sort the data as he/she likes in teh grid.

So does this mean it's bad to pass sorting parameters into the bll? For example I've been playing around with something like this (you may have been able to tell from my other post) ProjectManager.GetProjects( string fieldToSortOn, bool isDescending ) To me, even though sorting technically "presentation" specific, it's a lot more work to do it on the client, at least in asp.net. My opinion is probably wrong though simple_smile

If you pass back an entity, you need a reference to the generated code in your GUI layer. It's up to you if you want that. (if you're the only developer, you probably don't have a problem with that, big teams probably don't want gui developers have access to raw entity classes). What makes your job more easy should be used.

I'm the head of a small team and the only one who develops full-time, but everyone will probably do a little of everything (ui and bll). I haven't decided whether or not I trust them to use the entities directly in the ui. It's a lot easier to use them directly now, since i don't have to write and maintain dozens of methods with constantly changing parameters. I realized that I could use adapter after I asked that question, and I suppose I could simply not reference the db specific dll and that will pretty much stop them from calling any save methods outside of the bll simple_smile

With IEntityValidator you can always plug in the validation before the entity reaches the gui.

I haven't played with validators much, but would you use this technique with adapter, or just with self servicing? With adatper, if you simply populated the entity with data and passed it back to a method as a parameter, would it even call the validator?

Thank you again for taking time and explaining a lot of this stuff. I can see the different options I have a lot more clearly (implementing them well is still another thing). The biggest hurdle I see for my project(s) is consitancy. I think i can get away with passing entities to and from the ui most of the time (which is very convenient), but there are enough exceptions that I could easily develop a messy and inconsistent bll. I'll just keep telling myself that n-teir is a journey, not a destination wink

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39619
Joined: 17-Aug-2003
# Posted on: 24-Apr-2004 11:49:13   

Cadmium wrote:

Thank you for taking the time Otis, I've know I've asked a lot of general questions. I appreciate your help. Did I ever mention you're my favorite MVP? wink

Heh really? wink

So as long as you keep that kind of logic out of the gui and simply make the gui call a method (either by passing arguments or by setting properties) it's ok. A method call is prefered over properties (I learned that with the old llblgen 1.x open source generator ) by a lot of people because it makes code easier: you just write 1 line of code instead of a lot of property set calls.

Yes, it's a tough call. In my current application I've been playing around with both. My main issue with a static method call with the data being passed as arguments is that it defeats the convenience using a o/r mapper to a certain extent. If I make a change in the database I now have to change the signature of the method, which seems to make the application more fragile. But, like you said, when you have the ui interacting with multiple tables/entities, I don't know how to handle that without static methods or putting more logic in the ui.

Exactly. It's a trade-off, as, sadly wink , with everything.

Initial presentation can be easier when the data is sorted using a default sort clause, for example customers sorted on name, or orders sorted on orderdate. Once this data is initially presented, the user (or gui, via preferences settings for example) can sort the data as he/she likes in teh grid.

So does this mean it's bad to pass sorting parameters into the bll? For example I've been playing around with something like this (you may have been able to tell from my other post) ProjectManager.GetProjects( string fieldToSortOn, bool isDescending ) To me, even though sorting technically "presentation" specific, it's a lot more work to do it on the client, at least in asp.net. My opinion is probably wrong though simple_smile

No it's not bad, as sorting is not something most BL will need, but gui's will. So if a gui wants some data, it tells the BL to get it, and how.

With IEntityValidator you can always plug in the validation before the entity reaches the gui.

I haven't played with validators much, but would you use this technique with adapter, or just with self servicing? With adatper, if you simply populated the entity with data and passed it back to a method as a parameter, would it even call the validator?

With both, as it's a good mechanism for plugging in 'set and forget' logic: when something fails the validation, the code will die in an exception, which is what you want, so the check is in place and no worries are left. The validator is called by the save logic, if there is an entity validator object set (an object implementing IEntityValidator). So it will always be called, you can't work around it.

Thank you again for taking time and explaining a lot of this stuff. I can see the different options I have a lot more clearly (implementing them well is still another thing). The biggest hurdle I see for my project(s) is consitancy. I think i can get away with passing entities to and from the ui most of the time (which is very convenient), but there are enough exceptions that I could easily develop a messy and inconsistent bll. I'll just keep telling myself that n-teir is a journey, not a destination wink

simple_smile Test a few options and see which one is more appealing to you. After all, if you find a given method the best for your way of working, choose that one, however always think of what the pro's and con's are of that given method and perhaps with a little change of your way of working another method is more appropriate because it gives better maintainable software for example.

Frans Bouma | Lead developer LLBLGen Pro