Design and Code Reuse

Design and Code Reuse

Old forum URL: forums.lhotka.net/forums/t/5158.aspx


Wbmstrmjb posted on Friday, July 25, 2008

I am wrestling with how to reuse code and still have a "task-centric" view of the BOs.  In Project Tracker, code is basically not reused and the properties for a "Project" and for a "Resource" are repeated in the ResourceAssignment(Project) and the ProjectResource(Resource).  So in order to look at the objects from a "page" or "task" POV, you have the same object made two different ways.

What are some ways to design a system that still uses good CSLA practices but can reuse code?  Traditionally before diving into CSLA, I would have almost a 1:1 table to BO relationship and then a logic layer that just used the BOs to write and read data.  Obviously this meant only having properties in one place, but also meant that each object was unaware of the objects that related to it.

Any thoughts?

Thanks,

Mike

JoeFallon1 replied on Friday, July 25, 2008

I tend to make 1:1 BOs to tables because it is easier to code gen that way. But then I enhance them with borrowed fields in many cases in the derived class level.

But my key "breakthrough" was to create a higher level BO called a USe Case Controller which coordinates all the "CRUD" level BOs for a given use case. So a particualr screen may need a root BO with a child collection and an NVL. The Use Case Controller is just a root BO which fetches all the contained BOs and presents them to the UI. Each BO is self contained in regards to rules and and CRUD but the UCC object can have higher level rules which cut across the contained BOs if necessary. It can also perform additional CRUD actions that are outside the scope of the contained BOs.

In other cases, I have classes which perform the same functions for various BOs. So the code is pulled out of the various BOs and simply centralized in this one class which they all can call so it is consistent.

Joe

 

tmg4340 replied on Friday, July 25, 2008

Wbmstrmjb:
I am wrestling with how to reuse code and still have a "task-centric" view of the BOs.  In Project Tracker, code is basically not reused and the properties for a "Project" and for a "Resource" are repeated in the ResourceAssignment(Project) and the ProjectResource(Resource).  So in order to look at the objects from a "page" or "task" POV, you have the same object made two different ways.

Rocky touches on this in his book, and it's been discussed a few times here as well.

CSLA is designed to support business objects that are defined by use cases.  Tasks are certainly an acceptable alternative as well.  But the point is that code re-use is not an overarching goal.  In fact, Rocky will stress that re-use is really only acceptable if the use cases do exactly the same thing.  Otherwise, your objects are taking on more than one responsibility, which is only going to cause you trouble.

This is one reason why you don't see much re-use in the ProjectTracker app.  By the nature of how he builds his apps, there just isn't much re-use.  It also doesn't help that PT is more of an example app, so you don't see what could be considered "best practices" in some areas either.  But even beyond that, the concept of the single-responsibility/use-case-driven design goes a long way towards pushing re-use a ways down the list of Important Factors To Consider When Building Objects.  It's also why you see property duplication - the object is designed to support a single use case, and as such will pull all the data it needs to complete that task.  Use cases for a particular subsystem will often use much the same data.  Finally, the isolation of code that this technique provides proves to be a lot easier to deal with when your use cases change.

I will say that this can be a really difficult concept to come to grips with.  After all, the whole OOP paradigm is built on code re-use through hierarchies, decoration, patterns, etc.  But that's not the approach he takes, and it can be hard to shift your thinking.

That's not to say that you shouldn't look for ways to re-factor your code.  But instead of going for a class hierarchy (which in CSLA 3.5 forces you to do some rather unfortunate hack-like things to get it to work), or making classes that serve multiple purposes, Rocky tends more towards creating common "modules" that classes can share.  It kind of strikes me as a somewhat service-oriented approach, where you're creating these utility/gateway/service classes that are usually just a collection of stateless methods.

