January 2008 - Posts

Hard Code

"The trouble is that qaulity and value are wrapped in perception. Even if we built a product that precisely matched the spec with zero bugs, customers and reviewers might still hate it. If it doesn't work the way they think it should, it's junk. If it doesn't solve the problem the way they expect, it's trash.

 At the same time, I-Puke can produce a buggy piece of glorified plastic that crashes twice a day, and it will get showered with praise and command premium pricing just because it reminds people of their pet rocks. Life isn't fair. The markey isn't fair. And customers are fickle." [1]

Never forget that the most "flawless" code in the world can still fail to meet customer expectations. At the end of the day, your goal is to meet customer expectations, not to write "flawless" code. As important as clean code may be, spagetti code that meets customer expectations is far better than beautiful code that fails to do so.

 [1] Hard Code by I.M. Right (Eric Brechner) 

 

 

Silverlight Supercomputer

Dan Fay pointed to an interesting article on CodeProject about building a grid computing framework that runs on Silverlight. The proposition is really interesting. Imagine someone like the folding at home (http://folding.stanford.edu/) project providing and embeddable Silverlight widget that people can place on their sites to help speed genetic research... or how about a little widget on your page that takes some of the load off of your server to help offset high traffic volumes? Just imagine how many teraflops a site like MySpace could output on a given day. Google could potentially use something like this to index the web or calculate page ranks via MapReduce and eliminate a large chunk of their server farm.

Pretty interesting possibilities here... the question is, what are the ethics of "stealing" bandwidth and CPU cycles from viewers?

Posted by Jesse Ezell with 1 comment(s)
Filed under: , ,

.NET Clipboard Problems Under VirtualPC

When performing Clipboard operations (SetDataObject, SetImage, etc.) in a .NET program under VPC, you may encounter the error "Requested clipboard operation did not succeed." This error turns out to be a major pain if you are doing dev. in a VPC like mine, because 99% of your calls will fail. Every once and a while, you'll get lucky and one will go through (it seems to work if you go to another application, cut some text, paste that text, then come back and use the clipboard in your .NET app).

There are a few approaches to fixing this issue:

1) Retry your operation. In fact, this scenario is common enough that Microsoft included with the 2.0 framework an overload of SetObjectData that accepts retry counts and delay counts. However, this is not gaurenteed to work.
http://dedjo.blogspot.com/2007/10/clipboard-setdata-getdata-troubles-with.html

2) Create another thread, set it's apartment to STAThread (since clipboard operations require STAThread) and execute your clipboard actions there. http://bloggingabout.net/blogs/mglaser/archive/2006/11/06/Using-CopySourceAsHTML-in-a-Windows-2003-VPC-environment.aspx

3) Kill and disable the VPC service responsible for clipboard sharing. You will lose some OS integration, but it will fix the problem when the above fail.
http://blogs.msdn.com/virtual_pc_guy/archive/2007/10/31/disabling-folder-sharing-clipboard-integration-etc-under-virtual-pc.aspx

Posted by Jesse Ezell with 18 comment(s)
Filed under: , ,

Sun Buys MySQL, Gets into Database Business

With their plans to acquire MySQL, looks like Sun is gearing up to go head to head with Microsoft on another front.

[1] http://blogs.mysql.com/kaj/2008/01/16/sun-acquires-mysql/

Posted by Jesse Ezell with 3 comment(s)
Filed under: , ,

Designing a Generic Database Layer

Some people like to automatically generate their database tier. Personally, I had enough bad experiences with ORM tools that I try to avoid them. After all, data tier code can be knocked out pretty quickly and it's always nice to know you didn't take any shortcuts. It's been a while since I've seen data tiers discussed, so I figured I'd pass along a modern approach that I have found works quite well and results in really clean data tiers.

Very early in your programming days, you learn that when separating an application into logical tiers, it is important that lower tiers do not couple themselves with higher tiers. As coupling between the tiers is reduced, your code gains flexibility. The entire data tier should be able stand on its own. If later you need to completely revamp your domain model or business layer, the data tier should be able to remain untouched.

First, consider a simple create operation inside a database class.

One option is to simply pass a data row to your database class and let it handle the update. There are a few problems with this approach. First, DataSets aren't exactly a high performance solution and have a lot of overhead. Additionally, a simple DataRow doesn't have a defined set of columns. As a result, you can't use refactoring operations should the column name change, nor can you use the compiler to check argument types or counts.

Another option is to pass an entity object directly to your database class. This is slightly better, as it ensures type safety and supports IDE features such as refactoring and auto-complete. However, this approach has a few flaws of its own.  You can't tell by looking at the method which properties are required to create a customer.  You can't tell if the data tier assigns the customer an ID, or if the ID must the ID be set before you pass the customer in. Additionally, now your data tier is being coded with explicit knowledge about the layout of your domain model. Since the domain model lives above the data tier, this should not happen.

A third approach is to have a method which takes all the parameters required to create a record in the database and return information about the results of the database call, such as an ID from an identity column. By going this route, you keep the coupling between the two tiers low, support compile time checking, and explicitly encode information about inputs and outputs of your method in its signature

