Halhelms
SIGN UP FOR MY NEWSLETTER
 
 
Halhelms

Shameless Money

Recent Entries

RSS

Subscribe

Project Serenity

Every cool project needs a cool code name. The open source ColdFusion ecommerce project now has one: Project Serenity.

First question for aspiring software architects: how do we deal with use cases such as...

1. During the month of December, second-day shipping is free

2. If you buy product X, shipping is free

3. If you buy more than $200, you get a free gift

4. During this weekend, no sales tax will be charged

5. On certain days (e.g. Sabbath), no purchases can be made

These are obviously business rules. Question: how do we integrate business rules into an ecommerce system?

Thoughts?

Comments
Ben Nadel's Gravatar I guess the first question is who has to know about what? Is is the shopping cart's business to know what purchases can not be made on a given day? Or is that the "store".

Does the store care about free shipping for a certain amount of purchase? Or is that the responsibility of the shopping cart?

All difficult questions :)
# Posted By Ben Nadel | 6/30/09 12:22 PM
Hal's Gravatar It's my contention that the cart should NOT know anything about the business logic. If it's the cart's responsibility, we're going to have (I think) a lot of ongoing customization in the cart.

Does anyone solve this now in a way they like?
# Posted By Hal | 6/30/09 12:28 PM
Shannon Hicks's Gravatar "Does the store care about free shipping for a certain amount of purchase? Or is that the responsibility of the shopping cart?"

The shopping cart. Free shipping with purchases over $XYZ is a great up-selling tool, and should be prominently displayed in the shopping cart.
# Posted By Shannon Hicks | 6/30/09 12:29 PM
Shannon Hicks's Gravatar Also, most customers want to know what the shipping cost will be, by entering their zip code in the cart interface.
# Posted By Shannon Hicks | 6/30/09 12:31 PM
Jeff Chastain's Gravatar Sounds like you need a business rules engine. I know there are several Java based ones, but I have never seen one put together in ColdFusion.
# Posted By Jeff Chastain | 6/30/09 12:31 PM
Raymond Camden's Gravatar You can look at these rules at a high level as:

If (time check/total in cart/num in cart) matches value
you get reward of (free product/discount in $/discount in %/no ship cost flag/no tax).

That could cover many of the discounts. I'd consider the Sabbath rule to be outside of this area of concern as it applies to the store as a whole.
# Posted By Raymond Camden | 6/30/09 12:31 PM
Ben Nadel's Gravatar @Hal,

I think I agree with you.

@Shannon,

I think you can come up with ways to have the page display deals without having the cart know too much. For example, the page could simply get the subTotal() of the cart and then display accordingly. This way, the logic could be kept out of the cart.
# Posted By Ben Nadel | 6/30/09 12:32 PM
Curt Gratz's Gravatar One thing that I have done is something I call a "pricefixer" method or cfc.
I pass the product through this and see if there are any business rules that need
to be applied to it before adding to the cart that would adjust its price. I
do something similar with shipping, to see if the "cart" meets any business rules
to reduce the shipping charges. That way the business rules for discounting is
encapsulated outside the "normal" process, and if there are no discounts, the
methods don't adjust the price. Doesn't handle all of your given scenarios, but
should handle most.

Just a thought. I would be interested in opinions on this idea.

Thanks,
Curt Gratz
Computer Know How
Coldbox Alliance Partner
# Posted By Curt Gratz | 6/30/09 12:32 PM
Shannon Hicks's Gravatar @Ben

I was thinking of the cart as a page, not as an object, sorry :)
# Posted By Shannon Hicks | 6/30/09 12:34 PM
Shannon Hicks's Gravatar How would you handle a promotion like buy one get one, or buy X and get Y for a special price/free? Don't some kinds of promotions need to be handled at a cart level?
# Posted By Shannon Hicks | 6/30/09 12:36 PM
Raymond Camden's Gravatar @Shannon Hicks:
"How would you handle a promotion like buy one get one, or buy X and get Y for a special price/free? "

Those are both the same rule, buy X get Y for free/reduced price. I'd assume rules would have a nice text string for descriptions "Hey, because we love red, all the red bikinis are on sale this weekend!" so that would be used to differentiate between a "BOGO" sale and a related product sale.
# Posted By Raymond Camden | 6/30/09 12:38 PM
Peter Bell's Gravatar Do I get away with "it depends"?! I generally do the following. I have an Order object which has 0.* OrderItems. For me a shopping basket is simply an order where status=cart. This has strengths and weaknesses, but means you don't need to replicate a lot of behavior between the two objects. If you found a lot of status specific behavior you could subclass an AbstractOrder with a Cart and a PlacedOrder, but I haven't bothered to so far.

