Thursday 26 June 2008

Time Out - Buying a New Car

It pays to analyse in areas other than computers. Two and a half years ago I purchased a 2 year old car on the basis that it was better value. Now it is up for $7,000 in costs over and above normal services - and I found that I can't trade it in for nearly the figure I still owe. So, this time I attempted a total cost of ownership analysis.

First I looked at same or similar model in the same marque that has been around for 4 years. I compared it's new price against worst case private sell price for a car in good quality low mileage. From this I get a percentage drop in price. For example I used carsales.com.au to compare a BMW 118i hatch:

New price: $50,000
High 4 year: $40,000
Low 4 year: $20,000
% drop: 44%


I ran a few other cars through for comparison. Drop in value appears to be fairly consistent for a marque. In Australia BMW is around 45%, Peugeot is 55 and Citroen 65%.

My second table attempts to calculate the total cost of ownership over 4 years - for both the older cars and the new replacements. One column for each car and rows for:

  1. Purchase Price - being $0 for an owned car or one on lease.
  2. On-Road - again a new car cost.
  3. Repayment - Monthly repayments for lease, hire purchase or whatever
  4. Term - time lease is for.
  5. Residual - How much you would need to pay to own the vehicle after the term
  6. Resale @ 4 years The cost of the vehicle adjusted for the %drop in value from above.
  7. Trade In - The difference between 5 and 6, being positive if it is worth more than you owe.
  8. Service per year - Calculate average service over 4 years. A car that needs servicing yearly will have 3 services while one that requires 2 yearly will only need 1 in the life of the lease. If you do big mileage this will be a different calculation.
  9. Paid Out - is the total cost of repayments over 4 years.
  10. Sub-total/year - being yearly cost of repayments and servicing.
  11. Economy l/100k - used to calculate fuel costs
  12. Cost per litre - a guess on average cost of fuel over the next 4 years
  13. Fuel @ 10k/year - Cost of fuel given an estimated distance driven per year
  14. Rego - Registration costs from your local registry office.
  15. Insurance - Insurance calculation. Many insurance companies have calculators for this.
  16. TCO / year - Adding all these up gives a rough total cost of ownership
  17. Per week - Byt reducing that to a weekly cost we see how it effects our budget.
The results are interesting. I always knew that the cost of maintenance on an older vehicle offsets the higher repayments on a new vehicle, but this calculation put numbers to it. In short a 12 year old Citroen Xantia that I own outright still costs me over $100 a week to run. Replacing it with a brand new Peugeot of similar size costs $80 a week more. My 5 year old C5 came out worse - being almost the same price as a replacement new vehicle.

Don't use my figures. Make a similar calculation based on the cars you look at. It is worth the time and effort. There are non-financial consideration - or those that are at least unmeasurable. We chose BMW because if (1) safety, (2) 2 years between services and (3) because of guaranteed by-back at end of lease.


Wednesday 4 June 2008

A Google CMS - Part 1

Synopsis
I have written extensions using the Google App Engine to use the Google Apps framework as a n active CMS (Content Management System). This series of articles documents the what, why and how - including code.

What is a Content Management System (CMS)
A content management system is a way to publish a consistent web site without resorting to basic HTML. It has a number of functions:

  1. Separate content from structure. This allows consistent templates to be created and content providers to only need to deal context specific information (words and images).
  2. Workflow - allowing content to be created by the experts but vetted by other interested parties before being published.
  3. A mechanism to keep page changes and revert to an earlier version on command.
  4. Consistent look and feel.
  5. Easy content entry from subject experts without a lot of technical knowledge.
An Active CMS
To this group I would add a new line item:
  1. The ability to combine application functionality with managed content.
Traditionally hard coded applications (stand-alone or web) had limited hard coded content - think help files and page footers. This is not very satisfactory. Most developers dislike UI work - and the result show.

A Content Management System allows a subject expert to publish static data on a web site with consistent look and feel without having technical knowedge of the web site. It separates content fron structure. An Active Content Management System adds the components to include forms, reports and results into these pages. It further separates business logic from the display.

In a perfect virtual world subject experts will create all the results they need inside an interactive Active Content Management System. From this a developer can develop the services (both input and output) needed to complete the pages created by the subject experts.

Why Google
When Google released the Google App Engine they added the final component needed to create an Active Content Management System using Google tools on Google infrastructure. In this first pass I am going to document here I use Google Sites to create content and Google App Engine to serve it. I use Google Groups for both community and private communications and Google Blogger to generate news articles to display on the site.

