Fundamental questions for a simple BO

Fundamental questions for a simple BO

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


Activator posted on Friday, August 10, 2007

Hello,

I'm new to CSLA, and now I have to create a simple BO in a project that uses CSLA. None of the original programmers is available at this moment, but I want to write code that conforms to the CSLA way how it should be done. Below I have some code (simplified for readibility), hopefully you can give me some feedback about some fundamental questions I have.

The BO is a (MailingList)Subscription. Users can subscribe by entering their email address, and optionally their name.

These are the first lines in my UI code:
Subscription s = Subscription.GetSubscription(txtEmail.Text);
if (s == null) s = Subscription.NewSubscription(txtEmail.Text);

My first question is about the necessary factory methods. Under water, each Subscription has a unique ID, and since I find that one in every BO I see, I've implemented the GetSubscription(ID) and NewSubscription(ID) factory methods, that use the (standard) Criteria object with only the ID in it, although they are not used now. Is that OK?

Additionally, since the UI uses the email address as the identifier, I also have an overloaded factory method NewSubscription(string email), that uses the NewCriteria class to pass the parameters. I could also name that class EmailCriteria, but since later on maybe not only the email will be in that class, and I find the NewCriteria name in various examples, so I decided to use that name. Is that OK?

Additionally, I have the GetSubscriptionByEmail(string email) factory method, that uses also the NewCriteria. Now, that name NewCriteria makes less sense. What should I do?

I also have a second question. Here's my UI code again:
Subscription s = Subscription.GetSubscription(txtEmail.Text);
if (s == null) s = Subscription.NewSubscription(txtEmail.Text);
s.Name = "txtName.Text";
s.Subscribe();

My question is about the s.Subscribe(): I didn't want to use the Save() method because it's not really saving the object, but additionally do some business logic that is particular for subscribing, i.e. setting the subscription date and marking the subscription as active (those are also properties of the BO). Is this a good way of thinking? Or should I use the Save() method and solve the business logic in another place?

I have implemented this Subscribe() method in the #region Business Methods of the BO: public void Subscribe(). Is this indeed supposed to be void or should it return a Subscription object?

And a final question: From this business method Subscribe(), should I set the properties and call the Save() method, or should the Subscribe() method call a factory method first, or should it call DataPortal.Execute with my own command? The DataPortal_Execute is an area that is not yet very clear for me right now.

If you could help me out with the above questions, I would appreciate that very very much! Thank you very much in advance for your time and help!

Kind regards,
Jeroen

RockfordLhotka replied on Friday, August 10, 2007

I am a minimalist. So I suggest that if you don't use a method, don't implement that method. No sense maintaining code that isn't used Smile [:)]

So drop the unused factories and unused criteria class(es) and only keep those you use.

I disagree with your Subscribe() method. Your object is a subscription, that's what it represents. It makes no sense for a subscription to subscribe to itself. You are creating/editing a subscription, and when you are done changing it, you are saving that subscription. So Save() makes perfect sense.

If you had a Customer object I could see it having a Subscribe() method, because a customer might subscribe to something. But that's not the case here.

It is possible that you have two use cases:

  1. Create/edit subscription information
  2. Activate the subscription

I don't know if this is the case, but you seem to be differentiating between "subscribe" and "save", so I'm guessing this might be the case.

If so, I'd suggest that your Subscription object serves the first use case well.

There are a couple ways to handle the second use case. One is to use the same Subscription object and just give it an Active property to indicate whether the subscription is active or not.

The second way is to use a command object to activate the subscription. The UI code to activate (or deactivate?) a subscription would be like:

SubscriptionManager.Activate(txtEmail.Text);
SubscriptionManager.Deactivate(txtEmail.Text);

You can see an example of a command object by looking at the Exists() command implementation in the Project class of ProjectTracker in chatper 8. Just make your command object's scope public to get the effect I'm showing here.

All this object would do, is have a DataPortal_Execute() that does a SQL UPDATE to change the activated flag (and any other data) in the database. Very simple and focused.

Activator replied on Friday, August 10, 2007

First of all, thank you very much for your very fast response!  I'll follow the advises you gave!

Maybe the following will clarify my thoughts:

My BO has the following fields: ID, Email, Name, IsActive, SubscribeDate, UnsubscribeDate.

I have indeed 2 use cases:
1. activate subscription (insert a new record in the database if email does not exists yet, OR reuse an existing inactive record with this email address)
2. deactivate subscription (set the active flag false, but leave the record in the database for marketing purposes)

What I wanted was not having to let the UI mess with the IsActive flag and the date fields, but leave that to the BO itself, so the UI would only have to say: Subscribe() or Unsubscribe(). I don't completely understand if this bites your suggested solution right now, but this weekend I'll try more!

Kind regards,
Jeroen


 

JoeFallon1 replied on Monday, August 13, 2007

