One of the common recommendations from both Microsoft and all the experts in our community is to create smaller modular extensions designed with either a single purpose or with a single functional area. Within software development this is often called Modular Development/Architecture.
This has several advantages, compared to create large (monolithic) extensions. The smaller the extension (the module) is the more likely it is that we can the sell the same extension to multiple customers. It also makes maintenance and extendibility easier. At least in theory, as it does have a lot of potential issues.
If the extension has no dependency, then you are safe to assume that it will not break due to upgrades by Microsoft. But if it didn't have extend any existing functionality in Business Central, then we didn't really need to develop as an Extension in the first place. That means that all extensions can theoretically break when Microsoft releases the next major update.
With each additional dependency to existing functionality in Business Central, then this risk that your extension may break goes up. And the risk continues to go up when we start to extend our own extensions. Or when we start to use our extension in different contexts, with different parallel installed extension.
The break may happen in two ways. If some of our integration points to other functionality is no longer present, has been renamed or changed, then your extension could fail when compiling it against the new version. That is the best case. It would be worse if it didn't fail, but that the functionality in our extension would have functional conflicts with the new version.
And that goes for all integration points, no matter if that is to standard Business Central code or to other extensions, no matter if developed by us or another Microsoft partner/ISV.
There are a many design patterns, that we can use when we develop the extension, which can help us to lower the risk in certain areas. But no matter how smart we are, then we can not eliminate it this way.
Even building large automated tests suites would not be able to eliminate it completely. But it can get us very close. If we are developing the extension for AppSource, then this is already a requirement from Microsoft. I would go one step further and recommend that every extension, no matter if for one customer or many, then we should always have covering test codeunits for it.
Anything we write in Visual Studio Code with AL, may potentially break. And that doesn't really matter this AL code is in a test codeunit inside the same extension or in a dedicated test extension. If it is code then it can break, and the more code we have, the higher the risk is that it will break.
A test codeunit as any other code may fail both when compiling it and when running. And in the same way as other code, then it needs maintenance.
No matter how we look at it, then having test codeunits makes the total cost risk of our entire solution higher. The more code the higher the risk.
If we want to have high quality Business Central extensions, which we safely can reuse and sell to multiple customers, then this is one of the things we must accept. And remember that the cleaner your code is, the easier (read less risk of breaking anything) future updates will be.
The next issues with having an extension with dependency to the main extension is specific to Business Central and the way Visual Studio and the AL compiler works.
Whenever we have a dependency in an extension to another extension or the standard BC functionality for that matter, then we need to download the symbols for this extension. These symbols are saves as .App files in the .alpackages folder in VSCode.
The result is that each time we change functionality in the main app and want to check that our dependent app still works, then we must first re-download the .app file for the main app.
And that's not really the worst part. That is the fact that we currently need to unpublish and uninstall all dependent extensions, before we can publish the main app again.
Even if not practical, then this may work in a situation where you are able to "freeze" the main app, before working on the dependent app.
If we want to separate our test codeunits into a separate extension, which is a requirement for AppSource extensions, then it makes it, if not impossible, then very difficult and impractical to do any kind of Test Driven Development with Business Central.
The TDD process is first to write the test, see the test fails, write just enough code to make the test pass, then refactor and write the next test. This process is also known as the "Red – Green – Refactor" mantra that we want to repeat again and again.
For this to be possible the individual steps need to be possible in seconds. It should not be something we measure in minutes!
The only practical way I have found is to have the test codeunits in the same extension. This way we can almost eliminate the issue of having to unpublish and republish the test app all the time. It also makes IntelliSense work (without the having to download the symbol file) and allows a full compilation across the "two" extensions.
This can work in the development phase, but generally we do not want to have test codeunits in a production database, so we would have the split it in two when we do the deployment build.
While the above "work around" can be used, then it's not really a good solution. It should be possible to do without having to hack the system.
Ideally if we had two (or more) dependent extensions inside the same workspace in Visual Studio Code, then the AL compiler shouldn't have the depend on the .App symbol files. It should be able to use the actual source files. Technically this should be possible, as all information is already present inside VSCode.
The same goes when it comes the process of having to unpublishing and republishing of dependent extensions. The user story for doing this, especially from VSCode, needs to be improved.
My personal fear is that many partners/developers would end by stuffing too much functionality into one extension, instead of splitting it up. Simply because working with multiple extensions is too time consuming.
If I were Microsoft, then I would do anything I could to improve working with multiple extensions. And I would do it fast, before most BC developers find out how difficult it currently is. An old say is that it you need ten good experiences to make up for one bad. I'm sure when Microsoft starts to split up the current C/Side core app into separate extensions, then we are going to see a lot of breaking extensions. Just as we saw when codeunit 1 was removed and refactored in other codeunits etc. And while most of them may not require too much time to fix, then they are all count as bad extension experiences.
And if it could make Test Driven Development possible, without having to find complex work arounds, would also be a great win.
If you agree, that it is important to improve the way we work more efficient with dependent extensions in Business Central, then please go to Microsoft's Business Central Idea site and give my two suggestions a vote up:
Enable compile/IntelliSense for apps within same workspace
Automatic unpublish and publish from VSCode
Great post, Erik.
However I don't think it's true that "No matter how we look at it, then having test codeunits makes the total cost of our entire solution higher": Yep, as we haven't been used to making this part of our work this will be extra cost. But IMHO I think an average NAV project (and probably product too) goes 25% over budget due to after go-live bug fixing (and according to many this is on the low side). WHo's paying for that? Often it's the implementation partner itself. So just make sure to spend this (non-budgeted) cost upfront.
Next to that, very probable it is that getting automated test embedded in your development practice will improve code substantially and code creation more efficient.
Thanks Luc,Well I am a little ambivalent with this. The more code, the more code to maintain (both test and main), the higher the cost. While at the fact that we have tests (assuming a good covering test suite), then that will lower the risk, by being able to alarm us if there are any failing tests and makes any future maintenance faster as wall (compared to a system which has not been refactored for testing) . But when we then add the fact that we (almost) risk free can reuse the same extensions with other customers, then that potential extra cost would not matter.If we have old upgraded code, where we first need to refactor everything to make it testable, then it is going to be very costly to make a good test suite.But it depends how we are doing it, if we code the way we have always done it with code first, then it will absolutely be more expensive. If we change the way we are coding, and starts with the tests (TDD), then I think that you are right. I will try to be a bit more concise in the test.