BuddyBetter 1.3

January 19, 2008

New version of BuddyBetter was released this morning! Today’s changes are relatively minor but include a few cool new ones

  1. HTTP Redirect fix. Now you can browse all your favorite buddybetter links with a friendly url (http://www.buddybetter.com/bet/Will_Apples_stock_hit_$300__share_by_end_of_2008)
  2.  New iPhone support allows you to add bets via special iPhone interface.

Additionally, we’re continuing to beef up the underlying framework we’ve built to support all of our sites. We have some really cool new shared modules coming down that we’ll be able to use on any of our sites without copying or retooling any code.

Lastly, expect a new interface sometime in the next 3 to 4 weeks!


BuddyBetter 1.2

January 9, 2008

New Release of Buddy Better tonight!

  1. Friendlier URLs — http://www.buddybetter.com/bet/my_bet instead of ViewBet.aspx?guid=xxxxx
  2. Buddy Better blog — keep track of what we’re doing!
  3. “Grab This” fixed — embed your favorite bets on your blog
  4. Share on Facebook — share your favorite bets on facebook
  5. Homepage — now shows most recent bets instead of bets from a specific category

More good stuff coming soon!


BuddyBetter.com Changes

December 31, 2007

I made a few changes to the BuddyBetter project this weekend:

  • I added unit testing to our WCF framework components.  This was necessary for me to build out the WCF.Common.Emailer stuff.  I’m using TestDriven.NET to aide in the execution of the tests (highly recommended).  This also leads the way for eventual build server and test automation via CruiseControl.Net.
  • I forced our BuddyBetter application to used the QueueEmail sender instead of the direct email sender.  I change the accessibility for all the direct SMTP sender methods to private.  I really want everything to go through the database, because the SMTP services are too unreliable (and not very testable).
  • In BuddyBetter’s Global.aspx, I kick off a separate thread to send the emails.  Basically, it does a Email.Dequeue, then goes to sleep for ten minutes.  Will have to keep an eye on things as this is the first time I tried to keep a long thread running in the ASP.NET execution space.
  • Log4Net wiring.  I added lots of stuff for Log4Net.  Will discuss at a future in-person meeting.

Log4Net In Action — Logging Levels

December 31, 2007

One of the reasons I prefer log4net over any other logging framework is because it provides five, and exactly, five logging levels. A newcomer to log4net may hestitate at the fact it only offers five static logging levels. In over seven applications, I haven’t found the need to create an extra level — these five levels covered every need. Also, only having five levels reduces the amount of time managing and discussing what event should be of what level.

Here’s how I use the five levels and how I filter during the different stages of deployment:

  • DEBUG – Low-level information. As much as you want to track. In fact, I like putting TOO much information in DEBUG. You can always filter it out in other environments other than development. Can be a positive or a negative message.
  • INFO – Summary information. Info is typically a positive message. Used for reporting loops of collected objects or other “everything is okay” type message. On in all enviornments except production. If production is showing an error that can’t be traced back, we’ll fall down to this level.
  • WARN – Precautionary error message. Typically, a weak negative message. Contains behavior that is unexpected, but the application can recover from the error. This level is typically in production. In early application versions, a lot of these messages may accumulate. Either it means your application is on the verge of failing or the wrong message type was selected. Either way, these should be few and far between in a solid running application.
  • ERROR – Something wrong occurred. This is a serious issue. However, the application can recover. A component of a system may have failed. For example, we try to open a file over the network, the computer is unexpectedly disconnected from the network and the application traps an exception. Typically, we can recover from this error and we’ll send an error message to the user in the form of a MessageBox.Show(“File cannot be opened because of network failure. Please call…”);. However, we want to send this up to our support team to warn them of a faulty application. As a consultant, I’ll typically send this to my email, even if the project is finished. These should rarely occur, but when the frequency rises, it usually indicates a bug in the application.
  • FATAL – Application panic. Typically, application cannot start or failed unexpectedly. An application should never get to production if it is still producing these errors. If this occurs in production, this message should be sent to first line of support for the application.

(Also crossposted at JasonHoekstra.com.)


Promotion – 1# 2008 Skill To Master

December 29, 2007

TJ, you and I are both good enough coders to given a reasonable amount of time, we can create whatever is out there on the Internet.  Login forms, automated emails, geographic searches, we’ve done it all and what we haven’t, we can figure out.  For me personally, I have maxed out amount I want to be up at 4am learning new technologies.  At a certain point, you wake up and realize that everything around you is data and it’s a matter of moving it or holding it in a place until you need it again.

The next important skill for us to master is promotion.  If I had to guess, I’d bet that all of your work in the promotion/marketing side of things has been handled by other people.  Mine has.  Either there is a team to do that sort of thing and it’s abstracted far away from me or the owner of the business is the thing and already taking care of things.  As weekend coding entrepreneurs,  we can’t pass that responsibility to someone else.  It’s in our hands.  It’s the reason why we talk about Flickr and Facebook and Google instead three other web sites.  A product has to fit the user experience for the task it tries to achieve and that product has to be promoted.

My goal for 2008 is to get better at promoting things.  SEO, word of mouth, guerrilla techniques, whatever it takes to get good products in front of people who need them.


NetTiers Code Generation Cycle

December 27, 2007

Code generation is the biggest disadvantage to running an application on NetTiers.  The code generation cycle is a bit long and unnecessarily complicated.  It would be much easier to generate the framework code when the database updates via a simple one click apparatus (or a few word command) as done with Rails.**

Each time the database model updates, you must re-generate the framework for your application.  NetTiers provides a strong types/objects from tables in your database, so when your database changes, the code will change as well.  Running through five or six clicks and generating code guaranteed to work is much better than hand coding changes to three or four individual layers (unless you are billing a client and bill by how many keys you press per hour).

These instructions apply after you have setup your initial project.  [This will be a separate post … someday.  Email jasonhoekstra@gmail.com and send a letter of encouragement.]

0.)  You must have CodeSmith 4.0 or higher installed.  (I’m using 4.1 for this post.)
1.)  Open NetTiers.Cst (mine is located in C:\NetTiers_2.2\NetTiers.Cst).  Double clicking on a .cst file will open the CodeSmith engine.  (I drop an icon on my Quick Launch bar that shortcuts to NetTiers.cst.)
2.)  Open the configuration file for the project.  TJ, for BuddyBetter, I open C:\Projects\WCF\Products\BuddyBetter\BuddyBetter.csp.
3.)  Make sure that Visual Studio has closed the solution, otherwise, you’ll have to answer to five or six new project notifications.
4.)  Hit the Generate button.
5.)  A web page summary will pop up.  Scroll to the error count.  Make sure it is zero.
6.)  Reload the project file in Visual Studio.  Go back to work with your changes.