Activator:

Hello,

I'm new to CSLA, and now I have to create a simple BO in a project that uses CSLA. None of the original programmers is available at this moment, but I want to write code that conforms to the CSLA way how it should be done. Below I have some code (simplified for readibility), hopefully you can give me some feedback about some fundamental questions I have.

The BO is a (MailingList)Subscription. Users can subscribe by entering their email address, and optionally their name.

These are the first lines in my UI code:
Subscription s = Subscription.GetSubscription(txtEmail.Text);
if (s == null) s = Subscription.NewSubscription(txtEmail.Text);

My first question is about the necessary factory methods. Under water, each Subscription has a unique ID, and since I find that one in every BO I see, I've implemented the GetSubscription(ID) and NewSubscription(ID) factory methods, that use the (standard) Criteria object with only the ID in it, although they are not used now. Is that OK?

Additionally, since the UI uses the email address as the identifier, I also have an overloaded factory method NewSubscription(string email), that uses the NewCriteria class to pass the parameters. I could also name that class EmailCriteria, but since later on maybe not only the email will be in that class, and I find the NewCriteria name in various examples, so I decided to use that name. Is that OK?

Additionally, I have the GetSubscriptionByEmail(string email) factory method, that uses also the NewCriteria. Now, that name NewCriteria makes less sense. What should I do?

I also have a second question. Here's my UI code again:
Subscription s = Subscription.GetSubscription(txtEmail.Text);
if (s == null) s = Subscription.NewSubscription(txtEmail.Text);
s.Name = "txtName.Text";
s.Subscribe();

My question is about the s.Subscribe(): I didn't want to use the Save() method because it's not really saving the object, but additionally do some business logic that is particular for subscribing, i.e. setting the subscription date and marking the subscription as active (those are also properties of the BO). Is this a good way of thinking? Or should I use the Save() method and solve the business logic in another place?

I have implemented this Subscribe() method in the #region Business Methods of the BO: public void Subscribe(). Is this indeed supposed to be void or should it return a Subscription object?

And a final question: From this business method Subscribe(), should I set the properties and call the Save() method, or should the Subscribe() method call a factory method first, or should it call DataPortal.Execute with my own command? The DataPortal_Execute is an area that is not yet very clear for me right now.

If you could help me out with the above questions, I would appreciate that very very much! Thank you very much in advance for your time and help!

Kind regards,
Jeroen

Jeroen,

Some comments:

===================================================================

These are the first lines in my UI code:
Subscription s = Subscription.GetSubscription(txtEmail.Text);
if (s == null) s = Subscription.NewSubscription(txtEmail.Text);

This only works if you are guaranteed that GetSubscription really returns Null. It could return an Exception or a new BO depending on your code.

===================================================================

Having standard factory methods that use the PK (the ID field) are fine. As Rocky says you could always remove them if nothing really uses them. But if you plan to use them in the near future it does not hurt ot leave them. You can consider commenting them out too.

===================================================================

"NewCriteria class to pass the parameters. I could also name that class EmailCriteria,"

This is fine. Naming of criteria classes is up to you. Making it something useful never hurts. Both names are fine here. A long time ago I decided to create a Criteria namespace and then remove all of my criteria from inside thier BO classes. By putting them in their own namespace I get complete re-use of the same Criteria class for many BOs. So I tend to give mine bland names like:

CriteriaCode - where the PK is a strong code field like ID.

CriteriaKey - where the PK is an integer key field.

These get used A LOT.

I have others where I need to pas 2 or 3 parameters and I made the much more specific. I tried to gernalize them but that was more confusing to use.

e.g. CriteriaNameStatus takes a Name parameter and a Status parameter (both strings.)

I could also have called it CriteriaCode1Code2 but that gets confusing.

===================================================================

Now, that name NewCriteria makes less sense. What should I do?

Nothing. It makes perfect sense to me. See above.

===================================================================

I have implemented this Subscribe() method in the #region Business Methods of the BO: public void Subscribe(). Is this indeed supposed to be void or should it return a Subscription object?

See Rocky's comments on Subscribe method.

If your Subscribe method saves properties of your BO to the DB then you should write it in the Factory Methods section. It should emulate the Save code so yes it should return a Subscription object. You can leave the name as Subscribe if you want. But Save makes jsut as much sense.

Any time you save a BO it goes through the DataPortal. You can branch you code once in the DP though. e.g. You can do a "full save of all object properties." Or you can update a couple of the fields in the DB only. It depends on what you are doing. Rocky recommends having a BO with a single responsibility so sometimes you create 2 BOs do do these 2 things instead of branching code in the DP.

e.g. Full Save is in the DP of your Subscription BO.

Update a few fields is in a new BO derived from CommandBase which handles that one ta

===================================================================

 

 

 

Copyright (c) Marimer LLC