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.
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 in…Set 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