Anti Patterns
Now that we have covered some good patterns and approaches it seems useful to add this section to deal with patterns which seem at face value like a good idea, but in reality are not such a great idea in the long run. This is not to say that you should NEVER use these patterns, but more a case of think about if the problem you are trying to solve could not just be solved in a better way.
Rather than go in depth on all of them we will just give "a quick rundown" over what they are, why they are seen as good, and why they cause issues.

Static classes

1
// Some static class
2
public static EventSystem
3
{
4
public static void Publish<T>(T message)
5
{
6
// ...
7
}
8
9
public static void Subscribe<T>(Action<T> subscriber)
10
{
11
// ...
12
}
13
}
14
15
// Anywhere you like
16
EventSystem.Publish(new SomeMagicMessage());
Copied!

Why its seen as good

So static classes basically provide you a class which always exists and can be accessed anywhere so no need to instantiate, this means no need to pass instances into constructors or have to worry about different implementations, there is only ever one, its always there.

Why its actually bad

Because you cannot change it.
Seriously...
Ok so lets look at a scenario where you want to unit test some class which uses EventSystem, how do you mock out the dependency? you can't right... and what if you are using multi threaded code... uh oh your static class may blow up if you are not accounting for threading.
You lose a lot of control and configurability over how your logic is run when you depend upon logic in static classes (extension methods to some extent can fall into the same trap), as you are not able to change the implementation without changing your source code, this impedes testing as well as overall design.

A better way?

First of all use IoC and inject in your dependencies, this way you can change the actual implementation whenever you want, it makes your code more testable and more configurable, which ultimately makes it more re-useable. If you pair this with DI you also are in a position to set your object to act like a singleton which is basically the same as a static class anyway without any of the design drawbacks of explicitly depending on a static class.

Singleton classes

1
// Some interface
2
public interface IEventSystem
3
{
4
void Publish<T>(T message);
5
void Subscribe<T>(Action<T> subscriber);
6
}
7
8
// Some singleton class
9
public class EventSystem : IEventSystem
10
{
11
private static EventSystem _instance = new EventSystem();
12
13
private EventSystem() {}
14
15
public static EventSystem Instance => _instance;
16
17
public void Publish<T>(T message)
18
{
19
// ...
20
}
21
22
public void Subscribe<T>(Action<T> subscriber)
23
{
24
// ...
25
}
26
}
27
28
// Anywhere you like
29
EventSystem.Instance.Publish(new SomeMagicMessage());
Copied!

Why its seen as good

A singleton is basically a fancy static class but with some additional benefits, like it can implement an interface because its not a static class, it can also be passed around as a varaible if needed as its both a static and an instance. It also enforces that there is only one instance of it in existence just like a static class, all other benefits are same as a regular static class.

Why its bad

Same reasons a static class is bad.

A better way

Same solution as a static class, create it as a DI singleton so its lifetime is configurable and more testable.

Generic Repository Dumping Ground (aka Generic Repository)

1
// Some generic repository interface
2
public interface IRepository<T>
3
{}
4
5
// Some repository implementing methods for Users
6
public class UserRepository : IRepository<User>
7
{
8
public User CreateUser(SomeGuff guff) { /*...*/ }
9
public User UpdateUsersEmailButNothingElse(Guid id, string email) { /*...*/ }
10
public IEnumerable<User> GetAllUsersWithMiddleNameJames() { /*...*/ }
11
public IEnumerable<User> GetActiveUsers() { /*...*/ }
12
// Repeat as many specific bits of logic as you need
13
}
Copied!

Why its seen as good

Its putting all responsibilities for the type (User in this case) into one class, SRP to the max! you can inject this in anywhere you need to do something against a user and you know exactly where to put your logic into when you need to do more stuff related to that type.

Why its bad

Where do you draw the line? it just becomes a massive dumping ground for any and all CRUD logic related to that entity, you also run into the common problem of "OH NO, MY UserGroupRepository NEEDS TO ACCESS THE UserRepository TO DO SOME STUFF" then you end up with repositories including other repositories just to access a couple of methods, then you end up making it harder to test, and each repository has LOADS of tests because it has to test every method you have come up with.

A better way?

Look at the repository section, the generic repository pattern does not need to be bad if you make generic CRUD operations and then put any specific guff like GetAllUsersWithMiddleNameJames into their own IQuery classes. This allows you to re-use queries within other queries/repositories/classes without including the whole repository and also makes things more testable/mockable as you are testing most parts in isolation.
It may seem like more of a faff up front but in the long run it can pay dividends and also improve your re-use without causing a massive spaghetti dependency nightmare where all repositories end up communicating to share logic.

Service Location

There is no point mentioning it too much here as its already mentioned in the service location topc, however its worth noting here that its bad, and you should probably use DI instead wherever possible.
Last modified 2yr ago