Generally an order knows how to getShippingCost - delegating to a ShippingCalculator if and only if the rules get really complex. Generally I put these kinds of business rules into the Order object or a composed object that it delegates to.

I personally find the concept of "business rules" one I try not to model as you can end up in this strange place where you have "Rules" but some affect display of ad banners, others affect discounting, others affect shipping and others affect what products you're allowed to view. Sometimes that is a useful modeling approach where the focus is on the business user management of the rules, but typically I find it more useful to model my shipping rules, discounting rules, product display/security rules, pricing rules and the like separately. Of course, if I needed to be able to manage and display rules across those boundaries, using business rules as a modeling concept might make more sense.

I think by documenting scenarios and user stories you're likely to be able to make more meaningful decisions. If you're got user stories about business users listing, adding, editing and deleting "business rules", that's going to suggest a different model than if the focus of the stories is on end user behaviors where it may make more sense to just implement the business rules in the appropriate Order methods.

I'd also suggest just building something and allowing the design to emerge rather than trying to BDUF the ultimate e-commerce rules builder, because the truth is that there isn't one. The texture, shape and feel of the actual rules you need to implement will drive the api's and/or DSLs you'll write to implement them (but as an ex woodworker, I'm sufre you know all about going with the feel of a particular piece of wood :-) ).

Just my 20c :-)
# Posted By Peter Bell | 6/30/09 12:45 PM
Raymond Camden's Gravatar For folks who may not know it (thanks Peter, learned something new):

BDUF = Big Design Up Front

http://en.wikipedia.org/wiki/Big_Design_Up_Front
# Posted By Raymond Camden | 6/30/09 12:47 PM
Peter Bell's Gravatar Thanks for the clarification. Sorry - hanging out too much around the agile groupies - you start to assume terminology.
# Posted By Peter Bell | 6/30/09 12:51 PM
Curt Gratz's Gravatar @Shannon

In the past I have just added another item to the cart at a $0.00 price with a nice description like
Ray had said. I have my "pricefixer" (for lack of a better name) method add this product to the cart
if certain rules are met.

Curt Gratz
# Posted By Curt Gratz | 6/30/09 12:52 PM
Shaun W.'s Gravatar This is great news Hal!

SiteDirector by Quill Design is the best open source CF ecommerce software I have found to date (via Clark V.) but leaves a lot to be desired.

I want Serenity Now!
# Posted By Shaun W. | 6/30/09 12:56 PM
Jamie Krug's Gravatar Thanks for easing us into things with such a simple question, Hal ;-)

Peter's line of thinking on this is making sense to me. I can see business rules being implemented within the appropriate Order methods, to a degree. If size/quantity/complexity grows, maybe make use of the Strategy Pattern to handle relevant calculations?
# Posted By Jamie Krug | 6/30/09 12:59 PM
Adrian J. Moreno's Gravatar I'd agree on the Rules Engine. At my last gig (insurance company), my team built one (using CF) for the payment application. It took into account user type, if a user was logged in or not, status of the policy, dates, etc.. We had planned out a larger RE for creating quotes, but that was shelved in favor of another solution.

Bottom line is define the rules for various sections of the application, define how rules are interpreted and then create a single way to process rules.

1. Shipping Rules
2. BOGO Rules
3. Discount Rules
4. Gift Rules

etc.
# Posted By Adrian J. Moreno | 6/30/09 1:01 PM
Raymond Camden's Gravatar Can I ask though - if we want to start simple - does it make sense to work on the rules first? I would have thought basic item management, order processing, would be our initial concerns, and things like discounts/etc would come later? I'm not saying we shouldn't think about it of course - but does it make sense to worry about that before the basics? If I can't go to a store, add an item, and checkout, then no amount of discounts will help me. :)

If I'm out of line, just say so. ;)
# Posted By Raymond Camden | 6/30/09 1:05 PM
Howard Fore's Gravatar I'd likely start with a master product object. The master product would implement the logic for rules 1,3,4, and 5, as these affect all products in the cart. Then you iterate over the specific products in the cart, which extend the master product. One of these products would implement rule 2. The cart doesn't need to know how to modify the various amounts for totals, shipping, tax, etc. Each product will affect those so the logic for those algorithms shoudl be in the objects themselves. The cart is sort of a mini-controller at that point, with future touchpoints to payment system and shipping system objects.

