Petshop example?

Posts   
 
    
stefcl
User
Posts: 210
Joined: 23-Jun-2007
# Posted on: 09-Dec-2007 22:10:55   

Hello,

I'm planning to redesign a bit the architecture of my application. It started as a very small windows GUI project but it's now bigger than I expected. I'm now asked to create a web UI in ASP.net to expose some functionalities, what worries me is that I did not properly separate the business logic from the UI and of course, I would like both the windows UI and the web UI to share the same internal behavior.

I'm just unsure which way I should go to implement my business layer, I'm using adapter and passing entities or entityCollections between the different layers is ok for me.

I have spent the day reading most of the posts on this forum but I'm still asking myself a lot of questions. I have also noticed that Otis wrote a petshop example a few years ago using llblgen, having a look at it could help me a lot because it could be close enough to a real-world application. Unfortunately, I can't find it anywhere!

If you know other examples or could share an advice, that would be very appreciated.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 10-Dec-2007 09:59:35   

You definitely don't want to look at the petshop example to get ideas how to do proper design. simple_smile It's a horrible design, at least what MS delivered. Sun's initial design was OK though, however as it was based on MVC, it wasn't really matching asp.net's capabilities.

You could have a look at this forums' sourcecode, HnD simple_smile (http://www.llblgen.com/hnd )

Frans Bouma | Lead developer LLBLGen Pro
stefcl
User
Posts: 210
Joined: 23-Jun-2007
# Posted on: 10-Dec-2007 10:12:44   

Thanks, I already did it simple_smile . It's very clean and properly designed, but I wonder if you would have done the same if it was a windows application instead of a web app. Most methods in your BLL take base types as parameters (for example (int id, string description)) and not entities, perhaps is it because databinding in web forms isn't as rich?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 11-Dec-2007 11:18:48   

stefcl wrote:

Thanks, I already did it simple_smile . It's very clean and properly designed, but I wonder if you would have done the same if it was a windows application instead of a web app. Most methods in your BLL take base types as parameters (for example (int id, string description)) and not entities, perhaps is it because databinding in web forms isn't as rich?

A forum is an application which does a lot of reads and little writes plus most data is read-only: you read it, dump it on a page and you're done.

In such environments, you simply need a way to get the data you need in a form which is easy to consume (i.e. a flat list) and that's it. So the architecture is build around that concept. Where data manipulation is performed, entities are used, as that's the better way to do data manipulation.

In winforms, where you use a 2-way interaction with data, flat lists in readonly form aren't going to cut it, so in there, you more use the approach which is used in the administation section of the forum I think: you mainly work with entities and more with databinding.

Frans Bouma | Lead developer LLBLGen Pro
stefcl
User
Posts: 210
Joined: 23-Jun-2007
# Posted on: 11-Dec-2007 15:02:40   

Thanks for sharing your advice... Please let me ask you one last question :

Do you think it's a wrong approach to construct prefetch paths and filters in the GUI layer and to pass them to a BL method which returns entity graphs? It gives a lot of flexibility to the forms for efficiently querying the datas they have to display but on the other hand, it reduces abstraction.

In fact you could have multiple overloads of BLL methods like GetCustomerById(...), GetCustomerByName(...), GetCustomerByIdWithOrders(...). Or perhaps just one or two like GetCustomers(IRelationPredicateBucket, ISortExpression), GetCustomers(IRelationPredicateBucket, IPrefetchPath2)

What would you recommand?

MarcoP avatar
MarcoP
User
Posts: 270
Joined: 29-Sep-2004
# Posted on: 14-Dec-2007 16:13:07   

stefcl wrote:

Thanks for sharing your advice... Please let me ask you one last question :

Do you think it's a wrong approach to construct prefetch paths and filters in the GUI layer and to pass them to a BL method which returns entity graphs? It gives a lot of flexibility to the forms for efficiently querying the datas they have to display but on the other hand, it reduces abstraction.

In fact you could have multiple overloads of BLL methods like GetCustomerById(...), GetCustomerByName(...), GetCustomerByIdWithOrders(...). Or perhaps just one or two like GetCustomers(IRelationPredicateBucket, ISortExpression), GetCustomers(IRelationPredicateBucket, IPrefetchPath2)

What would you recommand?

I like to do a mixture of both in my applications. Typically, I prefer naming my methods in such a way that it clearly exposes its intent. For example, 'FetchOrdersByUser', rather than 'FetchOrders(int userId)'.

Now on the flip side, I have a screen (Win App) which can be in a multitude of different states and sorting and filtering is done on the fly, as well as custom paging. So as you can see, all the sorting, filtering, paging, etc happens on the client. So, rather than exposing million different methods to handle each distinct situation (which is very inflexible in this scenario), I have my screen designed around the state design pattern, where each state object is responsible for constructing the RelationalPredicateBucket and SortCollection based on the current conditions of the screen, which is then passed to the business layer method.

That's my 2 cents on a real world situation.

Hope this helps! smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 17-Dec-2007 11:11:39   

stefcl wrote:

Thanks for sharing your advice... Please let me ask you one last question :

Do you think it's a wrong approach to construct prefetch paths and filters in the GUI layer and to pass them to a BL method which returns entity graphs? It gives a lot of flexibility to the forms for efficiently querying the datas they have to display but on the other hand, it reduces abstraction.

In fact you could have multiple overloads of BLL methods like GetCustomerById(...), GetCustomerByName(...), GetCustomerByIdWithOrders(...). Or perhaps just one or two like GetCustomers(IRelationPredicateBucket, ISortExpression), GetCustomers(IRelationPredicateBucket, IPrefetchPath2)

What would you recommand?

In DDD land people tend to speak about 'specifications'. So in layer X (e.g. the UI) code specifies what it wants, in terms known to the application. Those specifications are then send down to the layer X+1 which can understand the specifications and can fulfill the request of the layer X.

If you don't want to tie your layer X to what X+1 uses internally (e.g. LLBLGen Pro), you need to write your own specification stuff. If you don't mind, you can use the specification elements LLBLGen Pro offers you: prefetch paths, filters, relations, projections etc.

The thing is that the urge to avoid 'specifications tied to a given o/r mapper' is often based on a myth: even with POCO stuff, your entities are tied to the o/r mapper, and behavior of them will be dependent on the o/r mapper used.

That's not to say that it's not wise to look into a generic specification system: it can be easier sometimes to have such a system, and the most basic example of that is a BL API with methods like 'GetCustomersFilteredByCountry(string country)'.

What you should think of is: is the extra time spend on an API like that worth it? If your app is using LLBLGen Pro entities in the UI, you could opt for a mix of these elements or go all the way for writing filters at the spot where you need them.

The question 'where to write the code to specify the filter for a given set' isn't easily answered. If you need the set defined by the filter at 3 different spots in your application, one could argue to write a method for that and call that method at those 3 spots. However that can hurt you if you need to update the filter for 1 of those 3 spots after a while.

So it's a tradeoff. If you know up front where you need which data, you can write an API. if you don't know that up front, you can write a couple of generic methods which accept filters, sorters etc. and do the fetching there and return the data based on the filters specified.

Frans Bouma | Lead developer LLBLGen Pro
stefcl
User
Posts: 210
Joined: 23-Jun-2007
# Posted on: 17-Dec-2007 19:05:53   

Thanks a lot, I think I'm going to opt for a mix of both then. A bit like Marco said.