BuddyBetter

December 27, 2007

I just noticed that Facebook has a “share” link we can include on all of our BuddyBetter pages

http://www.facebook.com/share.php?u=http://www.buddybetter.com/viewbet.aspx?guid=a516e998-c8c8-47ff-a77c-12f005af9343

This will include some of the contents of the bet on a person’s facebook profile.

We still want to create a bet using their API. But this would be a nice stopgap solution.

Also, any thoughts on creating a BuddyBetter blog that’s linked on the actual BuddyBetter page? Where we announce new features, bug fixes, how-tos, etc? Just a thought


Linq or NetTiers?

December 26, 2007

With the core work of our first foray into collaborative web development out of the way, Jason and I have begun to discuss our next project. With that, I’m taking the opportunity to take a step back and think about what things we might be able to do differently next time around (me contributing more is but one).

In our first project, BuddyBetter.com, Jason and I leaned heavily on NetTiers to do most of the heavy lifting for us. It didn’t take me long to become an instant convert to how NetTiers could totally change my life as a coder. It’s fast, simple to use, and generates your entire data access layer for you. So why would I consider changing?

Enter Linq. With the release of .NET 3.5 and Visual Studio 2008, Linq finally becomes an ‘official’ part of .NET. Standing for “Language interpreted Query”, Linq is a radical new approach to treating a database in an object oriented fashion. Instead of the old paradigm:

// create dataset from a DB table    DataSet oDataSet = ExecuteDataset(ConnectionString, CommandType.StoredProcedure, "StoredProc",sqlParams);
 // Code here to load this dataset into a custom collection (or handle natively)

Of course the beauty of .NetTiers is that it handles the above code for you. However, under the hood it’s still treating the database like what it is — a collection of rows and columns that represent some object in the real world.

Where Linq differs is that it allows you to skip this conversion step and jump immediately to handling your database like a collection of objects. Now we can do something like :