The actual implementation of the rules in the product objects would depend on other requirements, like how often will those rules change.
# Posted By Howard Fore | 6/30/09 1:11 PM
Peter Bell's Gravatar I'm with Ray - I'd start with thin and complete. Start with ViewProducts story that'll elicit a ProductCatalog controller, a Product and ProductCategory object and category-view, product-list and product-view screens. Then maybe an "AddProductsToCart" story that'll add a Cart controller and some kind of Cart and CartItem or Order and OrderItem objects along with a cart-view screen.

I'd start simple, finishing off with a basic paypal checkout with very simple shipping rules. I'd then start adding product attributes, attribute options, different images, skus, weights and prices on a per attribute-option basis. Add support for multiple sku's to display on a single screen and so on. Then more complex shipping rules, discounting, cross sells, etc. And I'd release something very simple but fairly easy to extend.

I'd also consider leveraging a popular mvc framework with good extension capabilities. I quite like the flexibility of CB, although MG and M2 are great choices also. I don't use any of those frameworks in my product line, but if I was doing an OSS project in the CF world I think it'd be easier to get everyone up to speed if it was build on existing frameworks that everyone knew or could learn easily, and CB already has lots of support for interceptors, plugins, etc that could be easily leveraged for something like this.

That said, that's what I'd do - but it's not my project! Whatever happens I look forward to hearing more about this. There was also a cfcommerce group with some other people interested in doing something like this but it fizzled out. I'd also check out the cfpayment project as that'd be a nice fit potentially . . .

I know last time this came up it ended up with the suggestion of having a number of smaller plugable projects so you could use or not use whatever you wanted, but none of us got serious enough to deliver any working code.
# Posted By Peter Bell | 6/30/09 1:49 PM
John F's Gravatar Implicit in this complexification is an assumption of clairoyance. Project Serenity has the potential to make all serene all business logic to which one might otherwise subscribe.

Clearly.
# Posted By John F | 6/30/09 1:51 PM
Hal's Gravatar @Peter Note to self: Do NOT get off on a rant about frAgile...

Oh, what the heck... I'm in agreement with Joel Spolsky who, writing about this, said, "BDUF has saved me a great deal of time and money over the years."

@Ray The reason I bring this up now, Ray, is that it's important to think in terms of responsibilities, as Ben noted. Whose job IS it to handle business logic?

The problem with starting to build something is that these big questions go unanswered and architectural decisions are made not fully informed. I'm not saying this is the only way to architect -- just the way that has worked for me. I think we all know how to do a basic cart, but the idea of business rules is one that has been a very difficult one.

But let's continue the discussion. I'm open to changing my method.
# Posted By Hal | 6/30/09 2:22 PM
Hal's Gravatar @Shannon, the way I handle this is like so:
1. A page's "Buy" button is clicked.

2. An "addItemToCart" event is announced with various arguments in it.

3. A listenery dohickey listens for "addItemToCart" and translates this into a call to a controllery thing, passing a newly minted "eventObject".

4. The event is intercepted by a Rules thingy that is free to change the eventObject. So if today is Shabbos, change the event from "addItemToCart" to "explainDayOfRest".

5. The call to the controllery thing continues.

6. Assuming the original event hasn't been modified, the controllery thing announces something adds the item to the cart and registers a new event in the eventObject -- something like "itemAddedToCart".

7. The Rules thingy again intercepts the event and can execute its own logic. As in "if the user bought X, add Y to their cart with a price of 0".

8. The Rules thingy can change any values in the eventObject, including the next event to be announced.

9. The announcing guy announces the event located in the eventObject and we've completed the event lifecycle.

That's just how I do it.
# Posted By Hal | 6/30/09 2:37 PM
Ryan Miller's Gravatar @Hal: I was thinking about some of my recent readings from Joel Spolsky. I'm glad you were too.

General words of advice: Don't get too hung up. Make a decision, move forward. There is always version 2.0.

For some of your business rule use cases, what if you created 2 items (shipping and tax) each of which were auto-magically added to the shopping cart when viewing the cart and checking out. These two items would have their own business rules that would variably change price based on contents in the shopping cart, day of week, time of year, etc.

Keeping to the Spolsky theme, I hope you have a "ship" date. Otherwise, you'll be asking about and adding features for another 5 years. Ok, well, maybe not that long. Is #5 really needed? Why would you not want to open your online store, even for a day? Prioritize and meet your ship date.

Good luck!
# Posted By Ryan Miller | 6/30/09 4:50 PM
anthony's Gravatar @Hal,

I think one way of thinking about this would be to break the rules into types. From what I can tell there are 3 types.

-Before add to cart rules (ex. check for Shabbath). I think these rules fall into a different category since they don't alter the cart totals. These rules seem more like validation logic which should stop or continue the addToCart event.

