Tuesday, October 27, 2009

Yesterday, Beginning Django E-Commerce was officially released on Amazon, so it's now in stock and available for purchase. I don't know how long it's going to take my publisher to get the "Look Inside!" functionality working, so I figured that I would post the 500 foot view of the table of contents here for those who are interested an overview of the book's contents:

It doesn't say it anywhere else, but the book uses Django 1.1. For those curious about what I cover in addition to Django: I use MySQL as the database engine, mod_wsgi to integrate Django with Apache and NginX in deployment, Google Keyczar for symmetric encryption of credit card information, Google Checkout and Authorize.Net as payment gateways, and the jQuery JavaScript library to handle the Ajax functionality. The last chapter is dedicated to showing the basics of how to deploy Django projects onto Google App Engine using the App Engine Patch project.

I'd like to express my gratitude to all of those people who purchased the alpha version of the book, and thank those of you that provided your opinions and feedback.

Sunday, October 25, 2009

Sometimes, when someone asks you a question, and there's a lot riding on the answer, it's a relief when you can say, "I don't know" and really mean it.

I've worked for a lot of small companies that set up shop online, and management always ends up asking questions like "What should the text be in the header on the homepage?" or "Where should the 'Add to Cart' button be on the product page?" or "How many steps should the checkout product have?" They ask themselves, and ask their cohorts, but don't come up with any definitive answers, so they start asking the technical people who are busy coding up their site what they think.

I'm one of those people coding up the HTML for your site. And I'm telling you flat-out: I don't know.

Part of this is based on the fact that I'm dealing with incomplete information. If you ask the question more specifically, I might be able to give you my opinion. For example, what change are you hoping to affect in the results? In the land of e-commerce, the answer to this question is almost always related to the number of customers that place orders. You want to know if changing some part of your site will increase the total number of conversions.

Even given the intended goal, I have very little relevant experience on which to base my opinion. Marketers tend to ask developers these kinds of questions because they're hopeful that web programmers understand the domain better than they do. Unfortunately, no matter how experienced we are in e-commerce programming, we really don't know. There are lots of reasons for this. The requirements of your site might be different than other sites, even those of your competitors. Most importantly, it's because we are not your customers; we are developers.

Your customers are the highest authority to which you should appeal for answers about how you should design your site, what the copy should be, and what the contents of each page should be. If you ask me, decisions about the wording of value propositions and calls to action are too important to be left up to anyone other than your customers.

So what is the solution? A/B split test. Use a tool like the Google Website Optimizer which allows you to present two different versions of the same page, randomly, to different customers. After enough time has passed and you've gotten enough samples of customers viewing the page you're testing, the Website Optimizer will test both of them, and then give you a report about which version of the page led to the highest conversion rate.

This takes the guesswork out of it. I've been in several meetings where two managers are arguing with one another about some little point about how the site should look, and one of them turns to me, the developer, and says, "What do you like better, my solutions or his?" And then they both turn and look at me, waiting for me to answer, each one hopeful that I'll agree with their opinion so they can rub it in the other's face. Eagerly looking to me for a vote, as if I were some kind of "trump card".

You might be tempted to just agree with the one of the two people who is in a better position to approve your pay increases. Or you might actually be egocentric enough to think you know the correct answer. Don't risk it. Even if you offer an opinion, they might ask you to explain why, and then you're just going to become a fountain spewing forth made-up reasons in an attempt to justify yourself.

As a developer, you should practice saying it a few times, until it becomes automatic: "I don't know. We should split test it." Remember it the next time a couple of managers are engaged in a pissing contest and ask you what you think. You'll feel the relief of never actually having the burden of the decision rest on you. It's a great way to stop arguments before they even start.

Wednesday, October 21, 2009

In Chapter 12, when I talk about using Google Keyczar in order to handle encryption of credit card information, I mention that the library uses the Advanced Encryption Standard (AES) as the cryptographic protocol. I did not discuss the gory details behind how AES is implemented.

I found the following to explain it in a more concise and entertaining way than I could in the book. I hope you enjoy:

Last week, as I was wrapping up a user interface item that I had been working on at work, I called my boss over to have a quick look at the web page I had created, to make sure it made sense to a fresh set of eyes. It was a means for me to get some perspective to determine if there were any glaring problems with what I had created. In other words, I wanted to do a brief usability test.

He took one look at the screen and said, "You know, don't worry too much about creating a good user interface. We have a team of user interface engineers working right now to design something for customers, so you don't need to spend your time worrying about this. Focus more on getting it functional, and we'll overhaul it later." (This was the first I had heard of external user interface engineers being involved in any way.)

