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?


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 :)
Does anyone solve this now in a way they like?
The shopping cart. Free shipping with purchases over $XYZ is a great up-selling tool, and should be prominently displayed in the shopping cart.
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.
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.
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
I was thinking of the cart as a page, not as an object, sorry :)
"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.
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 :-)
BDUF = Big Design Up Front
http://en.wikipedia.org/wiki/Big_Design_Up_Front
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
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!
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?
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.
If I'm out of line, just say so. ;)
The actual implementation of the rules in the product objects would depend on other requirements, like how often will those rules change.
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.
Clearly.
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.
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.
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!
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.
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!
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?
LOL
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.
If the 5 rules mentioned encompass the extent of configuration options for this product then I wouldn't use it.
- 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.
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.
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.
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
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.
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.