Posted on 12/31/2008 2:00:37 PM by Justin Etheredge
This post started out as just another 2008 recap post, and then it took quite the interesting turn. Basically I went and pulled the top 5 blog posts for this year, and I pulled their names out of Google analytics. Because of the fact that it is hard to just jump right to the page with Google analytics I copied and pasted the titles into Google and searched for them. There was just one problem though, I couldn't find any of them! I would see my post titles linked from dzone, dotnetkicks, and many other people's sites, but not my own.
This was the point at which I started to freak out a bit. I went to Google analytics and confirmed that over the past few months my search traffic had dropped off to almost nothing. I was still getting many referrals, so I hadn't really noticed the drop off in search traffic. I started to wonder, what happened. I noticed that it started about 2 weeks after my new theme had gone up, and so I started looking at the site to see if I could find anything.
After about an hour of combing through html I remembered one of the rules that I had forgotten to follow. Whenever you are optimizing for SEO, turn off javascript! So I turned it off, and within about 15 minutes I believe that I found the problem. You see, on my post pages there was a div with a display: none tag on it surrounding the comments, and there was some javascript that displayed this div if the comment count was greater than zero.
Are you starting to see the problem here? When Google's crawler came to my page they saw a huge chunk of text at the bottom of every post that was inside of an invisible div. They thought that I was trying to game the search engine! Argh! It makes me sick thinking about how much traffic I might have given up because of this. :-)
I guess the moral of the story is, make sure that your site displays all of the content properly without javascript. Otherwise you might end up getting banned from Google. Here's to hoping that my Google link juice returns soon. Oh, and if you'd like to help out, go ahead and link to this post. :-) Have a happy new year, and always pay attention to your site traffic!
Posted on 12/30/2008 6:54:08 PM by Justin Etheredge
If you haven't yet read this thread on Joel's Software Discussion Group and Jeff Atwood's response to it, then please go do so. I'll wait...
You done? Okay, well for those who didn't read them (and that is probably most of you), I'll quickly summarize... a guy posted Joel's board asking about what career he could switch to from being a developer. He is clearly dismayed by the current state of affairs in the development industry and is looking for an out. While I agree with Joel that now is not the time to go switching jobs (never a good idea during a recession), I don't agree with a lot of what Joel says. Every time I read something Joel writes I have to remind myself that he lives in the land of milk and honey. Joel is obviously a talented guy, so why does he think that programmers are spoiled?
But before I start in on Joel's comment, let me first comment on Jeff's post... why is it that developers who are very passionate about their jobs get so pissed off when others aren't as passionate? This is the same mind-set that pisses me off when it comes to religion, politics, operating systems, etc... Okay, so you love your job and you just wanna hug it and kiss it and take long walks on the beach with it, well that is freaking great. Not everyone in this world is passionate about their jobs people! Do you think that every dentist out there just looooooooooves drilling teeth? Sure, there are probably a certain portion of dentists that love helping people, attend conferences about new tools and techniques, and just love everything there is about the mouth drilling arts. But reality is that most dentists go to work, drill some teeth, get a paycheck, and then go sip martinis while they stare out over their 300 acres of lush pasture. Being a dentist affords them to be passionate about something else in their life, wether it be their families, cars, art, pets, or martini sipping. But you don't hear dentists all over the internet complaining about how they can't believe that other dentists don't care as much as they do about what brand their particular water pick is. How could they possibly be using Oral-B's water pick when Colgate's is so superior!!!?? Freakin' idiots.
Get over yourselves. In most careers (and I say careers and not jobs on purpose) there is always going to be a small percentage of people who are going to be very passionate about what they do. And guess what, they are going to have an advantage above everyone else. If every single person in your career was as passionate as you are, then you might just be mopping the floor right now. We can't have development shops full of alpha geeks, nothing would ever get done because no one would ever be able to decide how to do anything. Most alpha geeks have very strong opinions on everything, and they can't freaking stand it when someone else doesn't have an opinion...unless it is different than theirs. In their conscious mind they want other people to be just as passionate as they are, but as soon as someone disagrees, stand back cause sparks are going to fly.
But back to my point... not everyone is passionate about their job. And honestly, we shouldn't expect everyone to be. There just aren't enough people in the world to find a passionate person to perform every single task. And I'm not saying that grossly incompetent people shouldn't leave the software industry, but I have known plenty of good developers who want to leave work and not think about programming until the next day. Jeff also says that the silver lining on the dot-com bust and the current economic downturn is that it weeds those people out who don't truly love software development. Well, I think that it might weed out those people that are bad at programming, but I'm not sure that it will weed out those who don't love it. It is possible that these two sets overlap to a good degree, but again, I've known plenty of good developers who don't do a thing involving computers in their free time. And before you say that they can't possibly be good if they don't program in their free time, then try and remember that if you are spending 45 hours a week writing software at work, how much free time each week are you going to have to devote to writing software? 5 hours? 10 hours? No matter how much time you put it, it is likely dwarfed by the amount of time that you spend perfecting your craft while being paid for it.
So to say that people who don't love programming need to find new careers, well, that is just silly. At the same time though, to say that you should continue to be a programmer if you don't like it is all about whether or not you can make money doing the other things that you are passionate about. And if you aren't passionate about anything, then god help you because you are in for a long and boring ride.
But just because someone doesn't love programming, does that make them spoiled? Well, to say that they are spoiled is to assert that they have been given something that they don't deserve. When someone has a child and they work hard to get paid an allowance and then they go out and buy something nice for themselves, do we call them spoiled? No, of course not, they earned that. The spoiled kids are the ones that mommy and daddy buy everything for, and yet they have no appreciation or respect for any of it.
And yep, we make good salaries, but do we really get treated better than people in other jobs? Well, I might get treated better than someone in a coal mine, but I've never worked in an office where developers are treated any differently from any other office worker. The only people that I have ever seen treated better than others are really passionate about their work, and they quite frankly worked hard to get where they are. In most companies I wouldn't say that developers are pampered any more than any other profession. But what about the salaries? Well, I make less than a surgeon, but do I think that surgeons are spoiled? No, they made their career choice. When I was in high school I was well aware that doctors and lawyers made tons of money, but I was interested in software. We all made those choices.
So is programming a fantastic career? That all depends, can you sit in front of a computer typing on a keyboard for 7+ hours per day? Sometimes a lot longer? Some people I know would think that is hell on earth for any amount of pay, free snacks, or foosball tables (and I, for one, have never worked for a company that had foosball tables). Personally though, I absolutely love it and wouldn't want to do anything else. I cringe at the though of one day being promoted into management. I love writing code and digging into complex problems. Sometimes I am up late at night programming away on something that I will toss aside a week later for some other piece of shiny code. And I love it. But do I expect all of my coworkers to do the same thing? Nope.
And yes, I get paid well, and I get treated well, and I probably have it better than 99% of people out there. Am I thankful for that? I absolutely am every single day. I realize how awesome it is to love what I do, but I didn't just fall into it. I wasn't just handed it. And every single day isn't gumdrops. I think I worked pretty hard to get where I am. Am I spoiled? I wouldn't say so. Okay, maybe a tiny bit. But when it really comes down to it, do I know any developers who are very successful and don't pour their heart and soul into their work?
Absolutely not.
Posted on 12/29/2008 8:18:04 AM by Justin Etheredge
I'm assuming that like myself, many of you out there work for companies that base much of their IT infrastructure (or at least software development tools) around Microsoft products. So, when a new tool like the Entity Framework comes out, even if you are not a fan, you still need to have a solid knowledge of it because you are going to have to use it at some point. At this point most of my ORM experiences have been with NHibernate, but I still feel the need to explore the Entity Framework to see if I can make it palatable for me to use. I say "palatable" because of the fact that the Entity Framework is designed almost entirely around database first design, which is not the way that I like to design my applications.
My goal with this post is not to trash talk the entity framework, but instead to take it as far as I can toward a usable solution that I would be okay with putting into a production application. This post is going to be written as I explore, so please let me know if you see anything that is wrong or missing.
Let's first talk about the domain that we are getting ready to look at. It is going to be a very simple domain, because otherwise it would just overwhelm the blog post by introducing too much complexity. I do want to have enough entities though so that you can see where each technology differs. What we are going to do is start off with a scenario that everyone is familiar with... a user with groups and roles. The user will also have a list of addresses associated with it.
We have 4 main tables along with two join tables. I would explain this schema to you, but if you don't get the schema then this article might be confusing anyway so I'm not going to waste everybody else's time with it. Basically we have already started designing this application in a way that would bother most people who are using DDD. Normally I wouldn't start with the database, but since the Entity Framework essentially forces you into starting with the database first, we are going to take this approach. The reason that I say that the Entity Framework forces you into database first design is because the primary method of generating an EF model is to generate it off the database. And then later on as you make changes, you can then update your model to reflect those changes.
At this point in the process the Entity Framework allows us to get up and running very quickly. We simply add a new Entity Data Model:
Then we get a wizard that lets us connect the model to our database and generate our entities. So, in just a few seconds we are looking at this:
Kinda cool actually. It knows about our join tables and generates many to many relationships automatically. It doesn't however know about join tables with payloads, but then again there is ambiguity about how we might want that sort of data modeled in our app. So now we have our entities in our Entity Data Model, but where are we really at this point? Well, we are actually already at the point where we can create new entities and save them off to the database.
var user = new User();
user.Username = "TestUser";
user.EmailAddress = "test@test.com";
var address1 = new Address();
address1.Street = "111 Test Street";
address1.City = "Test City";
address1.State = "Virginia";
address1.PostalCode = "22055";
var address2 = new Address();
address2.Street = "222 Test Street";
address2.City = "Test City";
address2.State = "Virginia";
address2.PostalCode = "23000";
user.Addresses.Add(address1);
user.Addresses.Add(address2);
var entities = new TestEFAppEntities();
entities.AddToUserSet(user);
entities.SaveChanges(true);
That was painless, wasn't it? But where did the "User" and "Address" classes come from? I don't remember creating any classes... But that is because we didn't. The Entity framework spit out all of these classes into a file that is hidden under our Entity Model called "Domain.Designer.cs". Here is the user class that was generated for the model (I removed all the comments so that it would only be kinda huge) ;-)
[global::System.Data.Objects.DataClasses.EdmEntityTypeAttribute(NamespaceName="TestEFAppModel", Name="User")]
[global::System.Runtime.Serialization.DataContractAttribute(IsReference=true)]
[global::System.Serializable()]
public partial class User : global::System.Data.Objects.DataClasses.EntityObject
{
public static User CreateUser(int id, string username, string emailAddress)
{
User user = new User();
user.Id = id;
user.Username = username;
user.EmailAddress = emailAddress;
return user;
}
[global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[global::System.Runtime.Serialization.DataMemberAttribute()]
public int Id
{
get
{
return this._Id;
}
set
{
this.OnIdChanging(value);
this.ReportPropertyChanging("Id");
this._Id = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value);
this.ReportPropertyChanged("Id");
this.OnIdChanged();
}
}
private int _Id;
partial void OnIdChanging(int value);
partial void OnIdChanged();
[global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(IsNullable=false)]
[global::System.Runtime.Serialization.DataMemberAttribute()]
public string Username
{
get
{
return this._Username;
}
set
{
this.OnUsernameChanging(value);
this.ReportPropertyChanging("Username");
this._Username = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, false);
this.ReportPropertyChanged("Username");
this.OnUsernameChanged();
}
}
private string _Username;
partial void OnUsernameChanging(string value);
partial void OnUsernameChanged();
[global::System.Data.Objects.DataClasses.EdmScalarPropertyAttribute(IsNullable=false)]
[global::System.Runtime.Serialization.DataMemberAttribute()]
public string EmailAddress
{
get
{
return this._EmailAddress;
}
set
{
this.OnEmailAddressChanging(value);
this.ReportPropertyChanging("EmailAddress");
this._EmailAddress = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, false);
this.ReportPropertyChanged("EmailAddress");
this.OnEmailAddressChanged();
}
}
private string _EmailAddress;
partial void OnEmailAddressChanging(string value);
partial void OnEmailAddressChanged();
[global::System.Data.Objects.DataClasses.EdmRelationshipNavigationPropertyAttribute("TestEFAppModel", "FK_Addresses_Users", "Addresses")]
[global::System.Xml.Serialization.XmlIgnoreAttribute()]
[global::System.Xml.Serialization.SoapIgnoreAttribute()]
[global::System.Runtime.Serialization.DataMemberAttribute()]
public global::System.Data.Objects.DataClasses.EntityCollection<Address> Addresses
{
get
{
return ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedCollection<Address>("TestEFAppModel.FK_Addresses_Users", "Addresses");
}
set
{
if ((value != null))
{
((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.InitializeRelatedCollection<Address>("TestEFAppModel.FK_Addresses_Users", "Addresses", value);
}
}
}
[global::System.Data.Objects.DataClasses.EdmRelationshipNavigationPropertyAttribute("TestEFAppModel", "UserXGroups", "Groups")]
[global::System.Xml.Serialization.XmlIgnoreAttribute()]
[global::System.Xml.Serialization.SoapIgnoreAttribute()]
[global::System.Runtime.Serialization.DataMemberAttribute()]
public global::System.Data.Objects.DataClasses.EntityCollection<Group> Groups
{
get
{
return ((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.GetRelatedCollection<Group>("TestEFAppModel.UserXGroups", "Groups");
}
set
{
if ((value != null))
{
((global::System.Data.Objects.DataClasses.IEntityWithRelationships)(this)).RelationshipManager.InitializeRelatedCollection<Group>("TestEFAppModel.UserXGroups", "Groups", value);
}
}
}
}
Hmmmm.... so where is my domain object in there? In fact, all of the domain objects are generated into a single file like this. You get to extend your domain objects by using partial classes. The partial classes that we implement allow us to take advantage of some partial methods that are in the generated classes. As you can see from this code in one of the above setters:
set
{
this.OnUsernameChanging(value);
this.ReportPropertyChanging("Username");
this._Username = global::System.Data.Objects.DataClasses.StructuralObject.SetValidValue(value, false);
this.ReportPropertyChanged("Username");
this.OnUsernameChanged();
}
We have two partial methods "OnUsernameChanging" and "OnUsernameChanged" along with two events "ReportPropertyChanging" and "ReportPropertyChanged". So when we create our partial classes we can tap into these methods. This way if we wanted to intercept the setting of our Username property we could implement a partial class like this (if you haven't ever used partial classes, then go here):
public partial class User
{
partial void OnUsernameChanging(string value)
{
// check value and do something here
}
}
But what if we want to do something when the property is retrieved? We don't really have a lot of options, the getter in the user partial class looks like this:
get
{
return this._Username;
}
Hmmm. So I guess they don't want us to hook into the getter! Having user code hooked into the getter might have caused issues at some infrastructure level for them, so I'm going to give them the benefit of the doubt! But not too much. At first I thought that maybe I could go to the EDM (Entity Data Model) and make the getter and setter on the property as private or protected. Then rename the property to something like "UsernameInternal". Then I could introduce a completely new property in the partial class to expose this property:
public string Username
{
get
{
return this.UsernameInternal;
}
set
{
this.UsernameInternal = value;
}
}
The only problem is that because we have wrapped the EDM generated property, we can no longer query against it! How would I write this query?
var userQuery = from u in entities.UserSet
where u.Username == "TestUser"
select u;
Sure we can put "Username" in the query because we have exposed our own property, but since this property is not in the EDM, the Entity Framework has no knowledge of this property so we can't query against it! Dang. And to think I was going to try and use this same technique to implement some lazy loading. Hmmmmmmm. So if we want to be able to query against any property then we are going to have to directly expose the property that has the "EdmScalarPropertyAttribute" on it. This is the attribute that signifies to the Entity Framework that this property is a mapped scalar property.
This property has to share the name of the property tag in our CSDL file. Sadly, in order to get any control over my classes, it looks like I am going to have to ditch the Entity Designer altogether. Which isn't necessarily a bad thing considering that all of the xml and class files are generated into only two files which creates an interesting situation for teams that are editing these files independently. Definitely a merge nightmare. What blows my mind is that they also actually store the metadata for the EDM diagram right in with the mapping xml.
Before you start thinking that I ditched the Entity Designer too soon, another issue here is that all of the generated entities descend from a base EntityObject class that keeps us from forming our own object heirarchy. And we can't edit any of the generated classes or else all of our changes will be overridden whenever we make a change to it. Another issue is that we don't really have any control over our object lifetime. The Entity Designer spits out default public constructors and a default factory method containing parameters for all properties of the object. Why? I don't understand why they just didn't leave off the constructor and factory method and let me define them in my partial classes. I can't remove them from the generated classes, but I could easily add them if they weren't there. Geeeez.
Alright, so I mentioned that we need to ditch the EDM designer, so what do we use now? Thankfully Microsoft provided us a tool called EdmGen.exe. This is a command-line tool that we can use to generate the mapping files for our database:
EdmGen actually spits out different files for everything. And when I say "everything" I mean only the different file types. So we get these files:
What we are going to do here is ditch the ObjectLayer.cs and Views.cs files and create our own Entities. Hopefully we can isolate most of the EF specific code into a base entity class. But since we are going to remove generated entities we are going to have to keep the behavior that the previously generated classes had. This is where that IPOCO stuff comes in. IPOCO allows you to implement a few interfaces (in our case three) instead of using the base EntityObject class. Our base entity class' definition will end up looking like this:
public class Entity : IEntityWithKey, IEntityWithChangeTracker, IEntityWithRelationships
These are the three interfaces that we must implement in order to use this with our EDM. The first just gives the entity framework something to identify your entities by, the second provides a change tracking mechanism, and the third provides a way for your entity to hold its relationships. These are fairly self explanatory, and luckily we can isolate most of the behavior for these into our base class. So our goal is to have business entities that lack Entity Framework specific details, and which expose no Entity Framework specific types. This post is getting a bit long, so I am going to leave it off right there for now...
In future parts of this series we will break down the base entity class that I have created and take a look at the different entities and how we can create them. We will also take a look at creating an ObjectContext and show you how we can use and query these entities just like we could if we created them through the EDM designer. I will also provide you with the full source to the project that I am using in this series, so stay tuned!
Posted on 12/25/2008 1:49:46 PM by Justin Etheredge
If you follow Jeff Atwood's blog, then you probably already have seen his post about how his awesome Christmas turned into a tragedy all because Lenovo has decided that they want screw him over with insanely priced hard drives and hard drive trays that they won't sell to their customers. I mean honestly, this is exactly the kind of horrible business practices that company's get skewered over. What made me laugh though was that only a few short hours after he put up the post, I searched for "Lenovo server drive tray" on Google and got this back:
It seems that these days when you decide to screw over a customer like that, you might want to google them beforehand. You never know who might be buying your products and what kind of audience they might have. Oh, and Merry Christmas!
Posted on 12/16/2008 5:27:18 PM by Justin Etheredge
For those of you who have used Ruby on Rails before, you most likely already know what migrations are, and you probably love them! They are such a simple idea and once you start using them you'll wonder why you never thought of them. Recently I was doing a bit of work which required me to do some build automation, and (after prodding from some co-workers) I decided that we needed to do some migrations. Migrations are easier to just show you than explain, so I am going to move right into some code. First though, I am going to explain to you the tool that I chose.
I searched around a bit, and found two different tools for doing Migrations in .NET. One was called MigratorDotNet and the other was called RikMigrations. I evaluated them both, and in the end I chose RikMigrations because I liked the way that it searched an assembly for embedded migrations (instead of pointing to a folder of source files) and also allowed you to have multiple sets of Migrations in the same project by identifying them with keys. I'm assuming that this could have been accomplished in MigratorDotNet by using multiple folders, but I chose not to take that approach.
Okay, so let's see some code. First we are going to start off by creating a blank database called "TestMigratorApp". Next I am going to pretend that I have received a requirement for creating a user table with just two columns. One for "Id" which is going to be an auto-incrementing integer column, and another for username. Obviously our user table would be a bit more complex than this, but we don't want to clutter the example with too much extra crap.
So we are going to first start off by referencing the RikMigrations assembly. This is the first part of the process that threw me initially, because RikMigrations is an executable that also has the libraries in it. So you have to add a reference to the executable in order to pull in the types you need. This can be a bit confusing for some, as we are not usually accustomed to adding references to exe's, even though it is perfectly valid.
Once you have referenced the RikMigrations.exe you will need to create a class that implements the IMigration interface. This interface has two methods, one called "Up" and the other called "Down". So, our class will initially look like this:
public class Migration1: IMigration
{
public void Up(Schema db)
{
}
public void Down(Schema db)
{
}
}
The idea is that in the "Up" method we will put code to create our schema, and in the "Down" method we will put code to revert the schema. So, if we wanted to create a user table, we might do this:
public class Migration1: IMigration
{
public void Up(Schema db)
{
Table usersTable = db.AddTable("Users");
usersTable.AddColumn("Id", typeof (int)).PrimaryKey().AutoGenerate();
usersTable.AddColumn("Username", typeof (string), 50).NotNull();
usersTable.Save();
}
public void Down(Schema db)
{
}
}
Here we are using the "Schema" parameter to add a table to the database and then we are adding two columns and saving the table. Pretty cool, huh? We get to create most of our schema using straight C# syntax. We still have the "Down" method empty though, so what would revert our "Up" method? Well, dropping the table, duuuuuuuuuuuh.
Here is the updated version with the delete:
public class Migration1: IMigration
{
public void Up(Schema db)
{
Table usersTable = db.AddTable("Users");
usersTable.AddColumn("Id", typeof (int)).PrimaryKey().AutoGenerate();
usersTable.AddColumn("Username", typeof (string), 50).NotNull();
usersTable.Save();
}
public void Down(Schema db)
{
db.DropTable("Users");
}
}
Okay, so now that we have a complete migration, how do we tell the migration utility that this is a migration that needs to be run? We have to add an attribute to the assembly. We can add an assembly attribute anywhere though, and I choose to put it in the same file as my migration:
[assembly: Migration(typeof(Migration1), 1, "Module1")]
This tells the migration tools the type of this migration, the order of the migration (more on this in a second), and the module name that this migration belongs to. Now we can throw a bit of code in our sample application that will run this migration:
DbProvider.DefaultConnectionString = @"Data Source=localhost;Initial Catalog=TestMigrationApp;Integrated Security=SSPI";
MigrationManager.UpgradeMax(typeof(Migration1).Assembly);
Here I am specifying a connection string, and then passing the assembly that "Migration1" is part of to the "UpgradeMax" method on the MigrationManager. This will tell the migration manager to check the current version of the database and run all of the migrations up to the max version! But how does it know what migration the database is currently at? It creates a table. You will find a table called "ModuleVersions" along side any other tables that you created in your database. This table holds module names and current versions so that the migration manager can easily run only the migrations needed in order to get to the latest version.
Let's say that now we need to have a password field added to the user table that we created in our first migration:
[assembly: Migration(typeof(Migration2), 2, "Module1")]
public class Migration2 : IMigration
{
public void Up(Schema db)
{
Table usersTable = db.AlterTable("Users");
usersTable.AddColumn("Password", typeof (string), 50);
usersTable.Save();
}
public void Down(Schema db)
{
Table usersTable = db.AlterTable("Users");
usersTable.DropColumn("Password");
usersTable.Save();
}
}
All we have to do is just alter the table. Note that the assembly attribute must be at the top of the file, outside of any namespace declarations. In the "Up" we add a column, and in the "Down" we drop the column. Quite simple. Now, if I run my app, it will modify my database by only running the second migration. But if I go in and delete everything out of my database, it will run both migrations which gets me to the latest version of my schema!
This allows you database schema to be developed in a much more iterative manner, just like your software should be! In a later post I am going to take a look at some of the more advanced features of RikMigrations and delve into a few of the missing pieces and how you can get around them. Overall though RikMigrations is a wonderful tool and one that you should consider adding to your tool belt.
Click here to download the source.