Microservices have really only become possible for .NET Development with the advent of .NET Core, and because of that we have almost two decades of built up practices that don’t apply in the world of microservices.
In case you haven’t heard of Microservices, here’s a quick ten second primer on them: They’re a deployable focused on doing one thing (a very small thing, hence ‘micro’), and they communicate their intent and broadcast their data over a language agnostic network API (HTTP is a common example).
For instance, sitting in the WordPressDotCom editor right now, I could see maybe a dozen Microservices (if this weren’t WordPress), a drafts microservice, notifications, user profile, post settings, publisher, scheduler, reader, site menu, editor, etc.
Basically everything above is a microservice. All those clickables with data or behavior above? Microservices. Crazy, right?
Back of the cereal box rules for Microservices:
- Code is not shared
- APIs are small
- build/deployment of that service should be trivial.
So that’s code, but what about organization? What about project setup? Those are the pieces that are as crucial to successful microservices as anything else.
In .NET Monolithic projects, we’ve spent years hammering home ‘good code organization’, with lots of namespaces, namespaces matching directories, and multiple projects.
But thinking about those rules of organization for Monoliths, when’s the last time you were able to easily find and fix a bug even in the most well organized monolithic project? On average, how long does it take you to find and fix the bug in a monolith? (Not even that, but how long does it take you to update your code to the latest before trying to find the bug?)
The benefits of Microservices are the polar opposite of the benefits of a Monolithic application.
An ‘under the hood’ feature of Microservices is that code is easy to change. It’s easy to change because it’s easy to find, it’s easy to change because there’s not much of it, and it’s easy to change because there isn’t a lot of pomp and circumstance around changing it. In a well defined microservice, it would take longer to write this blog post than to find the issue (I’m exaggerating, but only slightly).
If you’re developing .NET Microservices, here are some points to keep in mind, to keep from falling into the old traps of monoliths:
Keep the number of directories low: The more folders you have, the more someone has to search around for what they’re looking for. Since the service shouldn’t be doing that much, there isn’t as much need for lots of directories.
Move classes into the file using them: Resharper loves to ask you to move classes to filenames that match their class name. If your class is just a DAO/POCO; rethink that. Keep it close to where it’s used. If you do split it into a separate file, think about keeping all of its complex types in the same file it’s in.
1 Microservice, 1 .NET Project, 1 source control repository: This is a microservice. Splitting things out into multiple projects in one .sln file necessarily raises the complexity and reduces the advantages Microservices have. Yes, it feels good to put that Repository in a different project; but does it really need to be there? (Incidentally, it’s currently impossible to publish multiple projects with the .NET Core CLI)
Code organization should be centered around easily finding code: If I can’t find what your service is doing, I may just rewrite it. Then all that time you spent on that service organization will be gone anyway. The inner-workings of your microservice should be easy to find and work with. If they aren’t, maybe it’s doing too much?
Your build process should be trivial: If your project pulls down Nuget packages from two separate repositories, it’s time to rethink your build process.
Why are you sharing code, anyway?: Private Nuget packages are monolithic thinking; to make “sharing code” easy. But in the Microservice world, you shouldn’t be sharing code, right? Duplicate it, pull it out into its own service. Sharing it simply means you’re dependent on someone else’s code when it breaks (which is why we have microservices in the first place; so we don’t have that dependency).
Working beats elegant, every time: I love elegant code. I also love working code. Incidentally, I get paid to write working code, not elegant code. If using a microservices based architecture allows me to move faster in development, why would I hamper that by spending time making code elegant that doesn’t need to be? There are even odds that this service won’t even exist in its current form in 6 months, let alone be around long enough for its elegance to be appreciated.
Microservices are a different paradigm for software development, in the same way agile was meant to be different than classic SDLC (Waterfall). The same thinking that built Monoliths can’t be used to build Microservices successfully. Next time you’re writing a microservice, think about what practices and inertia you have; and double check: Does this practice make sense in a Microservice? If it doesn’t, jettison it.