Be sure to have alot of time on your hands 😉 I've been developing a system on and off for about 2 years and am just now starting to get to where I want in terms of code and application design.
If this will be something you'll be using as a base to develop shops for others, there are some key things I think take precedence over things that might be more important if it was just solely for you... well one thing mainly:
- make it flexible
Flexibility is key. What do I mean by this? Make is so that the core application is not bogged down in features. Delegate features out to plugins or addons. If a feature likely won't be used by at least 75-80% of customers (or more), don't put it directly in the core. Make it easy(er) to customize and add functionality without having to funk with core code. Meaning a strong plugin API and possibly the ability to override certain parts of the core in a "user" space. This also makes rolling out core updates a zillion times easier, since theoretically, every install, no matter how customized, will have exactly the same core code.
For hierarchial structures like categories, I'd say use the Modified Preorder Tree Traversal (MPTT) method if you can. You can pull out a whole tree with a single query this way. The other major option is the common Adjacency method (as seen in most php ecommerce applications), but with this method, SQL queries quickly escalate (the more categories = more queries to build the tree).
MarkR wrote:Try to identify where things are similar and put them into the same class (/ table if using a RDBMS** via an ORM, as we are). The fewer entities the better. We have quite a lot of features in our system, and have 12 tables at the moment. Oscommerce has 48.
How are fewer entities better? Unless you are pulling data from one table at a time, one row at a time, it doesn't really make much difference. Most RBDMS are optimized to perform well up to 4 or 5 joins, which is probably about the max you'd do anyways on a single query. Depending on what level of normalization you are going for, 48 tables for an eCommerce application is nothing.
This is one reason I tend to stay away from most PHP ORM solutions, such as Propel. They escalate the number of SQL queries in table relationships, performing one query for each related table for each row, instead of pulling it all in one query and then splitting it out into objects. The n-query method is alright for some applications, but you definitely don't want that in an eCommerce system.
MarkR wrote:A design error made by a lot of shops (including oscommerce) is to consider a basket a different type of entity from an order. A basket is really just an order which hasn't been placed yet.
Couldn't agree with this more. The way I do it is a parent order class with 2 children, an order basket and an order database class. Though I use the order basket through the checkout process until the order is placed in the database and then from there when the order is accessed use the order database, naturally, one could also delegate out a 3rd child, used during the checkout process. Or take another approach entirely.
MarkR wrote:Variables / variants add a great deal of complexity - therefore, don't add them unless you REALLY have to. If you do, do at least a couple of days analysis with your other developers / customers beforehand, to study the problem in-depth. Particularly SKUs*** and stock control, but also other issues.
I think that alot of applications have the product options/variants model wrong. They kind of see them as being something optional and almost external to the product, which leads to overly complex application logic to account for when they might occur. It's also a pretty unrealistic model, IMO, and doesn't do a good job of representing what the makeup of a product looks like in reality.
This is one area where I took my cue from ElasticPath, because after much though, I think they've got it right, or much better than other systems. The model they use says that all products have at least one "variation". There is "generic" product and description information that is common to all variations, and then items like price, sku, stock, weight, etc are part of each variation. If you think about this, this is exactly true for every product under the sun.
This approach does complicate the SQL a little bit (not exactly for the faint of heart), but greatly simplifies the application logic as all products follow the same model. Not only that but is also gives greater flexibility over "multi-variation" products; you can either choose to display them as separate products, or as a single product with variants/options; but the basic product model allows for either one and doesn't force your hand to one or the other.
You can go another step further as well and add more flexibility by adding information that might be specific to a product "type". ElasticPath does this in the database with what they refer to as "attributes" I think (which are not like attributes in oscommerce or zen cart). Here I have chosen to have a product plugin API where you can create product plugins that add additional functionality, including adding and displaying additional info, for specific product "types" or product classes as I've called them.
And then again, doing something like this [extending functionality with plugins], allows a basic and relatively simple product model that can be easily expanded upon. For example a site might sell Books, CDs, and DVDs; all of which are sort of similar, yet all are quite different in terms of what you might want to do with them. So you create a plugin for each one to facilitate that; or you might go the database route and create "attribute" sets for books, for cds, and for dvds. But either way, you keep the product model relatively simple and lightweight, only having additional information exactly where it is needed (as opposed to having it there even if it isn't needed).
MarkR wrote:PSP**** integration is one of the most painful parts of it. Aim to integrate at least one PSP from day one - don't add it as an afterthought. Bear in mind the different types of integration PSPs do.
I'm not sure I agree. I think all PSP integration can be basically boiled down to a few types. You've got your advanced or transparent integration. And you've got you're 3rd party offsite integration, which could be split into a couple of types, depending on how the system notifies you of the response. If you abstract the payment system to a payment plugin API, then you can write hooks in appropriate places for the different integration types (among other things a payment plugin might want to do), and it will or should be relatively easy to write a plugin for any PSP. Getting a good plugin API would be the hard part, since you'll naturally miss some things and will be adding them in as the system evolves.