Monday, March 19, 2007

It's All About Blog Trust

I have an idea I'm certain would vastly improve the blogosphere, enhance a blogger's ability to find a larger audience and enable blog readers to find worthwhile blogs. And it has everything to do with trust.

Blog Trust


One of the most popular features on many blogs is the "links to other blogs" section. And for good reason, it is a great way for bloggers to list out blogs they find interesting. These kinds of links are what the web is all about, after all.

As an example, here's a screenshot of Guy Kawasaki's "Blog Scratching" section:



He's got tons of links, but the one I'm interested in is the link to Bill Joos' blog.

So, what's the problem? Well, it's not so much of a problem as a greatly missed opportunity. Let me explain.

Because Guy Kawasaki links to Bill Joos' blog, we can assume that
Guy "trusts" the information that Bill Joos dishes out on his blog. If I start out on Guy Kawasaki's blog, and I have a great deal of respect for the information that Guy gives out (which I do) then I can feel pretty good about going over to Bill Joos' blog.

But what happens if I come across Bill Joos' blog? I have no idea that Guy recommended Bill. And that's exactly where Blog Trust comes in.

The Blog Trust Proposal


I'm proposing that in addition to a "Blog Roll" bloggers put in a "Recommended By" section which links to bloggers who recommend the blog you're currently reading. If you think about it, it's a great way for you to provide links back to bloggers who "trust" you and it helps bloggers get to know who you are.

If Bill Joos' had that section up there and listed Guy Kawasaki as someone who trusted him - I'd be able to "trust" his blog much more.

Wait, There's Something Wrong With This!


Yeah, I know. You're thinking, "some sleazy blogger can just slap a link to Guy Kawasaki and say hey, he recommends me!" You're absolutely right.

What would solve this problem is a central service which would allow people to recommend a blog. If you are the blog owner, you can display the list of bloggers who recommend you right there, front and center on your blog. Hmm....you know, the more I think about it, the more it sounds like a FINE startup idea. Don't you?*


*If you do think this is a good startup idea and run with it, you BETTER link back to this post AND recommend my blog on your brand new service! And that's if you beat me to the punch - cause I'm working on it already. ;)

Wednesday, March 14, 2007

Who Needs a Database? How I Built a Fully Functioning Website Without One

Why?


Why would you want to build a website without a database? I'll try to answer this question for you by explaining some of the reasons why I did it.



  • One of the reasons was purely academic - could I build a site that persisted data and was fairly interactive but with no database? If I did, what kind of problems would I run into, would the implementation be stable? Could I build it in such a way that if I ever needed to use a database - woud it be hard to convert? In short, it was a challenge I couldn't resist.


  • Another reason was simply because there was no reason not to do it! Once I had settled on the site design, there was just no solid, compelling reason other than convention why I would have to use a database as my persistence medium. None whatsoever. Many of you will disagree with me of course, and I welcome your comments and rants. :)



With no reason not to use a database, and with the challenge in hand, I got down to the business of building the site. Before I explain how, I'd like to give you a quick overview of what the site is and what it does:



The Site


The site was built using ASP.NET 2.0
To reference the fully functioning site throughout this tutorial, go here.

The site design is very simple. Every day ten Sudoku puzzles are displayed on the main page, which I call The Scoreboard:



Clicking on a Scoreboard widget (shot below) will take you to a page where you can solve the puzzle. If you solve it quickly enough, you get to enter your name and url and take your spot on the scoreboard. If someone comes along and solves it more quickly than you did - they bump you down the list. Only the top 5 players are shown for each puzzle.




Nice and simple.


The Ingredients



The Solutions File
The first hurdle was to decide how I would generate the 10 daily puzzles. I didn't like the idea of having a scheduled process generate 10 new puzzles at midnight every day so I went with generating several months worth of puzzles and placed 10 puzzles into their own "solution" text file. Each file is placed into a folder labeled with the date it is to be used for. Essentially, when the scoreboard needs to get the list of puzzles for the day, it nagivates to the directory labeled with the current date and retrieves the puzzle information from the file inside the folder.

The solution file is simply a delimited file with the first value being a GUID (to uniquely identify the puzzle) and then a comma delimited list of values that represent the Sudoku puzzle.

Here's what the solution file looks like:



The Puzzle List

Since this file contains the list of puzzles for the day and once read would never change, it made it a great candidate for caching. And that's what I did with it. The Scoreboard never directly interacts with the solution file, instead it interacts with a Class (called Sudoku) that exposes a Shared method. The method returns a Hashtable called PuzzleList. The key is the puzzle Guid and the value is the comma separated puzzle values.

The benefit of this approach is that the Shared method can determine if the puzzle list needs to be reloaded (say, it's a new day). If not, it the hashtable is automatically returned.




Public Class Sudoku

Shared _puzzleList As Hashtable

Public Shared Function PuzzleList() As Hashtable

If _puzzleList Is Nothing Or Now.Date > HttpContext.Current.Application("lastSudokuCachedDate") Then '

Try

_puzzleList = New Hashtable
'populate puzzle list.

Dim puzzles() As String
Dim puzzleContents() As String
Dim i As Integer
Dim fileContents As String

Dim server As HttpServerUtility = HttpContext.Current.Server



fileContents = My.Computer.FileSystem.ReadAllText(Now.Date.ToString("MM-dd-yyyy") & "/puzzles.sln"))

puzzles = Split(fileContents, vbCrLf)


For i = 0 To puzzles.Length - 1
puzzleContents = Split(puzzles(i), ":")
'key is guid
'value is comma separated values represeting puzzle.
_puzzleList.Add(puzzleContents(0), puzzleContents(1))
Next

