Hacker News new | ask | show | jobs
by kryten 4718 days ago
It's also really easy to shoot yourself with unless you understand everything and think each problem through.

Four killer issues I've seen so far:

We had a major production performance issue which turned out to be a stray ToList which was causing a massive memory ballooning. Didn't get noticed in test as the test cases passed but it hit prod and 2000 users bashed it and tried to allocate 20Mb each causing our cluster to shit a brick.

Null reference exceptions! There are so many dereferencing operations in an average LINQ expression that you really have no idea which one is blowing if it goes pop in production in release config.

People using .Single(...) and getting more or less than one result back. So frustrating.

If you push an IEnumerable<T> over an interface boundary the performance and memory semantics are not preserved and you end up with a leaky abstraction. These are shits to resolve. Example: queries executing inside the view which is outside the transaction scope.

We've had to ban it in some circumstances.

1 comments

I agree with your pain points.

We try to use ICollection in our APIs instead of IEnumerable, since the latter can have surprising semantics like being a wrapper for some operation which may not be valid anymore, or might be slower than you expect to do things like .Count(). IMO it's really not best for transporting across interface boundries in the most common case; only when you're specifically trying to avoid having the whole collection in memory or something like that.

Another thing that can help is this wonderful May<T> library[1]. It a great option type[2] for .NET. It helps make operations more composable.

[1] https://github.com/Strilanc/May

[2] http://en.wikipedia.org/wiki/Option_type