Show HN: MongoDB + open source e-commerce = Forward
getfwd.com
getfwd.com
The UI is great, it's responsive, and well thought out.
Also, the data modeling issue is a great selling point. Right now, MOST all applications are the same. Take this data, validate the person sending you the data is correct, validate the data is correct, and store it. Then apply the same methodology to fetching it, modifying it, or deleting it. I've been a django/python guy for years but after recently diving into Rails, I don't think anyone has done this any better. You can very quickly get things moving in CRUD/REST without much code.
That being said, it all comes back to the modeling. Modeling is relatively simple in Rails. The ORM you get with Django far exceeds ActiveRecord in usability but either way, at some point, a developer needs to sit down and define the data modeling. I realize you're marking this to developers (obviously) but I feel like with your cool UI and mongodb backing, you might even be able to expand this to administrators of the service.
Meaning, I can deliver a pre-configured product to my clients but if they want to add some fields to a product that are searchable/sortable/validatable/etc... they won't need to wait for me to do it. They won't need to wait for me to deploy it. I won't need to run a migration script.
Modern REST frameworks typically work based on a separation of a model and a resource. The model handles data storage and representation, and the resource handles serving it up, controlling access, etc... I think we need to couple these together. One unified object. I can create something, like a `Product`, give it some properties, set validations and permissions for those properties, and boom. Done.
Things like this and Meteor are shining examples of the radical change that we need in this current era of development. Yes, you guys will find faults in that statement. The neckbeards will come out and tell me mongodb does not scale, or node.js async development does not make sense. That is not the point. The point is that we're really not making it much easier on ourselves to build the things we want. Right now it makes more sense for me to pay Parse to handle an iOS back-end. Why? Because for the most part building it is a pain in the ass.
It doesn't need to be. I'm excited about Forward, very excited.
Why do you dislike them?
Separation of design and code seems pretty important, so having a template system that's really a (more or less limited) programming language of its own seems like a step backward to me.
Instead, Forward aims to make templates expressive and easy to understand by anyone. Time will tell if this causes problems, but for the projects we've built with it over the last year, it has been good and easy to maintain as there is no procedural connection between template/back-end.
### Example User
user: {
name: "Michael",
bio: "The quick brown fox jumped over the lazy dog.",
products: [<Product>, <Product>, ... ]
joined: "09-07-12"
}
<table>
{% for user in users %}
<tr class="{% cycle 'odd' 'even' %}">
<td class="user-name">{{ user.name }}</td>
<td class="user-bio">{{ user.bio|truncatewords:3 }}</td>
<td class="user-products">{{ user.products.count }} Product{{ user.products.count|pluralize }}</td>
<td class="user-joined">{{ user.joined|date:"M jS, Y" }}</td>
</tr>
{% endfor %}
</table>
### Would Display
<tr class="odd">
<td class="user-name">Michael</td>
<td class="user-bio">The quick brown ...</td>
<td class="user-products">2 Products</td>
<td class="user-joined">September 7th, 2012</td>
</tr> <table>
{foreach "/accounts"|get as $user}
<tr class="{cycle values="odd, even"}">
<td class="user-name">{$user.name}</td>
<td class="user-bio">{$user.bio|truncate:30}</td>
<td class="user-products">{pluralize "{$user.products.count} Products"}</td>
<td class="user-joined">{"M jS, Y"|date:$user.date_created}</td>
</tr>
{/foreach}
</table>Here are several equivalent ways of expressing this:
// PHP
$accounts = get("/accounts");
// Template
{get $accounts from "/accounts"}
{$accounts = get("/accounts")}
{$accounts = "/accounts"|get}
Here's a really cool side effect of the way the model result works... {$account = "/accounts/123"|get}
{put [role => "admin"] in $account}
When converted to a string, they represent a model URI. {put [role => "admin"] in $account}
Does this mean you have all your view logic inside the templates?Still, Forward is built on a new micro MVC framework and controllers do still exist. Those that prefer to write them can do so in a more traditional way.
class AccountController extends Controller
{
function index ()
{
$this->account = get("/accounts/123");
put($this->account, [role => "admin"]);
}
}
(This is not very useful code but you get the idea)> you might even be able to expand this to administrators of the service.
There is already a channel/entry system much like that of ExpressionEngine, and administrators can create new channels in the Admin, specify which fields belong in it, and start storing/searching documents without a line of code. Again, thanks to ExpressionEngine for the inspiration on that one.
So far we've used channels to manage things like: Blogs, Knowledge base, Staff procedures, Bug reports, Customer reviews, and much more. It's early still but I expect the channel/entry thing to be a huge feature for administrators.
Also for developers, channels/entries make it really easy to mockup new features without writing a new data model. For example...
{put $params.custom_data in "/entries/custom-data"}
It just works. This entry will appear in the Admin and can be fetched again with get("/entries/custom-data")https://github.com/webnotes/wnframework
Its complex and not documented. It is primarily built for an small business accounting + inventory app we publish (ERPNext, demo - http://demo.erpnext.com/)
Ecommerce is super complex and it will be a really difficult mission to make this really work and be flexible without getting bloated. But if it can happen, this will be a game changing project. My full support is there, and I'll see if I can contribute as well if I have time : )
Also, what you describe is exactly what Forward aims to fix. Custom features were needed for every single e-commerce site we've built, so we thought it made sense to focus primarily on this workflow.
On the other hand, I still believe it can be done and I think the approach you're taking is one of the ones with a decent chance of succeeding.
Good luck; I'll be keeping an eye out for clever ideas to steal as you move forwards :)
{get $order from "/orders/123"}
{put $order in "/trash"}
Now the order is no longer in the "orders" collection in MongoDB, instead it's in the "trash" collection. You can still get it by ID though: {get $order from "/orders/123"}
{$order|dump} -- Still here! But not really here.
We can just as easy pull the document out of the trash and put it back where it was.It's the reason you see we can delete documents without even a warning in the demo (http://demo.getfwd.com).
Magento and Prestashop are perfect examples of "relational databases gone wrong"... 2,000 tables? Right!
Instead we built a platform from scratch to fit the unique features of that site, and it worked. The business did $400k in revenue the first year.
Now a few years later, I can accomplish the same thing with the same basic skills (HTML, CSS, easy to understand data storage), but I don't have to start from scratch. I wanted this to exist so that I would have fun building e-commerce sites again.
One of the reasons we decided to delay code release is that we need more time/resources to get it ready for the different ways developers will try to use it early on.
get(uri, data)
put(uri, data)
post(uri, data)
delete(uri, data)
It's easy to code a model around this pattern, and the result is a system that functions entirely without procedures from the template's perspective.For those used to WordPress style functions in templates, this model accomplishes something similar, but again without functions.
I guess since it is open source, if I want this added, I should put my money where my mouth is and add it myself. Maybe one day, if I ever have the time..
My last e-commerce business was a fashion site (http://redtagcrazy.com/blog) built on a custom platform, and we dealt with variations of course, but so far only one of the early sites we built on the platform needed this feature (and they have it).
Edit: I would add that Forward aims to be full-featured, and anything you might reasonably expect out of the box in something like Magento, will be available in one form or another.
I have also built totally custom ecommerce platforms in the past (getbuckyballs.com) and I understand many of the difficulties involved. I think you guys have done a great job with this, I hope I have a project that can use it.
Devs complain endlessly about the rigid, complex mess of e-commerce software. I'm trying to change that with a platform that is easy to understand and customize by developers. We've had a lot of success so far with early projects like http://jellyfishart.com.
MongoDB has been a huge help.
{put [custom_field => "Blue"] in "/products/123"}
{get $product from "/products/123"}
Value is: {$product.custom_field}
You can also search for that value... {get $blue_products from "/products" [search => [custom_field => "Blue"]]}
While you could accomplish this with a SQL database also, it wouldn't be as easy to read, and probably slower.Performance in early projects has been phenomenal with MongoDB.
That said, how do you deal with transactions? It was my impression that MongoDB doesn't really support ACID transactions. Did you find a workaround?
I know from prior experience working on a major eCommerce store that there can be really taxing loads on the database server, right around Black Friday, and having inconsistent writes could really be disastrous. Have you tested your transactions for consistency under load?
Also, I'm pretty confident MongoDB is going to introduce an easier mechanism for document locking in the near future.
Currently it's in alpha testing and promises multi-key ACID transactions. And also introduces a really interesting layers concept. http://www.foundationdb.com/#layers
Keep up the great work!
Time will tell, and we are very interested in offering an open source product and service that will compare with the likes of Demandware.
Play with the demo for 60 seconds. How long would it take you to build that? How much do you charge per hour? I built a lightweight ORM for pymongo/mongodb last weekend from an empty .py file. It was fun, but it was challenging and took pretty much the entire weekend. And it's basic. You can find, find_by_id, find_one, and a few other things. What these guys have done is tremendously impressive and difficult to do. They deserve every right to ask for money and that will only fuel further development.
Everyone has to keep the lights on at some point.
All of our paid options surround the idea that developers can go faster and better leverage their time with time-sensitive help. We've all become used to Stackoverflow saving the day, but if the answer doesn't magically pop up in Google, we can waste many hours chasing it needlessly.
I hope the future is full of paid open source options.
We believe open source is ideal for most software, but community-only projects suffer from a lack of central ownership and support. I would adopt more open source solutions if there were professional developer support available. That's our goal here.
We want to be there when a developer needs help. No more empty support forums where you have to pray for someone to kindly answer your question.
At the same time, if you prefer to just take the code and run, that's fine too, we don't own these ideas :)
I wonder if you found the lack of relational data an obstacle? Maybe not now but do you see it being a problem down the road?
// class Accounts ...
'orders' => function ($account) {
return get("/orders", [account_id => $account['id']]);
}
Get an account, access the relationship: {get $account from "/accounts/123"}
You have {pluralize "{$account.orders.count} orders"}
{foreach $account.orders as $order}
...
{/foreach}
This also works as expected: {get $orders from "/accounts/123/orders"}
It would be cool if you built your platform on Forward. Just sayin' :)Where is the source code repo for Forward? I take it its public as it says "open-source platform"
edit: nm i found the burb.
"Scheduled for public release in June 2013. The code will be 100% free forever, supported by our team plus a community of open source developers."
The first time I've seen the project I've thought "oh no, another MVC framework!"
Now that I've seen the {put [status => "shipped"] in "/orders/12345"} I think it's cool.
We went with the MVC pattern to leverage ours and others' experience in that architecture, but there is almost no typical MVC boilerplate to deal with in Forward.
You just create a new template file, like "mypage.html", and go, just like you would with raw HTML mockups. If you prefer to write controllers you can. If you want to write custom data models (for something like this {put [something] in "/my-custom-model"}), you can, but you don't have to.
This is meant to make it easy for less technical designers to move fast without having to learn MVC patterns.
The architecture: A very small PHP MVC framework (5% or so the size of Zend Framework last I checked). I started developing the earliest version of it ~6 years ago, around the time Rails picked up steam. I loved Rails and Ruby, but with so much invested in PHP (10 years back then) I decided to implement Rails-like patterns instead. Those patterns have matured a lot, but I stick to idea that the framework should be very light itself. Happy to answer more specific questions.
Also, I'm really excited about the idea of porting the framework/platform to languages like Python and Ruby. I think it's possible because it's so light weight, but time will tell. People might call me crazy for that one, but I've been dreaming about a multi-language platform for years.
One of the driving ideas is that people will develop different versions of an Admin interface. What you see in the demo is just a template, like any front-end template, so creating one with Backbone would be an interesting project.
Oh well, very nice product, glad to hear of yet another use-case for MongoDB and ecommerce.
MongoDB makes this much easier because the database only needs to know about the way you are using it, and not the various other ways that unrelated businesses might use it.
Digital file delivery is on the roadmap now (will publish this in the near future).