So one of the most common elements I see come up as your build out a micro-service architecture, is that there is a fair bit of code-reuse when you do that. And managing that code can be painful, and cause its own configuration drift, that can cause management issues.
Now given the above statement, the first response is probably “But if each Micro-service is an independent unit, and meant to be self-contained, how can their be code re-use?” And my response to that, is that just because ultimately the services and independently deployable does not mean that there isn’t code that will be reused between the different services.
For example, if you are building an OrderProcessingService, that might interface with classes that support things like:
- Reading from a queue
- Pushing to a queue
- Error Handling
And these elements, should not be wildly different from each micro-service, and should have some common elements. For example, if you are leveraging KeyVault for your configuration, odds are you will have the same classes implemented across every possible service.
But this in itself creates its own challenges, and those challenges include but are not limited to:
- Library Version Management: If each service is its own deployable unit, then as you make changes to common libraries you want to be able to manage versions on going.
- Creating a central library for developers: Allowing developers to manage the deployment and changes to versions of that code in a centralized way is equally important.
- Reduce Code Duplication: Personally I have a pathological hatred of code duplication. I’m off the belief that if you are copying and pasting code, you did something wrong. There are plenty of tools to handle this type of situation without doing copy and paste and adding to technical debt.
Now everyone is aware of NuGet, and I would say it would be pretty hard to do software development without it right now. But what you may not know is that Azure DevOps makes it easy to create a private NuGet feed, and then enable the packaging of NuGet packages and publishing via CI/CD.
The process of creating a feed is actually pretty straight forward, it involves going to a section in Azure DevOps called “Artifacts”.
And then select the “Create Feed”, and give the feed a name, and specify who has rights to use this feed:
And from here its pretty easy to setup the publishing of a project as a NuGet package.
A few years ago, this was actually a really painful process, but now its pretty easy. You actually don’t have to do anything in Visual Studio to support this. There are options, but to me, a NuGet package is a deployment activity, so I personally believe it should be handled in the Pipeline.
So the first thing, is you need to specify the details on the configuration. If you go to “Properties” on the project:
These are important as this is the information your developers will see in their NuGet feed.
From here the next step is to configure your pipeline to enable the CI/CD. The good news is this is very easy using the following pieces:
- task: DotNetCoreCLI@2 inputs: command: pack versioningScheme: byEnvVar versionEnvVar: BUILD\_BUILDNUMBER displayName: 'dotnet pack $(buildConfiguration)'- task: NuGetAuthenticate@0 displayName: 'NuGet Authenticate'- task: NuGetCommand@2 inputs: command: push publishVstsFeed: 'Workshop/WellDocumentedNerd' allowPackageConflicts: true displayName: 'NuGet push'
Now using the above, I have specified the BUILD_BUILDNUMBER as the identifier for new versions. I do this because I find its easier to ensure that the versions are maintained properly in the NuGet feed.
One thing of note, is that NuGet Authenticate step is absolutely essential to ensure that you are logged in with the appropriate context.
Now after executing that pipeline, I would get the following in my NuGet Feed.
Now, how do we make this available to our developers, and to our build agents. This process is very easy. If you go back to the “Artifacts” section, you will see the following:
The best part is that Azure DevOps will give you the ability to pull the XML required when you select “dotnet”, and it will look something like this:
<?xml version="1.0" encoding="utf-8"?><configuration> <packageSources> <clear /> <add key="WellDocumentedNerd" value="....index.json" /> </packageSources></configuration>
After this is done, and added to your project, whenever you build pipeline attempts to do a build of your code project it will consider this new data source in the NuGet Restore.
As I mentioned above, ultimately one of the biggest headaches of a micro-service architecture for all of its benefits, is that it creates a lot of moving parts. And ultimately managing any common code, could make things difficult if you have to replicate code between projects.
So this creates a nice easy solution that allows you to manage a separate code repository with private / domain specific class libraries, and still have versioning to allow for having different versions on each service while enabling them to be independently deployable.