(Of course, Rocky being primarily a VB programmer, Module is probably the literal term.  But a static class in C# works just as well.  Smile [:)])

That's also not to say that OO techniques can't be used.  Design patterns are still very effective, and if you're in the composition-over-inheritance camp, you can still do a fair amount of that as well.  But you won't see a ton of inheritance, and you probably won't see a ton of re-use of your objects.  And that's OK.

HTH

- Scott

RockfordLhotka replied on Saturday, July 26, 2008

This has been discussed many times before - it is a common question.

Here's one good post in response to a similar thread:

http://forums.lhotka.net/forums/post/17257.aspx

You can also search the forum for the term "coupling". You can't have reuse without coupling, they are two sides of the same coin. While reuse is desirable, coupling is the ultimate sin. So you should only reuse code if it incurs no coupling (which is impossible).

So in reality you should only reuse code if you are willing to accept the resulting cost of coupling. And sometimes that is a cost worth paying, because you can carefully design your code to minimize the cost - there are various design patterns and techniques that enable reuse without too much coupling.

But things like inheritance are very dangerous, because they are a tightly coupled relationship. Yes they provide reuse, but at a very high cost (in most cases).

The most important thing to remember is that reuse is not the goal, maintainability is the goal. Reuse is merely one tool you can use in pursuit of that goal, but it always comes with coupling, which is in direct conflict with that goal.

Wbmstrmjb replied on Monday, July 28, 2008

This helps alot.  I still struggle with not being able to write one class for each table and put them into various combinations to achieve the goal.  I guess I've always looked at it from the data's standpoint and not from the use cases'.  I looked at building applications like a Lego set and all of the "blocks" were just the database tables modeled in code.  Combine the blocks and make an app.  I think it is still going to take some time to wrap my head completely around a use-case-centric design, but I am starting to see some benefits.

Wbmstrmjb replied on Monday, July 28, 2008

One question I have is how is code generation effective when you're looking at it from a use case POV?  Normally I'd code gen all the "table" classes because the generator would just pull fields from the table and the generator would create a class that implemented a property and all the CRUD for the fields/table.  Now there are "partial tables" (just a few fields needed from a table) and parent/child relationships that need to be accounted for.  What code gen solution works well for CSLA classes and this perspective of thinking?

Thanks,

Mike

JoeFallon1 replied on Tuesday, July 29, 2008

I use Codesmith. It is a great tool.

You can point Codesmith at a DB table (or View) and it will codegen the fields into a BO for you (using the CSLA template.) So this is closer to your way of thinking of a table is a BO. I tried to explain earlier that it is not 100% wrong to think this way. I like your term of using them as "building blocks" inside the the app. The use case thing comes in to play when you need extra data which is not in the same table. In that case, you can borrow fields from other tables (either by doing a JOIN in your SQL or by executing a 2nd query after the base table's fields have all been fetched.)

So codegen is quite useful to:

1. Get the BO built with 98% of the code needed.

2. Get the BO built the same way every time.

3. Have bug free BOs which compile the first time.

I use Inheritance to then create a layer where I can manually add fields, properties, methods to the BO. In many cases there is little or no code in this level. In some cases there is a lot of code.

CSLA templates can account for child BOs too.

Joe

 

 

Wbmstrmjb replied on Tuesday, July 29, 2008

I think I'm more confused now.  In most applications, one single table is not the only data needed on a given screen.  So it seems that the "use case thing" is always applicable.  When does the "building block" method work well for CSLA in a "real" application?  It seems to me that could get accomplished what I need to do with building blocks, but it won't be elegant and simple to hook up the UI like it is in PT.  It seems to go directly against the principles that CSLA directs you to employ.  Creating an editable root for every table and "joining" them in a higher logic layer is not super smooth.  Am I making sense?

I have another question regarding the DAL that pertains to this discussion.  Do most people prefer to use one DA class for each table and then use that from within each of their objects, or does it make more sense to create DA classes that directly mirror the data to be retrieved for a given use case?  What I mean is that if you have Projects and Resources, is it better to have a Project DA and a Resource DA that the Project/Assignment and Resource/ProjectResource access respectively, or to create a "Project" DA that retrieves the Project and it's ProjectResources and a "Resource" DA that retrieves the Resource and it's Assigments?

Thanks,

Mike

RockfordLhotka replied on Tuesday, July 29, 2008

In most applications there’s a large percentage of screens that are pretty much 1:1 with tables. Maintenance screens, basic edit screens and other stuff – usually the parts of the app that are mind-numbingly boring to write too.

 

Data-centric code generators can really help you out here, by creating business objects that map to tables – and that’s OK because the use case maps to the tables pretty well too.

 

But most applications also have a small percentage of screens that are actually interesting. Screens with complex business logic, and that often interact with many, many tables (or at least little parts of tables). This is where most code-gen tools fall down, in that they struggle to create objects for these screens.

 

In a sense, that’s OK though, because those are the screens (use cases) where you want to spend most of your design time, and where many odd and interesting things may be required.

 

Rocky

 

tmg4340 replied on Tuesday, July 29, 2008

This has always been my issue with code generators - pretty much every single one out there starts with database tables and goes from there.  Sure, many of them work off views as well, but ultimately every code generation step is tied to how your database is set up.  Why should I have to create a view simply to create a piece of code?

(And if anyone knows of a code generator that can build BO's off the output of a stored procedure - including one that returns multiple result sets - please let me know...)

I know that Rocky has mentioned that Magenic built a code generator for their CSLA use.  He can't share it with us, but perhaps he can shed some light on what they did concerning this issue.

Joe is a big proponent of the "1 table, 1 BO" option with use-case controllers.  It seems to work very well for him, so perhaps he can shed some light on how databinding works.  I am also wondering about the "excess weight" of the objects - after all, I may not need all the data from a particular record for a particular use case...

As for the DAL, I tend to match my DAL structure to my BO structure.  So if I have a Project BO, I'll have a ProjectDAL object as well.  The kicker to this concept is that you can pretty much eliminate code generation with this option if you're not careful - and a DAL is the perfect place for code generation.  So how mine usually get structured is something similar to Joe's use-case controllers.  I generate the DAL from my DB schema, and then I create my ProjectDAL object, which just consolidates calls from other objects as necessary.  You do have to design your stored procedures (if you use them) to work with this style, but a lot of times those can be code-genned too - often times all you need are basic SELECT/INSERT/UPDATE/DELETE procedures.

(Where this usually breaks down are the SELECT procedures, since I'm often returning multiple result sets.  But that's not always the case, and if those are the only SP's I have to write and manually code for, then I feel like I'm ahead of the game.)

Of course, I have yet to dive into 3.5 and LINQ, so once I get some time to do that, I might look at this whole thing differently.  And who knows what's going to happen with the Entity Framework?

HTH

- Scott

Michael Hildner replied on Tuesday, July 29, 2008

tmg4340:

(And if anyone knows of a code generator that can build BO's off the output of a stored procedure - including one that returns multiple result sets - please let me know...)

CodeSmith does that. I'm using the free version (v2.6) and Ricky's (I think it's Ricky) templates.

Wbmstrmjb replied on Tuesday, July 29, 2008

Where can you find CodeSmith's free version?  I've looked around and it seems now that they're charging for it, the free one has disappeared.

Michael Hildner replied on Tuesday, July 29, 2008

http://www.codesmithtools.com/freeware.aspx

Wbmstrmjb replied on Tuesday, July 29, 2008

I too am very interested in Joe's approach.  I think it will help to have a starting point that is somewhat familiar to me.  It seems that with that apporach though, you have disconnected objects that do not know about each other, only about themselves.  Basically you have a ton of editable root objects that are standalone?  Please ellaborate.

JoeFallon1 replied on Wednesday, July 30, 2008

"Basically you have a ton of editable root objects that are standalone? "

Yes. In a way.

The Use Case Controller BO is a root BO which contains all the other BOs required for the use case. So the other BOs do not know about each other (unless they are nested themselves). For example the UCC BO could contain an Order object which has a Lines collection made of many Line objects. It could also contain a couple of NVLs, an ROC and anything else you may need.

So when you call DataPortal_Create on the UCC you may pass the OrderID as the criteria. The UCC then fetches the Order (and its lines) using the OrderID. It also fetches the 2 NVLs for that use case and the ROC of related data. Each BO is exposed as a ReadOnly Property in the UCC so that you can manipulate its data, but not swap out the reference itself.

The UCC can have its own validation rules which can cross over the BOs contained in it. So it can be used to execute some fancy logic that is outside the scope of the contained BOs. e.g. The Order BO should not need to know about the state of some other related data which is not strictly part of the order. The UCC takes care of this.

When you call IsValid on the UCC, it checks its own rules and then checks IsValid for the contained BOs.

These UCC BOs are most useful on exactly the screens described by Rocky - the complex screens with lots of business logic.

HTH

Joe

Wbmstrmjb replied on Wednesday, July 30, 2008

This is exactly how I used to build apps and much easier for me to wrap my head around.

How well does databinding work for this scenario?  I normally shy away from databinding because of some of the quirkiness, but it certainly makes things more elegant when you don't have to spell out each "update" that needs to occur as a result of property change.  I would assume that you are databinding to the UCC BO and that the internal objects like Order and OrderLines would be exposed to bind to their properties.  How does that work out in terms of business rules that are encapsulated in the UCC BO? 

For instance, let's say the Order must have two OrderLines to be valid.  I would assume this business rule would be in UCC BO because your Order BO has no knowledge of the OrderLines BO and vice versa.  If you were to place a validator on the screen to make sure that there were two lines, I assume you'd bind it to the UCC BO's IsValid.  When two lines are added to the OrderLines BO, does the UCC BO "know" that those lines were added given that they weren't added to it, but rather one of it's internal objects?

I hope that example makes sense.  Thanks.

JoeFallon1 replied on Wednesday, July 30, 2008

"I would assume this business rule would be in UCC BO because your Order BO has no knowledge of the OrderLines BO and vice versa. "

Bad example. The OrderLines is a child of the Orders BO so the Orders BO *does* have knowledge of it. So the rule is in the Orders BO that there must be at least 1 (or 2 if you want) lines.

I shy away from Databinding and datasources in my web app.

When values are set in each BO the rules are run automatically (as is standard CSLA behavior). When the user posts the page I check IsValid of the UCC BO and if it is not then I send a message to the user which contains all the broken rules. I have a method which builds the broken rules for a given BO and all its contained children.

Joe

 

Wbmstrmjb replied on Wednesday, July 30, 2008

You are correct.  That is a bad example since lines don't stand on their own.  A better example that we all know would be PT. 

Although Projects have People as children, People also have Projects as children.  Thus there are two separate classes for each (as a parent and as a child).  In your methodology, I assume that you would have both as Editable Roots and a UCC that has both inside it for each scenario.  Maybe this is a misuderstanding on my part.  If my assumptions are correct, then each know nothing of the other and if there were business rules that stated each project must have at least one Resource (Person) and each Resource must be assigned to at least one Project, then the UCCs would each have those rules respectively. 

But how does changing the property of one object inside the UCC propogate up to the UCC so that it knows whether it is valid?  PropertyChanged would be fired on the (for example) Resource and thus Resources would get it's "validation", but the UCC doesn't know that there was a change.

Is this a better example?

JoeFallon1 replied on Thursday, July 31, 2008

A long time ago I wrote code to recursively search through a BO and its contained BOs for IsValid and IsDirty. So I do not have to do those overrides anymore. (I have posted it here many times.)

I think Rocky just added this functionality to 3.5 but I have not compared the implementations in detail yet. So a root BO can know if it IsValid and if its contained BOs are valid.

In regards to your example - if there are 2 different screens which use the "opposite" cases like you describe then Yes - there would be 2 UCC BOs which have different BOs inside them. Sometimes you have a DB relationship like that but you only have 1 screen where you enforce 1 side of it - in that case you only need 1 UCC.

Joe

 

ajj3085 replied on Tuesday, July 29, 2008

Someday I'm going to look into making a Visio plugin that will generate BOs from class diagrams.  Smile [:)]

Copyright (c) Marimer LLC