RoR-e

If you haven't seen The 15 minute E-Commerce Site CLICK HERE


I'm currently looking for Contract jobs, Contact Me if you are interested. Dave.

Consultants don't make good CTO's David Henner Jan 21

Post a comment

I've been working with a lot of CTO's and consultants in the past couple years. One reoccurring trend I find is that success does not align with a great technologist at CTO. That does not mean a CTO should be a bad technologist or that a great CTO can't be a great technologist. However, you can have a great technologist that is a bad CTO.

A CTO's role is to:

  • Understand Business goals
  • Understand how to get a tech answer:
    • Hire great technologists
    • Understand who has a better answer than yourself
  • Know how to say no to good tech and focus on business goals

A great consultant will almost always recommend the latest and greatest technology. Sometimes just so they can play with the latest tech toys. That is great for a consultant but a CTO understands how to say no.

Lets say your whole tech team knows:

  • Vanilla jQuery / javascript
  • *.erb
  • css (without a framework like bootstrap)
  • Pivotal Tracker
  • mySQL

A consultant might come in and say I can go faster if we use:

  • coffee script
  • *.haml
  • sass (with twitter bootstrap)
  • Mingle
  • postgres

A good CTO should sit down with the consultant and either pick one thing that adds business value or tell the consultant they are not the right guy for their team. The disruption to change so much to your team's stack might make the consultant more efficient but it comes at the expense of your team's efficiency. It might be that the consult just wants to bill you while learning one of these technologies also. Hence, it could be a lose lose situation.

Picking a consultant means picking a guy that will not add so much complexity that it kills your current team. Consultants can be great at explaining to tech value to any new technology. A CTO needs to be able to explain the short and long term business value.

All this being said the same consultant that is bad for your business today, might be great for your business after you have updated your tech stack in the future.


Don't hand your first Tech guy the CTO role!

Another thing I see is that the first tech guy on a team is given the CTO role. Please, PLEASE, For the love of god PLEASE STOP!!! This might turn out to be a good thing but do you really know if it is a good choice? Probably not! Hire a guy and promote if they deserve the CTO role. If they can't deal with other developers or don't deliver then you have a chance to hire someone that does deserve the position.

Unfortunately there isn't a position above CTO. That first hire might be perfect as a developer but not as the CTO. So please hire wisely. Good Luck!

ror_ecommerce 1.2 David Henner Sep 09

Post a comment

I'll keep this post short. Version 1.2 of ror_ecommerce has been released.

This version highlights a brand new look and feel to the admin area. This work was spearheaded by Dean Perry. If you have not heard of Zurb Foundation you really need to take a look at it. All I have to say is Twitter bootstrap "eat your heart out." The admin work took several months so a double thank you to Dean is deserved!

There were also several bug fixes in this version.

Soon more additions in Translations, documentation and easier use of things like Stripe and FeeFighters Samurai will be added.

Validation Issues David Henner Sep 06

Post a comment

Every time I hear a business guy make a hypothesis about why a form isn't converting customers I ask if they are basing the hypothesis on any real data. Most of the time people take stabs at the wind when they are creating an A/B test. What if there was a better way.

One of the primary reasons a form doesn't convert is because there are issues with validation. Sometimes there is a bad reg-ex. Other times there is a darn "check this box to confirm" that people forget to check. If the form has a validation error too many times the customer leaves your site.

What if you could track the form before A/B testing. If you had the data you could either make an obvious change without the A/B test to begin with. The other alternative could be making an educated guess based off real data.

I now introduce ' Validation Issues '

"Validation Issues" allows you to log all validation errors on a form. It even allows you to log the A version vs the B version of a test. Thus you may find that version A of a form is not converting because The "first Name" field isn't filled out but version B of a form is not converting because "Last Name" is not properly filled out.

If you just did an A/B test without the extra data you might not realize there is a different between the 2 forms. Having the extra data points allows you to understand and act on what is really happening.

Once is set up you can simply do the following in your controller:

def create
  user = User.new(:first_name => '', 
                  :last_name  => 'Good Last Name')
  if user.save
    user.log_successful_validation!('user_form')
    # do something
  else
     user.log_validation_issue!('user_form')
     # do something else(like render the form again)
  end
end

The logsuccessfulvalidation! method will help track the number of times the form has been completed. The logvalidationissue! method will track each of the form's fields that have validation errors.

Then you just need to point your browser to http://www.yoursite.com/validationadmin/validation_issues. If the user has admin privileges they will see the breakdown of the form's performance.

On a separate topic

I am moving to San Francisco in 2-3 weeks. If anyone needs a consultant my rate is $175/hour. Email me at drhenner [at] ror-e.com to start a dialog.


One more note: I've been working for StackSocial in LA. They are hiring Ruby, Front-end and QA engineers at http://jobs.stacksocial.com. These guys power digital commerce for sites like VentureBeat and Cult of Mac. They are good guys.

E-commerce Tips 1.3 (Inventory) David Henner Jul 06

7 comments Latest by Gary

Tracking inventory can be much trickier than most people imagine. I've seen several different solutions. While many can work with very few purchases others are seriously flawed at scale. Lets go through a few solutions.

