Reflections and Corrections
If you’re reading this, perhaps you’ve found something on this blog interesting or helpful. Odds are that you’ve never read the About Me page. And why would you?
This post is about my other blog posts. Like the About Me page, I’m writing it only because to some extent my blog represents me. Over time, however, the individual posts may not. I feel compelled to address this somehow, even though it’s unlikely that anyone cares except me.
Some of this reflecton is a little bit funny. This blog contains bits and pieces of my learning journey, but it’s weird to read myself describing unit tests like I’ve just discovered fire. In other cases the information is obsolete. And sometimes I no longer feel the same way about what I wrote or I was just wrong.
With that in mind, here are some notes on a few older posts:
Abstract Factory Pattern
Alternatives To Abstract Factories Part I - Lifetime Management
I used abstract factories a lot in 2016. Since then it’s completely fallen off my radar. I didn’t use it in any domain modeling sense because I had no idea what that was.
In the example I created an IAddressValidatorFactory
. Code that needed an IAddressValidator
would pass it some argument (like an address). The implementation would decide what sort of IAddressValidator
to create, create it, and return it.
In retrospect the way I used these factories made little sense. Even if it’s abstract, why would a consumer need to know that there’s a factory creating implementations of IAddressValidator
?
There may be different address validation strategies. For example, the way we validate postal codes or provinces could vary depending on the country. But I’d encapsulate all of that within an implementation of IAddressValidator
. Pass the address to it, and internally it decides which validation strategies to implement. Within that encapsulation there could still be a factory that returns a different IAddressValidator
. But I wouldn’t expose any of that complexity to any consumer that just wants to validate an address.
Dependency (Constructor) Injection With Web API Action Filters
Once upon a time we needed this. Now we don’t. There are attributes like ServiceFilterAttribute
and TypeFilterAttribute
that simplify injecting dependencies into filters.
Define Types Instead of Using Primitives
This post could be replaced with
Google “value objects.” They’re great. Use them.
If we’re using C# records then we don’t need to implement equality checks.
.NET Event Bus - Dependency Injection Friendly and Agnostic
This was fun to play with back in 2016. I think I used it once. In real life I think I used it once. I was picking up little pieces of domain modelling concepts but never got to use them. Eight years later I rarely get the opportunity to do anything that resembles domain modelling. Unfortunately the pull of anemic, database-centric code is very strong in many .NET environments.
Given the opportunity to use domain events I don’t know whether I’d bother with writing custom code when options like NServiceBus are available.
The Dependency Inversion Principle For Beginners
Dependency inversion is a valuable concept. These days it’s so baked into .NET applications that I’m not sure if the explanation helps. I don’t think about it when writing code. It’s just what we do. At the same time I didn’t understand the concept as well and my explanation was probably all over the place.
Depending on Functions Instead of Interfaces - Why and How
Depending on Functions Instead of Interfaces - The Navigation Problem
I still like the idea of it and I use it once in a while, but not as much as I hoped. It’s one more slightly different thing introduced into a code base and never catches on.
String Interpolation Functions vs. string.Format Constants
This is a solution without a problem.
The Interface Segregation Principle Applied in C#/.NET
I mostly stand by this. I argued that the principle is about dependencies and coupling, not about avoiding large interfaces. I suppose it’s about both, although we generally overlook the coupling issues and focus on the size of the interface.
I’ll re-iterate that articles focusing on not throwing NotImplementedException
completely miss the point. We shouldn’t throw that, but that’s not what the principle is about.
No, MediatR Didn’t Run Over My Dog
This is the one that haunts me. I was in an odd purist phase in which I ranted about MediatR left and right. Yes, it was misused in places. No, I still don’t see how it’s connected to the mediator design pattern. And yes, I still cringe when I see “CQRS with MediatR” articles because the two have nothing to do with each other.
That has nothing to do with the tool. I’ve used it many times since then. It’s familiar. It does something we need. My reasons why we shouldn’t use it didn’t make sense. I recant. (In this case I felt compelled to add comments to that effect all over the original post.)
An Experiment With Making Integration Tests Easier to Write - Part One
An Experiment With Making Integration Tests Easier to Write - Part Two
It was an experiment. It led me in the right direction but I wouldn’t do what I described here. It’s overcomplicated. Over time I’ve settled on something more like what I described in this post.
- Cleanly separate dependency injection code so that I can re-use the production code in a test.
- Create a
TestServer
orIHost
and register dependencies with it using the same code as I use in production, including code that reads from configuration settings. - If neeeded, override some dependencies with mocks.
- Either send HTTP requests using the
HttpClient
provided byTestServer
, or resolve dependencies from theServiceProvider
and interact with them.
That’s it. I’m the only one who cares, but now I feel better.