-Add to cart rules or product specific rules(ex. check if item is on sale)

-After add to cart rules or cart specific rules (ex. check if order is over $200)

Obviously the rules in the "Rules" object should have sort orders and the ability to stop processing other rules (no free shipping if you are already getting 50% off your order).

Just my thoughts.
# Posted By anthony | 6/30/09 5:33 PM
Andy Sandefer's Gravatar I've written a lot of programs like this - some in CF and some in fat client ERP systems. Break the rules down by type and figure out when (the events) we will test for their existence. Some rules are contingent upon the sum of the parts (the running total of the order and what it is comprised of) and some rules are contingent upon time (the calendar/date and time rules). It seems quite obvious to me that anytime you add, update or delete an item for the order you'll test for these rules and update all running totals while the order is being built (you can easily display little ajax driven messages that read to the effect of "buy another 24.35 worth of crap and get free shipping"). Has everyone truly thought this ALL the way through? What happens if I'm shopping at 11:55PM EST on a Saturday night and by the time I finish my order it is now Sunday and Hal's wacky no buying on Sunday rule applies? Sounds like a breeding ground for angry customers to me.
You're going to have categorize and subcategorize business rules and in some cases you will have an order of operations where compound conditions allow certain rules to trump other rules.
As an example, I worked in a system where there were order discounts (orders with a total greater than or equal to X would yield a percentage discount), item qty. discounts (order a certain quantity of an item and receive price level breaks contingent upon the total qty. ordered, as well as customer/item discounts (certain customers or groups of customers received specific pricing for certain items or groups of items) - all of these had configurable date ranges as well that the system used to determine whether or not these rules applied based on order date. To complicate matters, if multiple discount conditions existed then additional logic was used that either allowed or disallowed the compounding of these discount types.
Other rules included decision making logic for VAT tax vs. US State Sales Tax, custom shipping charge logic etc.
This all sounds far too broad to even begin writing an app around. Nail down the events and to what extent the rules are allowed to work together and maybe we can start something!
# Posted By Andy Sandefer | 6/30/09 5:47 PM
anthony's Gravatar @Andy
I think the no buying on the Sabbath Rule is kind of crazy, but what if you are building a site like woot.com and you need a rule to stop people from buying specific products on a specific day?
# Posted By anthony | 6/30/09 6:01 PM
Andy Sandefer's Gravatar @anthony - That's actually quite easy if you have a sub-table with a composite key of ItemID and DayOfWeek (or could be a specific date, date range, etc.). If you're really smart about it you'll build a filter for this into the query logic that fetches the item list for items that are not in the subtable vs. the day of week (or whatever criteria you went with) and you'll also check for it before you allow an insert into the cart (in case you're allowing people to store favs or order templates - a template used and saved on a Tuesday might not be valid on a Friday in your scenario, etc.).
# Posted By Andy Sandefer | 6/30/09 6:06 PM
Andy Sandefer's Gravatar The only Sabbath I want is Black Sabbath - this site should load Ironman on page load!
LOL
# Posted By Andy Sandefer | 6/30/09 6:08 PM
anthony's Gravatar @andy
I think your idea is why we are having this discussion, so we can figure out how to handle these situations. So in my earlier comment about rule types, the "before cart add rules" should actually be executed every time I look at my cart. That further separates it from cart and item specific rules.
# Posted By anthony | 6/30/09 6:20 PM
Andy Sandefer's Gravatar Well I like to remind clients that the more we design the business logic (and agree not to drastically change it) the less re-development we'll have to do. My point was that the specs (rules) provided were not defined to a point where we could truly start talking about development.
If the 5 rules mentioned encompass the extent of configuration options for this product then I wouldn't use it.
# Posted By Andy Sandefer | 6/30/09 6:31 PM
Marc Henkel's Gravatar Perhaps a list of sample business rules could be started to see if we can discern a pattern? Maybe break it out into must-have and would-be-nice?
# Posted By Marc Henkel | 6/30/09 7:09 PM
Steven Esser's Gravatar 1. During the month of December, second-day shipping is free
- Hmm yeah.. business logic for shipping calculators. I usually build my shipping calculator at
order level so not at the cart really, but rather at the processing of the order and then things as
customer addressing and shipping methods are calculated. I'm not quite sure what second-day shipping means
but I am sure you can program such thing at that level.

2. If you buy product X, shipping is free
This could be build at product level really. An extra field in the product table for ShippingCategory
linked to the ShippingCategories Table (with one of the records a 0).

