Friday, February 26, 2016

Dynamics AX 7 Codebase Architecture

It is probably the toughest topic for developers to grasp and get used to and the most cardinal change for internal code architecture. The idea as I see it is to make the huge standard codebase modular and loosely coupled and promote AX architects and developers to do the same with their code.

Packages, models and dependencies

In AX 2012 and before the whole application code existed within one namespace split by layers and models. You could call or reference any code in your Dynamics AX instance from any other place. We all know the upsides and downsides of this approach.
Easy to develop and modify, tough to upgrade and maintain. After years of typical, average-quality maintenance your codebase evolves into a clew of spaghetti code with continuously increasing entropy and TCO. That may eventually lead to “upgrade / re-implement / switch to another platform” decision. Let alone the painful upgrades throughout the system lifecycle.
In Dynamics AX 7 the standard codebase is split into a graph of separate packages with one-way dependencies among them. Model can only belong to a single package.

Code in package B can call (reference, extend, instantiate, subscribe to etc.) code from the same package or package A only of it has a dependency B –> A (B depends on A). Circular dependencies are not allowed or at least not recommended. Dependency is not transitive (A –> B, B –> C does not mean that A ­–> C). You will get a compilation error when trying to use an object from not references package.

The standard code is split into tens of packages, the most important among them are:
-          Application platform – pure system code needed for AX to start.
-          Application foundation – code shared by different modules like number sequences, data management, emailing etc.
-          Application suite – the main AX business logic (AR, AP, Ledger etc.)
-          Self-descriptive packages like Dimensions, Directory (GAB), Calendar, Currency and so on.
Needless to say that you should follow the same pattern when designing the internal architecture of your application. Take your time and imagine the consequences to the architecture of your solution.


Source code

Source code is stored in a hierarchical folder structure on disk of development box (e.g. C:\Packages) and / or in in VCS. Text Descriptor file contains metadata and the list of referenced packages. Objects are mainly stored as XML files.


Extensions and event-driven architecture

There is a new modification approach and a number of AOT nodes named “Extensions”. Extension is an object that lives within the same package or in a dependent package, and is incorporated into the object it extends by the Runtime.
For example, if you need to add a field to a table, a control or datasource to a form, you may create an extension without changing the initial object, and runtime with show a complete form with all its extensions.

Cool isn’t it? But what if you need to change behavior? Some eventing capabilities existed in AX 2012 but anyway you had to modify the initial object anyway in order to subscribe an event handler to its event.
In AX7, you may subscribe to pre-, post- events, system-predefined object events or developer-defined class delegates in declarative way, without changing the source object. Just decorate an event handler method with attributes defining the event. Event handler must be in the same or in a referenced package. And that is quite impressive, I need to say.


The downsides of such approach are also known:
  • Poor code readability - you never know what is executed before or after your code. If you finish your method with “return 1;” it does not mean it will return one. There may be an unlimited number of post-handlers willing to override your and each other’s return values with unpredictable result.
  • Not guaranteed sequenced of handler's’ execution.
  • Cumbersome way of parsing and casting formal parameters and returning result at runtime. You have to use special vehicles to pass and receive them. And error-prone, too.
  • Does not support all scenarios. You cannot not intrude into an arbitrary place of a method if there is no delegate.

Microsoft promises to increase the number of extension types and events so they can support most of the typical modifications. The currently supported may be found here:
There is another interesting patter of non-intrusive modifications though Plug-ins that did actually existed in AX 2012 R3. In few words, It is an attribute- and data-driven replacement for switch-based class-factory construct pattern that you had to modify to incorporate a new class in a hierarchy. The support in standard code is quite limited though.


Making your code extensible

The flip side of this architecture is that in order to make your code extensible you have to use special patterns, like using inSet instead is switch...case etc., specifically insert delegates into extensions points of your code. And that is definitely good as the more you think about your code architecture the longer and healthier your application will live.


Marketing view

Besides reduced maintenance and upgrade cost there is a marketing view on this: Plug-and-play approach to installation of third-party solutions. Just download it in a form of DLL(s) and that will plug into your codebase without tedious code merge etc. Ideally it should peacefully co-exist with other solutions you have. 


Overlayering

Old good overlayering still exists, but in fact may be done only within one package and may eventually be abolished by Microsoft, meaning that once you’ll get a set of standard objects and events that you can extend or hook up to but never change or even see the source code.
That in fact means that layers only matter within one package. Let’s say you’re developing you own Fleet management application that overlayers and uses some standard code and also introduces new objects. Fleet booking in its turn is a customer-developed add-on to Fleet management. In AX 2012 you would create new models at proper layers.
In AX 7 you’ll probably face a tough choice. The recommended, way of development is to create your own package and not to modify any standard code but only extend and subscribe to its events. However, because the present extension mechanisms do not cover 100% of your modification scenarios you’ll probably have to have an overlayering part (e.g. in Application suite). And this overlayering part won’t be able to use any code from your main model, because the reference is already set in opposite direction (your package –> Appl. suite). Say, you cannot modify a lookup on SalesTable form and call your class from there.
One of possible solutions is to overlayer the standard objects, but keep the footprint of your changes as small as possible through e.g. declaring a delegate in the overlayered code.
Imagine you develop a Fleet management application in a separate package and you have to modify Application suite and Ledger logic but extensions do not support your scenarios. If you want to reuse e.g. an EDT like FMCustTable in all modifications, the structure of your application will have to evolve as follows:

Meaning you’ll have to spin-off some common code into a separate package for common use.


Deployment

The development side of the packaged architecture describe above is naturally reflected in changes to deployment techniques.  There is no more source code in Production, only binary NuGet packages familiar to .NET developers. You create a deployment package in Visual Studio out of one or more source packages. The biggest collision so far is with overlayering. If you overlayer at list a single line in e.g. Application suite you’ll have to deliver the whole NuGet package and thus overwrite all changes at the target environment. The only known way to resolve this is to merge the source of the conflicting application which kills the idea of binary deployment.

No comments:

Post a Comment