Tuesday, May 3, 2016

Design-Compile-Run Part2: Design, Compile, Run in AX 2012

In Part 2 of this design, compile, run series we'll look what design, compile, run actually means in AX 2012.
If you haven't read Part 1 about the paradigms in AX 2012, please do.

We've looked at layers and models in Part 1 of this blog post series. In versions prior to AX 2012, these layers were stored in a physical file (AOD file) - each layer had one file on disk. In AX 2012, this changed into a Model Store database - containing all the layer and model's code, metadata as well as all compiled p-code and generated CIL binaries. Let's look at what these concepts really mean and represent.

First consider the metadata and code. When we say metadata we are talking about the form definitions, table details like relationships, indexes, schema representation etc. They are not "code" per se but represent an artifact in a meaningful way that is needed during development and parts of running the application, and some of it is used by the compiler as well.
The second thing the model store contains is the p-code and generated CIL. This is the binary form of the compiled code and metadata that is used to actually run the application. X++ originally (in AX2012 and before) is an interpreted language, and the p-code represents an easy way to run the code. The advantage of this is that parts of the code can be adjusted and only those parts have to be recompiled for the runtime to work. The disadvantage is that errors can easily occur at runtime when individual parts are changed without recompiling everything else in the system that may have a dependency on it. Additionally, since it's p-code that is executed by an interpreter at runtime, the performance of the execution can't match that of a properly compiled binary.
The introduction of CIL in AX2012 changed this story slightly. After the p-code is compiled, an extra process needs to be run that will translate the p-code into .NET assemblies. This step may fail if, as explained before, the application has errors due to individual parts having been changed without recompiling and resolving all consequential errors. The advantage is of course that X++ code can be run inside the .NET CLR. The disadvantage is it conflicts with the traditional change&save model of X++ since this can cause issues. Additionally, if CIL generation runs into errors the application is potentially in an unknown state. It is entirely possible to have the CIL assemblies be in an "old" state (since new compile failed) while the X++ p-code has the latest changes. Essentially that means you could be executing different versions of the code whether you are running X++ interpreted or in the CLR if your development and deployment processes aren't solid.

Since traditional development for Dynamics AX occurs inside the AX client, the underlying structure and process is not very visible, which could lead to broken deployment processes. It's important to understand these details to have a solid AX 2012 development and deployment process. It will also make the AX7 processes clearer. Based on the above information, let's make the following three buckets: design-time, compile-time and run-time. Within the model store, there are both design-time artifacts and run-time artifacts. Note that the run-time does NOT have models or layers.

Why? Well, at the time of compilation the compiler will take the top-most version of each object artifact (think "granularity" as explained in part 1) and compile that into binary p-code (which then is used to generate CIL). That makes sense: first, you can only execute one version of the code so why have binary versions of each layer or model? Second, one piece of code may reference another piece of code - and each may exist in different layers, so the compiler needs to make a decision on what code to compile against. So all in all, the compiler will "flatten" all the code and metadata into one version of the truth, and convert that into binaries.

Now that we understand the underlying distinction between design, compile and run-time and what artifacts each contains, let's review what tools are used for each.

I realize this is a simplification, there are other runtimes like BC.net and SharePoint Enterprise Portal, but in general times this a good representation for the sake of this discussion.
- The AX32 client is the most comprehensive. It contains design-time tools, compile tools and an X++ interpreter to run the p-code. Note that it doesn't have the .NET CLR so it cannot run the X++ CIL.
- The AX32Server AOS is mostly a run-time which can run both the X++ interpreter for p-code as well as the .NET CLR to run X++ CIL. Note that in theory this has a server-side compiler in it that is used by the AxBuild process but one would never explicitly use it.
- The AxBuild process was introduced in AX 2012 R2 CU7 and is available ever since. It's strictly to compile, and although it technically starts the AX32Serv executable to compile, we'll consider this the compiler.
- I also included Visual Studio as a design-time tool, although from an X++ point of view there isn't much functionality and its mostly used for reports or non-X++ code (C# etc).

Finally, although all of this is stored in the model store, there are different file representations of different artifacts. These are file formats and vehicles to transport these artifacts (i.e. deployment artifacts).

First is the traditional XPO file. It's essentially the closest to a "code file" you can get with X++, it represents an object and its metadata and source code. Although one could have an XPO containing all customizations to an environment, it's no longer recommended as a vehicle of deployment but treated for what it should be: a code file. Meaning it's good to share bits and pieces of code among developers, as well as source controlling code artifacts.
Next is the AxModel file. This is essentially a collection of source code, typically representing a full solution of a responsible party. For example an AX customer's custom code, an ISV's product, a VAR's add-on, etc. Note from the diagram you see the AxModel file, although a binary format (actually it's a .NET assembly), is still just code and metadata. This means just like the XPO, installing it on an environment only gives you the code and you should still compile everything.
Finally the model store, which contains all code, metadata, p-code and CIL can be exported as an AxModelStore file, or a SQL backup can be taken to move it. Since this contains everything, there is no need to recompile anything when moved. The model store file or model store database backup is the closest we get in Dynamics AX to moving a compiled binary.
As I keep reminding people I meet that have questions around all of this, I like the analogy of a program or windows update. When there is an update, does the software vendor send you some C++ files (i.e. XPO)? Or is it more a Linux-like source code package that can be compiled (i.e. axmodel)? Or do they send you a new version of the DLL (i.e. model store)?

Next part, we'll transition into AX7 based on what we reviewed in this article.


  1. Thanks Joris, looking for the next part...

  2. Always a good read. Great series so far

  3. This is a great overview and a way to explain concepts. Invaluable for instilling a disciplined build process. Can't stress that enough : )