Once this is complete and stabilised I will be starting on the active components. I have plans to use Google Charts for display, Google Docs for reports and other Google APIs and technologies as I can find a use.

While workflow can be implemented with Google App Engine, I have no need of it at this time.

Who Needs a CMS
Because I am comfortable with HTML and am developing Golf Adept alone I have been creating web pages as part of the application and loading it directly to Google App Engine.

My daughter runs a massage clinic and needed a new web site. My knowledge of Plone and other content management systems led me to believe that this was the correct approach for her site - even though there would only be one or two content providers.

On consideration I recognised the need to change Golf Adept to the new standard. Eventually I am going to need content that is to be created and maintained by others. Better to start on the correct path.

What Will be in Part 2
I know that this part has only been words, but every concept requires words to start on the path to understanding. The next part will be technical, showing how easy it is to create a content management system with a small amount of Google App Engine code.

Monday 2 June 2008

Sessions in Google App Engine

Google App Engine was a bit of a shock to many application server developers - no sessions.

What is a Session? Every browser request stands alone. The only connection between then are cookies passed back and forth between server and browser. Early CGI used these cookies to hold all important data. This is limited in size and does not allow for any security. Application servers usually only set one cookie - a reference to a session object. Every request from the browser can then be associated to a server-side session, including being logged in.

For efficiency on a single server these sessions are kept in memory. For small clusters the network makes sure that a session consistently accesses the same computer.

With the Google App Engine you do not know which server runs the application and which database store holds the data. This gives us massive extensibility, the vaunted Google speed advantage, redundancy, reliability and much more. The cost? Well, we can't hold a session in memory because different machines could very well serve different requests.

Why We must have a Session. Surfing the web is like reading a book. We hold the context of the context thread in our heads as we read. Using an application server is more interactive - like a conversation. A conversation requires that both participants hold the context so that it can exceed a single exchange.

The Browser Session. All modern browsers hold a session using cookies. Cookies are associated with a particular web site or path on a web site. They are held by the browser and passed back with reach request. Both browser and server can set new cookies. In-memory cookies only last until the browser is closed. Cookies can be persistent, but since they are part of the browser they are specific to a single computer. For safety cookies can have a time-out after which they are removed. Because cookies are sent back and forwards with every exchange in the conversation they are limited in size. Cookies are great when used within their limitations.

The Google Session. Yes, I know that I said Google App Engine did not provide session management. This is not entirely true. It does provide a Users API. And guess what - it is reference by a cookie. Any Google App Engine code can pick up a small amount of user specific data - name, email address and a nickname to display. It is almost certainly kept in the same data store as our own data, but it is likely to be optimised.

A Session we can use. Because I needed connectivity early on I used some of the earliest examples. There has been a lot of session discussion on the forums since, but as I have an acceptable solution I have stopped following them in detail. Because data retrieval is expensive I wanted lazy loading.

My solution was a class (session.py) that I add a reference to in the parameters from any Django template:


params["session"] = Session(request)


Session is not persistent - it does not inherit from db.model. The idea is to keep it light-weight until something is needed.


class Session:
def __init__(self,request)
self.__dict__['request'] = request


The request object is of type HttpRequest with all the relevant information available. It can also be used to hold non-persistent data for use in a single request.

Because Django will access information from session as a dictionary or a function call, session becomes all-encompassing.


def user(self):
if not self.__user:
self.__user = users.getCurrentUser();
return self.__user


So, a template can access the Google user object - as in {{session.user.nickname}}. I also use the session object for other system information:


def loginURL():
return users.CreateLoginURL('/')
def isAdmin():
return users.IsCurrentUserAdmin


If we were to inherit session from db.Expando we would have to save the whole session any time a piece of data changed. I prefer to only update the data that needs changing by overriding __getattr__ and __setattr__:


def __getattr__(self,name):
if name.startswith('_'):
return None
self.__dict__[name] = value = UserData.Load(name).value
return value

def __setattr__(self,name,value):
if name.startswith('_'):
item = value
else:
try:
def modify(data): data.value = value
item = UserData.Modify(modify,name)
except:
logging.error('Setting session data for '+name)
item = value
self.__dict__[name] = item


UserData saves data to BigTable keyed to a specific user - posted at App Engine Fan: Saving user-specific data

So, instance data starting with underscore is not saved to persistent storage. Nor is data in session.reference. Anything else is persisted as separate data objects. Because UserData is a functional db.Expando, items can be any of these properties. For larger data groups, a reference to another database object or object tree would be suitable.