Code Smell: Solution Explosion

Symptoms

  • You’ve got more than one (Visual Studio) solution depending on the outputs from another.
  • Your checking binaries (.dlls, etc.) that aren’t third party into your version control system, as you do with third party stuff.

Causes

  • You have clumps of projects that are highly cohesive. You feel you need to organize them. A solution seems like a good organizational unit above projects.
  • More than one team is working on dependants. To avoid integration pain, they want to work on just their code, using a static version of the dependency (a compiled branch.)

What to Do

  • Put all the projects into one solution.
  • Use folders to organize them, instead of solutions.
  • If there are multiple teams, they all work on their projects in the same solution.
  • If it takes too long to build, unload projects you’re not changing right now. Load them again or use a command line build before checking in or doing cross project refactorings.

Payoff

  • Reduction in build and version control complexity
  • Reduction in code ownership
  • Less big-bang when updating dependencies.
  • More “we’re all in this together”
  • For web applications, you might end up using server resources far more efficiently if the modules can share an app pool. This can make a huge difference when you have a lot of projects.

Contraindications

  • If the project really, really needs to be complicated (say, 100+ screens/pages, each with 20+ controls/fields, or more than 15 developers) then it makes sense to separate them, at the same time spending effort to minimize coupling between the solutions. The idea is to make this more of a last resort. Rough estimate: solution/developer should be about 1/15.
Advertisements

Entity Framework: Soft Deletes Are Easy

What is soft delete?

When you work with data in your database you often need to delete records from the table. The standard and well known way to do that is just to execute DELETE query over this record (or force your ORM data mapper to do this for you).

DELETE FROM Companies WHERE CompanyId = 1

But there are many reasons you may want to “keep” your deleted records. For instance, if something has been removed accidentally by the user, or deletion was caused by the bug in your software. Sometimes backup won’t work for you, or restore data from backups can become a pain.

Imagine when you have IDENTITY(1,1) specified over CompanyId:

CompanyId int IDENTITY(1,1) NOT NULL

You accidentally removed this record and you want your company back with the same Id, because you already have urls like yourwebsite.blabla/company/1

You can’t perform

insert into Companies values (1, ...) 

easily and override identity column (MS SQL server will ask you to switch IDENTITY_INSERT to ON, can’t say a lot about other databases).

But the more serious reason comes into play when you have relationships between your entities (and foreign key constraints in your database).

Imagine that you have “Company – Newsletter” one-to-many relationship. Company can contain many newsletters, and newsletter belongs to one company. In this case when you delete a company, you need to delete all of the newsletters as well. You still can do this with database mechanisms like cascading deletion. But there are two reasons you don’t wanna do that:

1. Data loss risk is much higher, with one delete query you can delete multiple records.

2. You shift your business logic to the database engine. Now database decides how to delete your records, so you can’t cover your business logic with tests.

So for us it would be better to keep all of the records in database, but filtering them out on the way to our application. Soft delete is the technique when you add additional boolean field to your entity table (I usually call it IsDeleted). And when you want to delete something, you just set IsDeleted property to true. Our Company entity:

public class Company
{
	[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
	public long CompanyId { get; set; }
	public string Name { get; set; }
	public bool IsDeleted { get; set; }
}

 

Lame way to handle soft deletes

When you have additional property specified, you can now exclude deleted records from your query:

Or even you can write your own extension. But this approach has several disadvantages:

1. You must care about IsDeleted everywhere
2. Your code will soon become over-complicated
3. It’s very easy to forget about IsDeleted

So we need something more flexible and much easier. Ideally, we must be able to work with entities in our application like they are actually deleted. This would be perfect:

We don’t have any IsDeleted dependency and we don’t have to care about that every time we write a query or access mapped ICollection properties. But is it achievable? The answer is yes.

Entity Framework Code First and Soft Deletes

It’s easy to use soft deletes with Entity Framework if you know the trick. The trick is to tell model builder to take care about IsDeleted property for our entity.

The code above works like a filter between the database and our application. You don’t need to filter your entities by checking IsDeleted property every time. Filtering will work inside of Entity Framework.

Save It To Database, Jim

When you already have IsDeleted property, you can easily delete entity with marking IsDeleted as true, right?

Wrong! The code above won’t work. Because IsDeleted is not mapped now. Code won’t generate any exceptions, but IsDeleted property will be skipped while saving changes. So we need to handle the standard delete functionality somehow:

In order the above to work, we must extend our database context and override SaveChanges. Note that I also added DeletedAtUtc property – it’s always useful to know when something has been removed. You can also add DeletedBy in order to keep a reference to the user who has deleted particular entity.

Overriding SaveChanges

Overriding SaveChanges:

The code above will iterate through every entity marked as deleted and will SoftDelete it. Note that it’s marked as deleted by Entity Framework when we remove an item from the context. And here is self-explanatory SoftDelete implementation:

This method will execute sql query over each removed entity:

UPDATE Companies SET IsDeleted = 1 WHERE Id = 123

To make it versatile and compatible with any entity (not just Company) we need to know two additional properties:

1. Table name for the entity (Companies in our case)
2. Primary key name for the entity (Id in our case)

There are two functions inside of SoftDelete method for this purpose: GetTableName and GetPrimaryKeyName. I have defined them in separate file and marked class as partial. So be sure to make your context class partial in order things to work. Here is GetTableName and GetPrimaryKeyName with caching mechanism:

Conclusion

Soft deletes are easy when you know how to cook them. This article will help you to implement soft deletes for your application. I hope we’ll see soft deletes functionality in next versions of Entity Framework.

Building a Constraint in Rhino Mocks

I have been using Rhino Mocks for a while now, but I must admit there are a lot of features I know I could use that I don’t. One such feature formerly in this category is Constraints – namely, making my own.

I have a complicated, almost integration test, where I need a repository to return a large set of data to be using by the system under test. Essentially, the SUT will ask for prices for a bunch of securities on two separate dates.

This will always return the same set of prices. I need the Mock to return a different set of prices for a different date. I need to add a constraint:

This will tell Rhino Mocks to return T-N prices when the SUT asks for T-N, and T prices when asked for T.

Unfortunately, the SUT has a problem now where T is GetDate(), so the test will fail sometimes when the time between setting the expectation and the time the prices are asked for is greater than the minimum resolution of DateTime. This will be fixed later, but first I need to get it under test.

What I really want is just to be Date equal anyway, not DateTime.

It’s very easy to add a new constraint for this in Rhino Mocks:

Now I can simply use this constraint to set expectations:

I didn’t consult any documentation, blogs, google, other people to do this. I just let intellisense be my guide and literaly built it in about 2 minutes. I’d never written a custom constraint before. In fact, looking through the Rhino Mocks source code, I now see I could have written a PredicateConstraint instead (but it would have been a little more verbose to use.)

It’s really easy and natural, the way things ought to be (Thanks, Ayende!)