HttpContext.Current.Application("lastSudokuCachedDate") = Now.Date

Catch ex As Exception



End Try

End If


Return _puzzleList


End Function

End Class



The Scoreboard

When scoreboard.aspx is requested, it simply makes a call to Sudoku.PuzzleList() and iterates over the collection. A scoreboard widget is added to the Page's control collection and assigned a Puzzle GUID. That's it. All the scoreboard knows about is showing those scoreboard widgets (and Google Adsense of course!)

The Puzzle File

When a solution file is generated, an scores file is generated for each puzzle. This file is responsible for storing the information that you see on the scoreboard. It's a delimited file as well, storing the time, the name and the url of the person who solved the puzzle.



The Scoreboard Widget
This is perhaps the most important of all the ingredients. The scoreboard widget is a u ser control that takes one parameter - the id of the puzzle. When the widget loads it does two things - it looks in the cache to see if there is a score listing for the puzzle and if there isn't, grabs the file, parses it and sticks it in there.

Essentially, the scoreboard widget only ever displays the data from the cache. This is VERY fast especially when the alternative is to read it from disk every time.

Well, what happens when someone makes it on the scoreboard and the cache is different from what's in the .scores file? In that case, the scores for the puzzle is removed from the cache. So the next time someone goes to the scoreboard and the widget looks in the cache, it's not going to find anything and will grab it from the disk then cache it.

In other words, the first time through, the file is cached forver, until someone beats someone out of their spot on the scoreboard at which point, the file is updated, and the cache is invalidated. The cycle starts all over again.




Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

Dim fileContents As String

If (IsNothing(Cache(PuzzleID))) Then

fileContents = My.Computer.FileSystem.ReadAllText(PuzzleID & ".scores"))

Cache.Add(PuzzleID, fileContents, Nothing, DateTime.Now.AddHours(1), TimeSpan.Zero, CacheItemPriority.Normal, onRemoved)

End If

'get the data out of the cache.
fileContents = Cache.Item(PuzzleID)

Dim scores() As String
scores = Split(fileContents, vbCrLf)

Dim i As Integer

For i = 0 To scores.Length - 1

'parse the contents...blah blah blah
'snipped for brevity

Next

End Sub




The Puzzle Page
I thought I would throw in a description of the puzzle page in for good measure.

The puzzle page take a QueryString parameter ("id"). When the player is ready to play the game, he or she clicks the START button. The START button makes an AJAX call to another page which returns an XHTML representation of the puzzle. It uses the values in the solution file and randomly removes a set number of clues to the puzzle. When the user is done he or she clicks the SUBMIT button and the time is compared to the score values stored in the cache. If the player has beaten any of the times, the file is rewritten to disk with the new players information and the scores data removed from the cache.

And...that's it!


Conclusion



Is it feasible to build a site without a database? You bet! As I hope I demonstrated above, it all depends on is what you're trying to accomplish. The site I built didn't need a database. I just didn't need the overhead or the added complexity.

I have to admit that it was a refreshing excercise for me since I tend to do things just because it's how "they're done". It was great to take a step back, decide on a different approach and implement it. It's also incredibly gratifying to see it work. The site feels snappy because of caching and is very easy to maintain because of the simple file structure. And did I mention debugging? A cinch! I don't have to worry about queries, stored procedures, database connections, password, etc.

I hope this tutorial encourages you to try something out of the norm, or at the very least makes you think about ways in which you can simplify your designs.

As always, thanks for reading!

Update 8:37 A.M. 3-16-07

Reddit user bluGill left a comment:
"...I see several databases: First the the filesystem, which is itself a database. Second is his scorecard, which is a database..."

I can't disagree with this - but I think it's a bit picky. I assumed that it was very obvious that when I refer to a "database" I'm referring to a relational database such as Oracle, SQL Server, MySQL etc.

Update 10:14 A.M. 3-20-07

See my follow up post which is a response to anyone who thinks this is an incredibly bad idea. Please read it and feel free to comment!

Update 1:13 P.M. 3-23-07

I wrote another post about this topic called "Coding By Dogma"

Monday, March 12, 2007

How I Went From 100+ Page Views A Day to a Whopping 5 a Day

I think it might be time for me to throw in the towel and loudly proclaim that I just don't "get it." What I'm referring to here is the process of developing web site traffic.

I'm looking for feedback from any SEO types out there - or anyone who might link to any of my sites out of good will or genuine interest.

Three weeks ago I developed a new site called The Sudoku Challenge. The idea is simple. Every day 10 sudoku puzzles are posted. Solve a puzzle and if you solve it quickly enough - you get your name on the scoreboard. The scoreboard starts fresh every morning. Sound simple, right? I mean, LOTS of people like Sudoku, so you'd think it'd be relatively easy to attract visitors and keep them coming back! Not so, batman.

Initially, I posted links to it on del.icio.us, reddit, digg, and netcape. After getting 100 page views a day (that's not a lot, I know) traffic has all but died. NOBODY is coming back to play.

I have also sent emails (individually written, not templated) to several sudoku related sites letting them know about The Sudoku Challenge. So far, no response.

So I ask you, what is it that I'm doing that is apparently so uninteresting? Is it time to throw in the towel with this idea? Is it time to resort to begging for links (like I'm sorta doing now)? Should I wait, is a month too short a time to decide if an idea is viable?

Any feedback or links would be incredibly welcome! Please comment or email me at john at todotoh dot com so I can thank you personally.