Beating the Drum on Packages and Models
Filed under: #daxmusings #bizapps
Even though I work on the product side these days and am crazy busy, I keep a close eye on the community out there. I have RSS feeds going for many blogs, I scan LinkedIn, I watch our insider Yammer groups, and I even follow an RSS feed of the official Community forum showing me all posts for AX/365 (yeah this is a lot but I scan through the titles quickly for specific things).
It’s clear to me more and more people are moving onto AX7.x and as partners and ISVs understand the new world of X++ v7.0 things run smoother, bug reports become more useful, etc. That said, there is obviously still an influx of new people (partners, ISVs and customers) who are just now starting to learn the new paradigms. So, it doesn’t hurt to go through some details again - this time I will focus on specific pain points I’ve seen people struggle with, especially when upgrading from AX2012.
#1 Rule of Thumb: A package is a mini-modelstore in and of itself, with its own set of layers and models! I can’t stress this enough. The standard application code is split up into multiple packages. If you’re upgrading your over-layering code which is neatly contained in 1 model - it will get split up all over the place. And it will be split into models in existing packages as it needs to over-layer something in that specific package. Currently the code upgrade will not create an entirely new package for you. Do not expect to see a package with your name on it, but rather expect a model in multiple packages with your name on it. If you have a 2012 model called “Joris” then you may end up with an “ApplicationSuite\Application Suite Joris” and a “GeneralLedger\General Ledger Joris” folder. You will NOT see a package “Joris” in the root. If you over-layer SalesTable - that over-layering can only be done in the package that contains SalesTable (Application Suite). (Note: you can EXTEND from any other package!) If you over-layer LedgerJournal - that over-layering can only be done in the package that contains LedgerJournal (GeneralLedger). Keep in mind over-layering of the standard code is completely disabled in application version 8.0 and upwards, so if you’re upgrading you may need to go to 7.3 first to “buy time” to move things to pure extensions.
#2 Without a successful compile of the FULL package, you have nothing When you get a new development VM, there’s an application suite (package) present, and it has been compiled (each package is a unit of compilation - i.e. it translates to an assembly DLL for that package). If I now add a new class to that package which has a compile error in it… 1) Build/rebuild from a project/solution is ALWAYS an incremental compile on the assembly. This means in the class with error example, the application suite will be there but my new class won’t, as the incremental compile wasn’t able to compile and add my new stuff. 2) Full build from the Dynamics 365 menu is ALWAYS a full assembly compile. This means in the class with error example, the DLL will be completely recompiled. Now, the Visual Studio tools keep a backup of the DLL and in case of error, put it back. So in this case essentially nothing will happen - the DLL will be the exact same as before the compile since the tooling will just put the backup copy back. 3) Be mindful of removing objects and understand that build/rebuild from a project is an incremental compile. When in doubt, do a full build of your package to ensure removed objects are gone and new objects are added! When you’ve moved your code in its own package by extending instead of over-layering in existing packages, these compiles won’t take long. If you’re still over-layering, compiling something like Application Suite will obviously take quite a bit longer.
#3 Packages consume each other using references, and these are references to the BINARY (compiled) package When Application Suite uses LedgerJournal, it can only do so because it has a reference to the GeneralLedger package where LedgerJournal is defined. But, this is a reference like any normal .NET reference. Let’s say I add a completely new package and call it CodeCrib. I add a new class called BlogPost. Now, this class shows in the AOT in Visual Studio. But if I try to use this class in some Application Suite over-layering, it gives me a red squiggly line and it won’t compile. So, I need to add a reference… From the Dynamics 365 > Model Management > Model Parameters screen, select your model in the drop-down and click Next to go to the references page, check the reference you need (to our CodeCrib package). This will add an official reference to the CodeCrib assembly (FYI this is stored in the descriptor of the package needing the reference). Now, adding the reference resolves the squiggly line in the editor. But it still DOESN’T COMPILE! What gives? Well, when you compile it’s all about the binaries! Since I haven’t compiled the CodeCrib package yet, the compiler can’t load the assembly when compiling AppSuite which references it! So when upgrading and you run a full compile, you’ll get LOADS of errors. But keep in mind that given #2 - a base package may not have compiled completely because of just 1 error. That could result in hundreds of errors in another package that depends on it! This is the way it works. Also note that these references have nothing to do with cross-references! Cross-references are used for the Visual Studio tooling, but the compiler NEVER USES cross-references for anything. In fact, it (optionally) creates the cross-reference, but it doesn’t consume it. So best tactic when upgrading is to review package dependencies, and just start with the small packages that have little or no dependencies. Get those to compile, then work your way up. Application Suite is usually the LAST package you want to fix - since it won’t compile anyway until you get its dependencies to compile properly. Once you have your own extension package, that one will likely become the last package to fix/compile, since it will depend on all the other packages it’s trying to extend.
#4 Extensions and references - one-way traffic The code upgrade does some work on moving obvious over-layers into extensions. This is ongoing work and as LCS updates and platform updates roll out, you may notice it doing more (you’ll be using code upgrade moving between minor application upgrades: 7.1, 7.2, 7.3 but not for just platform updates). Moving to extensions ultimately implies it should go into its own package. But moving something to an extension means you need a reference to use it, which may not be possible since references are one way. Let’s say we have a new field on table SalesTable. And we have some over-layering code in SalesTableType class that uses this field. Now, if we move our new field to a table extension of SalesTable and we put that extension in a new standalone package we created, then the over-layering in SalesTableType won’t find it. Now, to extend SalesTable in our package (let’s call the package CodeCrib), we have to reference AppSuite. For our over-layering in AppSuite to reference our table extension, we need a reference to package CodeCrib. Unfortunately that would create a circular reference which you can’t do. So there are two options: rework the over-layering in SalesTableType into extension as well (which ultimately you need to do), or keep the SalesTable extension in the AppSuite package for now, and move it later when you’re ready to refactor the other over-layering. For this reason the code upgrade, when it does create extensions, will put extensions in the original package where the over-layer existed - just so that you don’t have reference issues to worry about while upgrading. You can then move a whole bunch of objects in their own package when you’re ready.
#5 Conflict resolution The code upgrade creates a conflict project for overlayering code. Although this is handy, it’s important to remember that if you have code in MULTIPLE layers (let’s say, you have sys code over-layered in VAR, and that VAR over-layered in CUS), you want to fix each layer independently, and work your way up. As you rework a layer, you may move some code around. Note that doing that may cause NEW CONFLICTS in a higher layer. Because of this, I would encourage you to create your own conflict project for each layer once you’re done with a lower one to make sure no new objects have conflicts due to some refactoring you may have done in a lower layer. You can do this from the Dynamics 365 menu, under Add-Ins, Create project from conflicts. Bottom line: when refactoring code in a lower layer, YOU could be creating new conflicts in a higher layer. This is not a bad thing, just keep it in mind and make sure to check for any new conflicting objects when using customizations in multiple layers. Note that if an object was already in a conflict project, any new conflicts in the same object will just show up when you open the designer for that object. You’re more interested in new objects. The add-in for creating a project can also be useful when you’re done upgrading, just to go through each custom model to make sure nothing was left behind and you’re really done.
#5 Binaries versus code When you deploy a deployable package, it only contains binaries. There is no X++ code, only DLLs (and some other related artifacts needed). This means if you put a deployable package on a machine with Visual Studio, you will not see the code for the binaries you deployed. When you run the AOS of course you will run the binaries including your customizations. The larger issue I’ve seen is when you have overlayering code, let’s say on Application Suite. When you deploy a package, you would be replacing the application suite compiled code (binaries). But the code on the machine is still standard application suite, without your custom code. So, after deploying, the AOS is running fine with your code. However, if you now open Visual Studio and run a compile on application suite you are replacing the application suite binaries (i.e. replacing the binaries you deployed via the deployable package). Since you’re compiling the app suite without your custom code (since it wasn’t deployed there) you are ‘effectively’ removing your customizations.
For all the talk about layers here, keep in mind that the existing packages are sealed in application version 8.0 and above - meaning you won’t be allowed to over-layer any code in them and will be required to move to extensions. As such, when upgrading code you should consider the effort involved in upgrading all the code as-is, upgrading it by going through ALL the code (conflicting or not) and moving into extension. You still have the option to upgrade to 7.3 which has the application suite package still overlayerable (I just invented a new word).
And finally, if you’re new to Dynamics 365 but have 2012 experience, I encourage you to read my Design,Compile,Run blog post series. It’s hard to believe those articles are already more than 2 years old at this point…
There is no comment section here, but I would love to hear your thoughts! Get in touch!