The first solution and for some reason the solution I see most goes like this.

@order.pay!
@order.items.each do |item|
  item.product.remove_from_inventory!(item.quantity)
end

class Product
  def remove_from_inventory!(qty)
    self.quantity = quantity - qty
    save
  end
end

Unfortunately there is a lot going wrong above. The first issue has to do with the fact that the inventory is stored in the product class. Inventory and products need to be broken down into separate class. The fact is that they are not the same. The product class should not for more responsibility than it should know about.

Now we can refactor the code to look like this:

@order.pay!
@order.items.each do |item|
  item.product.remove_from_inventory!(item.quantity)
end

class Product
  def remove_from_inventory!(qty)
    inventory.remove_items(qty)
  end
end

class Inventory
  def remove_items(qty)
    self.quantity = quantity - qty
    save
  end
end

So now you have classes that have one responsibility but there is another glaring issue. The math is actually not accurate if you have 2 customers purchase at the same time.

For Example: Lets say order_one and order_two purchase the same item at the same time. This means the inventory object for each order will have the same quantity (let just say it's 5). Now when inventory is updated the first time the quantity will reduce to correctly. The second inventory object still thinks the quantity is 5 though. So when it updates inventory the quantity will still be 4 (if one item is purchased).

This brings us to yet another solution. Lets do the math in the database.

@order.pay!
@order.items.each do |item|
  item.product.remove_from_inventory!(item.quantity)
end

class Product
  def remove_from_inventory!(qty)
    inventory.remove_items(qty)
  end
end

class Inventory
  def remove_items(qty)
    sql = "UPDATE inventories 
           SET quantity = (quantity - #{qty}) 
           WHERE id = #{self.id}"
    ActiveRecord::Base.connection.execute(sql)
  end
end

This starts to help manage the problem better but there are still some issues. The issue that needs to be dealt with next is what should happen when there is only a couple items left to purchase? With the above solution the database would now at least reflect the correct number of items. The problem is the number could be negative if two people purchase at the same time.

This is where business needs will probably determine the correct solution. Unfortunately, I'm not going to give you all teh solutions right now. One solution might be to have your database return an error if the quantity goes below 0. Then you would need an appropriate error handler. Another solution might be this:

class Inventory
  has_many :inventory_items
end

This illustrates that each inventory item has it's own database record. Now if the item is in your cart you are the only one allowed to purchase the item. Again, you will need some business logic that will free the items just in case the customer doesn't make the purchase but with this solution there isn't a way to go below zero items in stock.

Yet another solution might be to have a safety stock level. This would mean when you have less than X number of items in stock people aren't allowed to purchase. That isn't a perfect solution if you do want to sell out but it does solve the issue with over selling.

Two more glaring issue before I move on. This all needs to be wrapped in a transaction. Thus if there is an item with collecting the money the inventory doesn't change and vice versa.

transaction do
  @order.pay!
  @order.items.each do |item|
    item.product.remove_from_inventory!(item.quantity)
  end
end

Almost done... Now lets move the @order.pay! option to the end of the transaction. Otherwise if there is an issue with inventory (or anything else) the order will not be charged. Likewise if there is an issue with paying the whole transaction will be reverted back.

transaction do
  @order.items.each do |item|
    item.product.remove_from_inventory!(item.quantity)
  end
  @order.pay!
end

Quantity isn't enough

Now at a high level you should have an understanding of inventory quantities being accurate and I hope you can improve your code at this level. However another big issue we have is quantity is not a good gauge of what is really happening. Quantity available to sell and Quantity in stock might reflect 2 separate numbers.

For example:

  • You have 10 items in stock
  • One item is purchased online.
  • The amount you can sell has reduced
  • BUT the amount in stock is still 10 until the item ships

So in reality the Inventory class should have the following columns:

  • count_in_stock
  • count_pending_to_customer
  • count_pending_from_supplier (optional)

Now the quantity is just

class Inventory
  def quantity_available_to_sell
     count_in_stock - count_pending_to_customer
  end
end

Well there is still much more to learn about inventory. This might justify creating a new post in the future. I hope you have taken away something useful. Thanks for reading.

E-commerce Tips 1.2 (The Shopping Cart) David Henner Jun 10

3 comments Latest by Daniel Errante

I've seen many shopping carts. Most work well enough. Some have glaring flaws. Lets start by identifying what makes a shopping cart great.

The first thing that comes to mind of a great cart is that it is "stupid". Sure that might sound crazy but it is very true. A shopping cart should not know much about your "order" or your "products". Your cart should simply be a bucket to keep a bunch of products for a specific user. It doesn't know the price of the products or anything about the checkout process.

The second thing about a great cart is that it ironically it is "smart" about itself. Your cart should not know about the order or products but it should know about itself. Note your cart is the combination of a "cart model" and "cart_items model". This cart_items model should have at a minimum the following fields:

  1. cart_id
  2. product_id
  3. item_type_id

Additionally the cart should only have the following field:

  1. user_id (allow NULL)

There are a couple interesting things I've left out of the minimum model. First is quantity. I would argue that quantity should be in your cart_items model. However removing quantity and just adding more cart_item records in your database is an alternative (Although I don't recommend this approach).

Additionally user_id is not a required field for the cart. Which means your minimum cart record in the database can just have an ID field and nothing else. Yes your cart does also have_many cart_items. This structure allows customers that are not yet logged in to have a shopping cart and only assign the user_id during the checkout process.

Also note I am in favor of adding user_id to the cart_items table to keep queries more simple.

One feature I added to the minimum model is the field item_type_id. item_type_id refers to a model that just has a name field. The ItemTypes are as follows:

  • shopping_cart
  • save_for_later
  • wish_list
  • purchased
  • deleted
  • admin_cart

What this simple field in the DB does is allows you to have a wish list and save for later functionality out of the box. Additionally you can WOW your marketing team by telling them all the items a user has ever deleted out of their cart or purchased. If you ever need to create a recommendation engine your cart will give you all the data you need.

Now with this model, purchasing an item is simply taking the items that are in the cart and have a item_type of shopping_cart and moving them to an order / order_items object. I won't go into detail but basically once you purchase an order_item you change the cart_item.item_type to "purchased".

Now you have an extremely slim cart with a tremendous amount of functionality.


Combining the Cart and Order Objects

I've heard the argument that using an order object for the cart "make things easier". Not only do I disagree but sorry, "You would be wrong". By mixing the cart and the order you have not separated concerns. This can make validations very conditional. It also mixes cart logic with order logic.

I view your cart as something that can be removed off the face of the planet and not effect much. Sure people would be upset to add things back to their cart but at the end of the day it would not effect anything financially. The order however is sacred. If an order was deleted you could lose financial data and even fulfillment information. Hence you don't want to be messing around with the order because you could be shooting yourself in the foot.

By nature your cart has a lot of abandoned records. If the order and cart are separated you could very easily archive the carts without much worry. If your order is your cart the risk to do this would be too great. One small bug could cost you way too much.

E-commerce Tips 1.1 (namespacing) David Henner May 19

Post a comment

One of the first things I notice when I look through other people's code is the lack of organization within the controllers. Almost universally I see a structure like this:

  • products_controller.rb
  • Admin (namespace)
    • products_controller.rb

Thus if you create a UI for searching products you would make a "search" action in the productscontroller. This would work but eventually you will have 50 actions in the productscontroller and your development workflow now changes from "open the controller and look at the CRUD method you want to modify" to "open the controller and do a grep for the method that concerns you". Also having a lot of methods in your controller now makes it almost impossible to have a before_filter with passing :except & :only.

A Better Approach

Lets move the example to something a bit more complex. Lets try a checkout process in an e-commerce application. I've seen many approaches to this solution. Most involve a checkouts_controller with about 20 methods within the controller.

Instead lets start with a "checkouts" namespace. Notice the namespace is plural. I namespace using plural because I know the namespace will not share a name with a model I have. For Example: If you have a "user" namespace instead of a "users" namespace and you do User.find, you will have an error.

Moving on with the checkouts namespace the first thing I will do is create a checkouts/base_controller.rb

class Checkouts::BaseController < ApplicationController

end

Now you can start creating some of the controllers within the Checkouts namespace.

class Checkouts::AddressesController < Checkouts::BaseController
  #...
end
# &
class Checkouts::ShippingMethodController < Checkouts::BaseController
  #...
end

So the first thing I would add for the base_controller is a line the requires a user to be logged in like this:

class Checkouts::BaseController < ApplicationController
  before_filter :require_user
end

class ApplicationController
  def require_user
     redirect_to login_url and return if logged_out?
  end
  def logged_out?
    !current_user
  end
end

What you really want is a method to ensure a user needs to login within 20 minutes of starting the checkout process. For this I would create a method that ensures that after 20 minutes of inactivity the user is required to login again. The following show some of the code that you would need for this.

class Checkouts::BaseController < ApplicationController
  before_filter :require_secure

  def require_secure
     redirect_to login_url and return if not_secure?
  end

  # at login session[:authenticated_at] is set to Time.now
  def not_secure?
    !current_user ||
    session[:authenticated_at].nil? ||
    (Time.now - session[:authenticated_at] > (60 * 20) )
  end
end

For another approach and more details of a checkout process take a look at ror_ecommerce's checkout.

The reality is namespaces are a great way to organize code for any application. It keeps your controllers small and it also keeps related controllers in the same folder in your app directory. Also don't be afraid to have namespaces that are several layer deep. For Example Admin::Shopping::OrdersController might be a controller that a customer service representative uses to make orders through the phone.

More great places for a namespace are:

  1. MyAccounts
  2. Shopping (adding things to your cart)
  3. Site (like "about us" and "jobs")

Also remember a namespace is mainly for organization. If you don't want the end user to see something like http://www.mysite.com/site/jobs and you just want to show http://www.mysite.com/jobs, you can always go into the routes file and make changes accordingly and still take advantage of the organization namespaces give you.

Thanks for reading, I hope this helps.