Bad
public class CustomerDB
{
  public void CreateCustomer(DataRow row) { … }
}
Better
public class CustomerDB
{
  public void CreateCustomer(Customer c) { … }
}
Best
public class CustomerDB
{
  public int CreateCustomer(string firstName, string lastName, string company, string phoneNumber) { … }
}

Create, update, and delete are easy to handle in this fashion. But how do we handle query operations?

Again, one option is to work with DataSets or DataTables. While this gets the job done, you again incur a needless performance penalty by loading things into temporary tables before the data is loaded into entity objects. Another option is to pass back entity objects from your data tier. Again, however, this couples your data tier to your object model and is bad for the same reasons as it was bad in your create and update methods.

An alternate approach, which utilizes delegates and generics, eliminates the coupling between the tiers as well as the performance problems associated with datasets. Because this approach is new, I have included more complete code, illustrating how the different layers can work together.

Bad

public class CustomerDB
{
  public Customer GetCustomer(int id) { … }
  public Collection<Customer> GetCustomers(string company) { … }
}


Better
public class CustomerDB
{
  public DataRow GetCustomer(int id) { … }
  public DataTable GetCustomers(string company) { … }
}

public class Customer
{
  public static Customer CreateFrom(DataRow row)
  {
    ...
  }
}

Best
public delegate T CreateEntity<T>(IDataReader reader);public delegate void AddToList<T>(T item); public class CustomerDB<TCustomer>
{
  public TCustomer GetCustomer(int id, CreateEntity<TCustomer> create)  
  {
    using(SqlDataReader reader = ExecuteStoredProc(“GetCustomer”, id))
    {
      if(reader.Read()) return create(reader);
      else return default(TCustomer)
    }
  }
  public void GetCustomers(string company, CreateEntity<TCustomer> create, AddToList< TCustomer> addToList)
  {
    using(SqlDataReader reader = ExecuteStoredProc(“GetCustomersByCompany”, company);
    {
      while(reader.Read())
      {
        addToList(create(reader));
      }
    }
  }
}
 public class Customer
{
  public static Customer CreateFrom(IDataReader reader)
  {
   
  }
}

public class CustomerManager
{
  CustomerDB<Customer> _db = new CustomerDB<Customer>();
  public Customer GetCustomer(int id)
  {
    return _db.GetCustomer(id, Customer.CreateFrom);
  }
  public Collection<Customer> GetCustomers(string company)
  {
    Collection<Customer> customers = new Collection<Customer>();
    _db.GetCustomers(company, Customer.CreateFrom, customers.Add);
  }
}
 

How Silverlight Will Change the Way We Build Applications

  "...Don't make the mistake of tossing Silverlight in the same bucket as Flash. While they definitely compete in some significant areas, and both have real strengths in different areas, Silverlight 2.0 was created from the ground-up to be an application development platform equally friendly to designers and developers. If you're a .NET developer (or want to be), you'll find the .NET framework included with Silverlight to be extremely capable and powerful..." [1]

[1] http://community.irritatedvowel.com/blogs/pete_browns_blog/archive/2008/01/08/Why-Silverlight-2.0-will-Change-How-We-Build-Applications.aspx

Posted by Jesse Ezell with 3 comment(s)
Filed under: , ,

Rails is a Ghetto

Zed Shaw, a former big time Rails dev, is leaving the community. He has a scathing rant of the community as a whole as well as ThoughtWorks. I must say that some of Zed's stories sound really familiar to when I was doing a lot of consulting work. There are a hell of a lot of bad customers out there that want you devote your life to thier projects, make them a ton of money, and not pay you back for your work. More often than not, it's because they don't really have any money to spend and they are simply trying to get rich quick off of some really bad idea, or some really poor execution of a fairly good idea.

At the same time, there are even more really bad consultants out there, especially at the big companies. Zed's story about the ThoughtWorks guys charging premium rates for people with next to zero experience sounds pretty familiar. Someone I know got hired by IBM Global Services straight out of college. IBM was billing about $200 for his services and calling him an expert, with zero real world experience... the funny thing is that he was only making about 60k a year... so while IBM was charging an insane rate for his time, his actual salary did a much better job of showing how much he was really worth at the time. I remember hearing a story about a project he was on for some extremely large clients. The project was to be written in a language that just about no one on the team was familiar with (despite the fact that it was one of the most commonly used languages for such things... further pointing out the lack of experience on the team). Their first official task while they were on the client's dime: "learn X language." So, not only was IBM billing an insane rate, they were also charging the client to train their own employees! Must be nice.

Now, I haven't worked specifically with any ThoughtWorks developers, but I have worked on projects with some big name .NET consultants... and my experience with those consultants has been the same as Zed's. They come into your place, bill you for experts, and produce a load of crap that you could have paid some high school kid $10/hr to build instead. But they really don't care, because they were on .NET Rocks or wrote some bloated framework that cures cancer, and now everyone and their mom is trying to hire them. So they'll come into your place, bill you 5x as much for 10x as much code as it should have taken to do the job, leave when the crap hits the fan, and then move on to the next unsuspecting client.

[1] http://www.zedshaw.com/rants/rails_is_a_ghetto.html

More Posts