using System.Data.Linq; // be sure to add this. the System.Linq namespace is not sufficient for SQL to Linq  // Create a class for each table we want to access (or use a tool like SQL metal to automatically create the classes for us)  [Table (Name="Groups")]
    public class Groups
    {
        [Column(IsPrimaryKey = true)]
        public Guid ID;
        [Column]
        public string GroupName;
        [Column]
        public string GroupSiteUrl;
    }     // now we can access our table thusly:  // actually handles the main connection to the DB
DataContext oContext = new DataContext(sConnectionString);            

// getting our table "Groups" --> see Groups.cs in this project
Table<Groups> Groups = oContext.GetTable<Groups>();
// query-like language. you can do wheres, group bys, orders, etc
var q =
 	from c in Groups
	select c;

 // all of the rows
foreach (var group in q)
	{
         	string s = group.GroupName;
                string r = group.GroupSiteUrl;
                Guid g = group.ID;
        }

And that’s it. You are now accessing table data using Linq.

So with all of this being said, what do we do for our next project? Stick with .NetTiers? Or move on to Linq. My gut tells me to sit tight and use NetTiers for the next project or two while we hone our Linq skills. I still have a lot to learn. Your thoughts Jason?


To be radically transparent…

December 26, 2007

Wired magazine had an excellent write-up earlier this year about this new concept called “Radical Transparency” (Wired 15.04). This is the notion that companies use a blog for a running dialog on what’s happening within their company. This includes the good — like new releases, the bad — like bugs or internal debate on how to handle an issue, and the ugly — like how to handle a PR nightmare a company might be working through.  All of this, collectively known as radical transparency, helps pull back the curtain on what happens inside a company. So I bring all of this up because Jason had a most excellent idea over the weekend (perhaps the spiked eggnog helped inspire him). Let’s take radical transparency one step further. Not only will we use this blog to discuss best practices, new releases, and forthcoming features. We will also use this blog to discuss, deliberate, and debate how we will implement technology going forward. Since Jason and I are mostly of like mind, this debate might end up a little boring (Jason: “Let’s use an HTTP handler for this” TJ: “Ok”) but if nothing else, it may help illustrate why we’ve chosen to do something and give you, the reader, a chance to weigh in and sway our opinions one way or the other.


NetTiers Recipe – ParameterBuilder

December 23, 2007

NetTiers provides a wonderful way of querying a SQL database with strong .NET types and a query simplified language.

For this example, I’m building our queued email sender. I have stored a bunch of emails in the database and it’s time to send them.

In SQL, this is the query I’m trying to achieve:

SELECT
EmailQueue.*
FROM
EmailQueue
WHERE
SentDateTime IS NULL AND
ErrorMessage IS NULL

With NetTiers, I’m going to use the strongly typed ParameterBuilder class, in this case, the generated EmailQueueQuery.

EmailQueueQuery query = new EmailQueueQuery();
query.AppendIsNotNull(EmailQueueColumn.SentDateTime);
query.AppendIsNotNull(EmailQueueColumn.ErrorMessage);
TList<EmailQueue> messages = DataRepository.EmailQueueProvider.Find(query);

foreach (EmailQueue message in messages)
{ // now I have a strong collection of EmailQueue object, send email messages }

There are hundreds of ways to solve this problem. I could use a SQL string or stored procedure and fill a DataReader. I could use a custom stored procedure, regenerate and obtain the same collection of objects. I prefer the method above and here’s why:

1.) Everything is strongly typed. When the model (database schema) changes, my code breaks quickly. When TJ changes the ErrorMessage to ErrorMessageType, regenerates and recompiles, there is going to be a big error message saying WCF.Entities.EmailQueue does not contain a definition for ‘ErrorMessage’. To me, breaking the code quickly (and repairing it quickly) is good. The alternative with the SQL text or stored procedure is to retest every reference to the query. (One of my favorite generated objects from NetTiers is the <T>Column enum, which contains the column names from the target table. No need to flip back to SQL Server to see what you called that field — IntelliSense will provide in Visual Studio!)

2.) I’m sure many DBAs would have my hide for this, but I prefer to keep everything in .NET and Visual Studio. Each time I have to leave the IDE, my attention is distracted. The parameterized query keeps my head down in the space of the problem. If we find during testing, the query is too slow and we need to refactor and replace, we can do that. For now, this is a simple solution which enables fast (as in keystokes, not always performance) database access. For me, it’s better to start simple and make complex as the situation dictates. I’ve found that parameterized queries fit around 90% of my data access needs.