He then went on to explain that in his experience, he and his business partners could sit there, furrow their brows, and brainstorm all day long about how to make a particular piece of the interface more intuitive. In the end, he realized, it didn't matter. Whatever they came up with confused some customers in a way that they hadn't foreseen. No matter the case, they always ended up having to take the feedback given to them by customers and improve the interface going on this feedback.

Now, he has a good point in this case, and I happen to agree with him entirely. I'm a backend developer and have very little interface experience. In my case, I wasn't trying to create a perfect user interface. I was merely trying to avoid introducing any additional confusion to what was already there.

And while my boss is well within his rights to tell me how to use my time (since he's paying me), there is a slight fallacy in what he was implying. Telling me not to concern myself with the user interface because there's a team of interface engineers that are going to come in and fix it later is like telling a person they don't need to learn to spell because their word processor has a spell checker. Spell checkers don't always catch missing words, or find errors that are contextual.

Creating software that's usable is a process, and I think it actually requires getting customer feedback and then fixing those problems. You're never going to anticipate all of the problems in advance, without asking a customer to try and use the software.

I'm not a expert on either, but whenever I create code for something, I do take a little bit of time to think about how I would break something I had written. I look for Cross-Site Scripting holes or other security vulnerabilities. I step back a page and then come back to the page I'm working on a few hours later to see if the interface makes sense. I code my HTML so that people with screen readers can use it effectively.

From a security, usability, and accessibility standpoint, this is a good mindset to have. It doesn't make my code 100% secure, or usable, or accessible, but I try to avoid adding more problems by keeping aware of the low-hanging fruit. When you're designing something, you don't have to be an expert on these particular fields, but knowing the basics and how to incorporate them will reduce frustration down the road.

It helps if you make this process a habit. In instant messenger chats with friends, I tend to be a stickler for correct spelling, punctuation, and grammar. This isn't because my friends care whether I use my English good or not. It's because later, when I'm typing an e-mail to my boss or a customer at work, I'm already in the habit, and therefore I'm less likely to make a mistake when it might matter.

Tuesday, October 13, 2009

I can recall a small handful of times when I decided to price shop around on the Internet for a particular product. I went onto Google Shopping, entered the product name, and started browsing the sites that were selling the product for the lowest prices. I chose the one that appeared the most reputable and didn't send up any red security flags as I started the checkout process.

While I completed my purchases from these individual sites, I had to create a customer account. I had to supply registration information, and, in order to complete my order, I naturally had to provide shipping and billing information as well, which included for some of them my CVV. Each time, the product I had ordered showed up in the mail in the next week or two. (I don't what happened to "Allow six to eight weeks for delivery", but I'm glad those days are gone; I'm from the super impatient MTV generation.)

Of course, I did business with these sites for the single product that I was looking for, and they sent me the product I ordered in the condition promised. They didn't do anything incorrectly. However, once I had completed each of these transactions, I was pretty sure that I wouldn't be ordering anything from them again. It's nothing personal...my purchase was just a means to an end: they had something I wanted for cheap and I bought it from them. The experience of shopping on their site didn't compell me to return to shop more.

The problem here was that, in each of these cases, when I returned to the sites, none of them offered me any closure. If I want to stop being their customer, there was no way for me to remove my information from their system. There was no "Cancel My Account" option that would scrub my shipping and billing information from their customer database. (It was also unclear to me in most cases just how much of my information they had chosen to store; some of them might have kept my CVV despite the PCI guidelines)

The reason they're doing this is simple: they want to make it easy for me to return and purchase more stuff. If there's even a chance that I'll return one day and attempt to make another purchase, they don't want me to be deterred by the inconvenience of having to enter my information again. Why not err on the side of caution and just keep my account there in perpetuity?

Another reason is the potential for vendor lock-in. They're hoping that the inconvenience of having to enter that information on another site might give them an edge over other competing sites that don't already have my information.

This sounds like a bad idea. People are sensitive about their personal information, particularly when it's financial. They're wary about to whom they're going to provide it. Hanging on to customer data in an effort to keep your customers returning to make subsequent purchases seems like sticking your thumb out between the index and middle finger of your closed fist and saying "Got your nose!" It also seems lazy; instead of competing in a creative and intelligent way, you're just holding a customer's data hostage in the hopes that it will provide them a net benefit that will help you.

One other important reason e-commerce companies are so tight-fisted when it comes to customer information: after the dot-com bubble burst, a lot of tech companies found that the only asset they had with any residual value was their customer data. There's value in the data. Of course, that's no reason to refuse to let customers remove their data. To make decisions based on the assumption that your company will eventually fail is a violation of the continuity principle. That is to say, you shouldn't let the "what ifs" cloud the day-to-day operating decisions of your business. You're supposed to be adding value for your customers, not planning your exit strategy.

Here's a progressive idea: let customers delete their accounts. Give them a clear and obvious means of doing it somewhere in the interface of your site. When you're trying to convert them from anonymous customer to registered customer, tell them that you'll provide them the option of removing their data when they decide they're done. And when they choose to remove their data, actually delete it...don't just provide a friendly message letting them think you've deleted it when you're really just copied all of it into an archived table.

Now, I think this is a great idea, and a good feature that more sites should offer. However, before actually trying to do this, you need to give what you're doing some thought. Take the following view function:

def cancel_view(request): request.user.delete()

In most cases where there aren't dependency issues lurking in your model relationships, the Django delete the user and all of the data associated with them. That's one nice thing about the ORM: it crawls the model instance hierarchy and deletes everything from the bottom up, instead of coughing up foreign key constraint errors or leaving some records orphaned in other tables.

In some cases, however, you don't want to delete everything. Take the OrderItem model we created in Chapter 5: it contains the quantity and unit price at purchase time for each item sold on the site. This is tied to the Order model, which might contain shipping or tax charges for each order. And finally, this is tied to the User model. Which means if you delete a customer, you delete their order information as well.

You don't want to remove this. This is part of your financial records. You may keep a fastidious paper trail, printing up packing slips and invoices for each order that you ship, and that might be sufficient for bookkeeping purposes. However, around audit time, it will behoove you to have this information in the database.

Exactly what you choose to store, and how to choose to migrate the information, is based on your own business requirements. At the very least, if you're storing credit card information, I would remove that completely at a customer's behest, particularly because it has no value for you once a customer decides they'll never authorize you to bill them for anything again in the future.

If I had to guess: most customers won't end up ever deleting their information. Even the customers that show up once, place one order, and ne'er return probably won't even go to the trouble of deleting their data. It's more about the offer up front, to ease those customers that are uneasy about providing the information in the first place. Think of it as falling under the same umbrella as your store's "Return Policy".

Friday, October 9, 2009

Man, it's great to be a Python developer! I'm in awe of Guido van Rossum, who made the conscious decision when he created Python to force developers to keep their code neatly formed and readable. He did this in the simplest way: format your code nicely or else it won't run.

This is based on indentation used in the code samples. For example, the following code sample will not run:

def say_hello(): print "hello!" print "hola!"

The function attempts to say "Hello" in two different languages. Notice that, inside of say_hello(), the indentation isn't consistent. This causes Python to raise an IndentationError exception.

This constraint may seem fastidious, but it's brilliant in it implications. Mr. van Rossum is telling you to keep your code pretty or it won't run. He based this on the insightful observation that code is read much more often than it is written. Even code that a developer has written becomes alien to the person who wrote it after only a short period of time.

This is innovation in engineering at its finest. The use of curly braces to denote context in computer code has been inherited by many languages, from C to C++ to Java to C#. Python's creator saw a problem with the status quo, and he chose to do something about it. He made his programming language much more usable than several others that came before and after it.

Creating a new programming language is not something most people, even programmers, can do. It's even rarer that people innovate in this fashion. Guido van Rossum did both; this is the reason that he now works for Google.

For this reason, I urge any developer getting started with Python (Django developers, this includes you!) to read the Python Style Guidelines in PEP 8. These guidelines have been put forth by Mr. van Rossum himself. If you're a Python developer and you haven't read PEP 8 yet, go read it now before you write any more code. It's well worth your time.

Of course, a lot of the recommendations made in the document are just that: recommendations. Your code will run just fine even if you don't adhere strictly to every last one of these guidelines. However, in order to keep number of broken windows in Python community code to a minimum (higher quality code = happier developers), you should be following these guidelines whenever you can.

One of the suggestions is to use four spaces for each level of indentation. (The document cautions against using tabs, but if you're going to use them, set the tab width to four character spaces.) Unfortunately, while I was writing Beginning Django E-Commerce, I was using two separate computers to write code and write the book. For this reason, some code samples in the book use four spaces for indentation, while others use five. I didn't catch this error before the book went to press since the Word template uses a very narrow font for code samples in the text. (They come out much wider in print.)

This does NOT mean the book's code is broken. Python allows you to mix different indentation lengths, just not within a single code block. As you're reading, you'll probably notice the difference in indentation between code in earlier chapters and later ones. It's unfortunate, but not a deal breaker. And the source code you can download from the Apress web site uses 4 space tabs for indentation, consistently.

Just something to keep in mind while you're pounding out Django code while working through the book: you are encouraged to use 4-space indents. Do as Guido says...not as I do.