Fifteen minutes reading time.
Once upon a time my ancestors roamed the icy plains of Northern Europe. They hunted behemoths, a single mammoth that could feed and clothe a tribe for a long while. But even though there was a lot of food on a single mammoth it was a bit of a pain to catch one. And once it is dead it is dead, and you need to eat it sharpish. So slowly they became smarter and started raising cows. Cows are standalone animals. Kill one, eat it, and the rest of the herd will continue to munch grass, produce milk, and be generally useful. So, we became cowboys. And survived.
Cool though the new job title of cowboy is it is nowhere near as cool as Slayer of Behemoths. That is why I offer a free Slayer of Behemoths t-shirt to the first 10 developers to successfully migrate a Dynamics NAV codebase to extensions. Details at the end of this post.
If you have been following me at all for the past months you will already know that at The Learning Network, we have been busy creating our first extensions. We have had our first extension in production since June and the grand total is now at eight, and several more in the works. It has not always gone easily though, but you probably read about that as well.
Now then why eight, and counting, extensions? Why not one big one? Why not wait and embed an ISV style extension in AL? Why even bother?
That is a lot of whys. We have been asking ourselves the same thing. Or not actually, we just enjoy building cool stuff and extensions are cool. Yes, they are. Period. So, we just started building. But just building cool stuff is not enough, it needs to be well engineered, well programmed, repeatable, reusable, testable, and maintainable. So, when we started planning the migration of one of our bigger business units to NAV2019 Business Central I set to work working out our design rules for building extensions. And since everyone is talking about migrating to extensions these days, I thought I would share them here.
Before I delve into the tech stuff some housekeeping. This list is by no means complete or accurate. It is a living guide. That means I will continue to update this post as I make lots of mistakes learn more. I you have tips or tricks please let me know.
1, Identify what to move into an extension by looking for the edge cases.
What is to be an extension? We don’t have time to redesign everything in one go. Therefore, we start looking for edge cases. An interface with our parcel delivery company. An interface with our order picking software. A redesign of our method of renting books that was happening anyway. Adding functionality to the job queue. Nothing that really touches on anything vital.
As we move the edge cases to extensions, we will find that the really complicated core modifications start to reveal themselves. There is simply less code for them to hide in. And when they do, we will have learned a ton about moving functionality to extensions.
2, Design to market
Working at an end user it is easy to create extensions for our own use only. But designing and building them for the marketplace will force us to not only design and build them better. Our extension will become a standalone microservice by default.
And because we build for the marketplace, we must do proper setup, testing, translation, and documentation. Remember, Microsoft does not require those things to annoy us. They require it to help us create the best extensions we can build.
3, Design all extensions as standalone microservices
This is the core of all our design principles. Moving to Business Central is just a small part of an overall redesign of our application landscape. For our landscape we decided on a system of standalone microservices connected using an events bus. So for Dynamics we also decided on a microservice extension architecture. Doing so enables us to create vertical and isolated extensions that interface neatly with our other microservices. That means a small multidisciplinary team can work on those isolated features as a single project.
In order to move our NAV2018 add-on to a microservice extension architecture we decided on a few ground rules.
- An extension is a standalone unit. Either a vertical unit that extends certain functionality or a horizontal unit that extends the technical working of the Business Central platform;
- All extensions will be built as an extension on the standard Dynamics NAV2018 codebase (our current version, to be upgraded to Business Central on premise soon). We do build new Business Central events into our NAV2018 codebase where needed;
- No extensions will have dependencies on other extensions except where we extend third party extensions. This is because it is harder to maintain an extension when it has dependencies all over the place, every time you upgrade an extension you need to rework all its dependents. Also it is harder to install updates;
- Extensions will be as small as possible but not smaller. There is no problem with a 500-object extension if that is the smallest it can be.
Using those rules, we end up with this model. It should be recognizable for those who attended Tech Days or Directions.
That is great, but it leaves two fundamental problems
- How to connect with the remaining custom C/AL objects;
- How to connect different extensions to each other.
We can solve these two problems in several ways.
An Interface Extension is a new extension that takes a dependency on the two separate extensions that it wants to connect. It is only used to connect extensions, no business logic will be in the interface extension.
An example of this would be an interface between our order import and our rental model. Both are vertical units but when importing an order with rented items on it the rental model business logic needs to do something.
To do this we use the events in the extensions we want to interface with. Because the interface extension is the one that is dependent our microservice extension remains a stand alone unit. That makes it much easier to maintain the entire application.
Interface extensions are also used to connect our new extensions with what remains of our old C/AL code. For smaller interfaces you might even use RecordRefs instead of dependencies.
You might want to check out James Pearson’s excellent 3 part series on integration.
Business Central has a workflow module that can be configured by the users. Our extensions will add their events and actions to the workflow module, so our application managers can configure the desired integration between extensions. More on this in this blog post.
ForNAV is the reporting tool we use to create output like invoices and packing slips, or management reports. ForNAV can use tables and fields from all extensions without having to create a dependency.
Web services and API
An extension can have its own Web service or API that other applications or other extensions can interface with without the need for dependencies. You might even subscribe to a Business Central API or web service in an Interface Extension.
Our model then looks something like this:
Some final remarks on microservice design.
- We will probably have blocks of code that will be cloned in several extensions. If this is something we absolutely want to avoid then this code should be moved to Azure functions or an API;
- We might end up duplicating data. That does not matter. A key feature of a microservice is that it keeps on working if all other applications fail. We don’t want our extension to stop working if someone deletes an extension that ours depends on for data;
- We will probably find there are others that have already created an extension that does what we need. We will use them, so we can focus on what we uniquely need. Don’t forget that we won’t have control over those extensions though. We use them as an API.
Some more information on microservice design:
4, Everything that can’t be done in an App Source extension gets moved out.
Do we just move everything we have to an extension? No, we don’t. I once said that we can do everything we should do with extensions. Or we will be able to in the very near future. But what is we should and should not do?
The three principles we use to decide if something stays in Business Central.
- We do not modify the standard code;
- We don’t use Business Central as a development platform;
- We don’t use Business Central for supporting functions like string manipulation.
The first principle means that we will lose some functionality. We still have modifications in standard code. They have got to go. Even though we request events where Microsoft has not added them already we will have to live with some loss of functionality. If we cannot live with this then Business Central is not the right platform for us.
There is of course a caveat here. Microsoft is still refactoring the core application to make it easier for us to extend it. But we don’t wait until Microsoft is done with this. We move what we can into microservice extensions. When Microsoft is ready we can move the rest.
If we must have data or even the UI of our web-based application available in Business Central, we bring functions from multiple applications together in a single interface in Business Central using control add ins and React (or Angular, or jQuery, etc). More on this in a future blog post.
The third principle means that we will do away with the tons of supporting functions we have in codeunits. We use Azure functions or APIs to do our string functions, date manipulation, e-mail sending, weird calculations, or whatever.
Case in point, we just found a function in one of our codeunits to check if an e-mail address is valid. That is something we want to use consistently in all our web shops, ERP systems, and other applications. We will stick it in an API. One less function to migrate to AL.
5, Design as an API
Our extension is someone else’s API. Someone somewhere will extend our extension. Someone will create an interface for it. They don’t want to redo their work every time we release an update. That is a sure way of building an unpopular extension no one will use. Some tips.
- Use proper API design guides. See this post for details on this;
- Be generous with events that others can subscribe to. Add events where needed. Check how Microsoft does that using their AL GitHub. They are doing it right;
- Add web services and APIs for our extensions. Create many ways that others can interface with.
I hope I gave you some ideas on how we work with extensions. I’m sure there are many other ways to deal with the move to extensions. This one just happens to work for us. I am always open for feedback, let me know what you agree or disagree with.
Finally, to win your Slayer of Behemoths t-shirt all you need to do is share this post and send me evidence of that plus evidence of taking a number of microservice style extensions into production. All judging is done by myself and will be final. MVP’s and Microsoft employees are excluded from participation.