3. If you buy more than $200, you get a free gift
This is at order level. And most likely order system is part of the cart system.
This is perhaps a certain functionality that can be switched on/off at CMS level, which also
controls a little message displaying/hiding at the cart level for the special offer and a banner
somewhere else for example.

4. During this weekend, no sales tax will be charged
Again something for the cart at order level. No messages for the cart. I generally prefer to show
prices ex tax on the whole website or make it including taxes but place a little warning of possible
price inaccuracy on the website.

5. On certain days (e.g. Sabbath), no purchases can be made
This is certainly on businesslogic but if your business is a shop only really, it could be added at CMS
level where you can select your opening or rather your closing times. Otherwise I would use a banner or
message showing that you are not shipping anything during the special days (news item really and extra
note at cart + order level). But the shop shouldn't shut down in my opinion, that is the whole deal with
online shops in my opinion: that you can show whenever, wherever and whatever time.
If a website should completely shut down at certain days this could also be implemented at CMS level
or the web owner should just simply click the option: show shop offline: which is nowadays available
in systems such as Mambo.
# Posted By Steven Esser | 6/30/09 7:27 PM
Hal's Gravatar Here's my thinking about the system. It should be flexible enough that the business rules can be applied OUTSIDE the ecommerce code itself. Otherwise, with every new business rule, we're going to have to go in and change the code that should be stable and closed for modification.

If there's a clean API for interacting with the ecommerce system, then any rules processing can happen outside that system. Applying business rules is definitely a complex task; my point is that the ecommerce system should expose methods that make it possible to do things like add free shipping or adding a free product if you order another one, but those rules should NOT be a part of the system.
# Posted By Hal | 6/30/09 7:39 PM
anthony's Gravatar You should be able to add and remove rule types without breaking the whole thing, so it doesn't really matter what the rules are, just where they should be placed.

It wouldn't make sense to attach these things specifically to the cart and item tables. An item shouldn't know that it's on sale. An item knows it's own price, and another object (maybe the rules object?) should know that the item is on sale when it gets to the cart. Ideally the items table should only have a few base attributes (title, description, sku, weight, etc.) that will apply to any item, regardless of what it is.

This brings up another item of interest, storing products in a DB. Different product types will need different attributes (ex. a toilet can have a gallons/flush attribute, but a TV can't). I've always hated using EAV tables for storing data, but I always end up having to use them since I can't think of a better alternative.
# Posted By anthony | 6/30/09 8:09 PM
Andy Sandefer's Gravatar @Hal
What about a data driven type of setup? If you have a method that looks to a table that holds the business rules and that table has the info needed to decide whether or not a rule is in play, how the parent method can call it and finally if it has dependencies on other business rule methods then it would be possible to change the behavior of the system by adding records to this "business rules" table. Then the only thing that the order management/shopping cart management code needs to know is that it must query this table on an event by event basis and execute whatever is there in the proper order.
It sounds like a lot of work but I'll bet that it was hard to build SARK, TRON and the MCP too!
LOL
# Posted By Andy Sandefer | 7/1/09 2:13 PM
Phillip Senn's Gravatar Bob Silverberg just did a cfmeetup called "An Object Oriented Approach to Validations", where he talks about putting the business rules in one place:
http://experts.na3.acrobat.com/p40599889/

@Anthony, your post about EAV tables was perfectly timed.
I was just handed a project this morning that requires information about patients.
I was curious what you meant by EAV tables, and this article
http://en.wikipedia.org/wiki/Entity-Attribute-Valu...
described my new project perfectly.
So much to learn! But perhaps I can take what Hal decides to do and apply it to my project as well.
# Posted By Phillip Senn | 7/1/09 2:15 PM
Sean N Henderson's Gravatar For some retailers, there's a MAP requirement for certain manus. (Minimum Advertised Price) The business/legal situation is that once the person puts the item into the cart, the transaction is then thought to be "in negotiation". At that point the real/lower price can now be legally/contractually displayed. So in this situation, the cart had to be sentient/application-like, not dumb or tool-like.
# Posted By Sean N Henderson | 7/2/09 11:34 AM
Phillip Senn's Gravatar Hal,

In your OutLoud podcasts, you said that you work from the front-end to the back. So much so that for one project you almost forgot that you still needed to program it, because your prototype looked so complete.

I'm looking forward to seeing how you go through that process, because I've found myself bouncing back and forth from database tables to html and css, to server side business rules, to client side business rules.

Do you really know your end goal before you start creating tables?

I don't have the skillset of a front-end designer, so I look at the project from the database perspective almost exclusively.
# Posted By Phillip Senn | 7/15/09 1:02 PM
 
   
Clicky Web Analytics