mfp's two cents

...on Dynamics AX Development!
  • mfp's two cents

    It has landed!

    • 5 Comments

    Just now I've held my first sample of the Inside Dynamics AX 4.0 book in my own hands. Before the proud owner walked away with it again, I had a chance to photo the beauty!

    If you want a copy for yourself, it is now available on Amazon.

    If you already own a copy, make sure to review it on Amazon. I'm eager to hear what you think!

     

     

     

  • mfp's two cents

    SysExtension Framework – to the rescue

    • 5 Comments

    There is a coding pattern that has been proliferating the X++ code base for years. It is not an X++ best practices – nor is it object oriented; yet it is used quite heavily (unfortunately). Consider a simple class hierarchy with an abstract base class and 3 derived classes. A typical implementation of a factory would be a static method on the base class, like this: (Please ignore the type of the parameter – it could  be anything, I choose str for simplicity)

    image

    Now; the problems with this approach are many.

    • First of all the base class has references to the sub classes. Why is that a problem? Consider the base class is a framework class – is it a good idea for framework classes to have references to consumer classes of the framework? Of course not – we don’t like that coupling.
    • Secondarily; the 3 subclasses are all referenced by the same method. Any new sub class would require an update to the factory. This turns the method into a congestion point, and it creates a coupling between sub-classes.

    The coupling between the 4 classes spells trouble. If you try to modularize an application written like this, you will quickly realize that the pattern above is bad. You cannot have references from lower-level models (aka. assemblies/modules) to higher-level models. Yet; having a single factory method is valuable and a good practice.

    SysExtension Framework to the rescue.

    Consider you decorate the subclasses with an attribute, like depicted here:

    image

    Then you can rewrite the factory method to this:

    image

    The extension framework returns an instance of the right subclass automatically. It uses the attribute to determine which subclass instance to create. Quite simple – extraordinary powerful!

    Now notice:

    • Truly decoupled! New subclasses can be added without any changes to the base class.
    • Less code is required! In the example here the delta is not significant – but sometimes you have switch statements spanning hundreds of lines.
    • No change in the public API! The contract stays the same – this is an easy and low risk refactoring.

    A few words of caution: There is a small performance impact on cold systems when using the SysExtension framework. In most cases you will not notice it; however – for performance critical paths, you should measure the impact of this change before going for it.

    To learn more about the SysExtension framework see here.

  • mfp's two cents

    Garbage Collection and RPC calls in X++

    • 5 Comments

    Dynamics AX is a 3-tier application that evolved from a 2-tier application.  Yes, this is right, the first versions of Axapta was solely a client side application communicating with the database. In version 2.0 the middle tier was introduced. The X++ language got a few new keywords, client and server, and the AX run-time provided the smartest marshaling of objects across the tiers on the planet. The marshaling is guaranteed to work in virtually any object graph you can instantiate. You can have client-side classes holding references to instances of server-side classes, which contains references back to other client-side objects, which references … you get the idea. All you have to do as a developer is to decorate your classes as client, server or called-from.

    You don’t have to worry about any low level details like how the instances are communicating across the wire. The key word in the previous sentence is “have” – stuff will just work, but unless you are very careful you may end up creating an extremely chatty (i.e. lot of RPC calls on the wire) implementation.  Recently I’ve seen two cases of well-intended changes that on the surface looked right, but both caused an explosion of RPC calls. Both were implemented by smart guys, and I wanted to point them to an article explaining the problem – and I realized that article didn’t exist. Until now.

    Garbage collection in AX

    The garbage collector (GC) AX is responsible for releasing memory consumed by object instances no longer in use. In .NET the GC is indeterministic, it runs when it “feels like” running, typically when the system has CPU capacity and is low on memory.   In contrast the GC in AX is deterministic – it runs every time an object goes out of scope.

    Consider this small example:

    static void GCJob1(Args _args)
    {
        MyServerClass myServerClass;
        //Create instance
        myServerClass = new MyServerClass();
        //Release instance
    }

    image

    Jobs run on the client tier, so this will create an instance of the MyServerClass and release it again. MyServerClass is a trivial class with RunOn=Server.

    If we enable Client/Server trace under Tools | Options | Development, and run the job, we get:

    Create instance
    Call Server: object: MyServerClass.new()
    Release instance
    Call Server: destruct class


    Notice this: The client-tier reference to the server instance, is keeping the instance alive. When the reference goes out-of-scope, then the GC takes over and calls the server to free the server memory.

    Island detection

    The GC is not just looking for instances without references – often object graphs are more complicated. To release memory that is no longer needed, the GC is looking for groups of objects without any external references – or in popular lingo: Islands. This search is potentially harmful to the performance of your application. The GC must traverse all members of any object that goes out of scope – regardless of their tier.

    Let’s build out the example by introducing a client side class that is referenced by the server instance.

    static void GCJob2(Args _args)
    {
        MyServerClass myServerClass;
        MyClientClass myClientClass;
        //Create client instance
        myClientClass = new MyClientClass();
        //Create server instance
        myServerClass = new MyServerClass();
        //Make server instance reference client instance
        myServerClass.parmMyClientClass(myClientClass);
        //Release instances
    }

    image
    Now; when myServerClass goes out-of-scope then the GC will start analyzing the object graph, and it will discover an island consisting of our two objects – despite they are on different tiers, and it will release the memory consumed.
    image

    Pretty smart – but not for free!

     

    This is the resulting RPC traffic from the above job:

    Create client instance
    Create server instance
    Call Server: object: MyServerClass.new()
    Make server instance reference client instance
    Call Server: object: MyServerClass.parmMyClientClass()
    Call Client: set class loop dependencies
    Call Client: test class loop dependencies
         
    Release instances
    Call Server: destruct class
    Call Client: destruct class

    Now suddenly we jumped from 2 RPC calls to 6! What happened? We met the GC! 

    • The first 2 calls are expected, they are a direct consequence of the methods invoked on the server tier.
    • The next 2 calls are set/test class loop dependencies. Both of these are consequences of the parm method. The set call is a result of the assignment inside the parm method. It tells the client that the server now holds a reference to the client side object. The test call is the GC looking for islands, but not finding any. When the parameter (containing the client-side object) goes out-of-scope at the end of the parm method, then GC looks for islands. As the server side class holds a client side member, then the traversal of the object graph requires a trip to the client.  
    • The last 2 calls are cleaning up. Notice that destruction is a chain reaction. First the server is called to destruct the server side object, then the server calls back to the client to destruct the client-side object.

     

    A real life example

    Consider a server side class that is looping over some data, and for each, say, row, it spins up another class instance on the server to do some calculations.  This is all server side, and perfect. So let’s add a client-side member to the mix.

    class MyServerClass
    {
          MyClientClass myClientClass;

          public void run()
          {
              int i;
              MyServerHelper myServerHelper;
              //Create client-side member
              myClientClass = new MyClientClass();

              //Loop over some data
              for (i=1; i<=10; i++)
              {
                  myServerHelper = new MyServerHelper();
                  myServerHelper.parmMyServerClass(this);
                  myServerHelper.calc();
              }
          }
      }

    image

    The alarming result is 10 client calls – or one per iteration in the loop – despite the loop only contains server side logic.

    Create client-side member
    Call Client: object: MyClientClass.new()
    Call Client: set class loop dependencies
    Loop over some data
    Call Client: set class loop dependencies
    Call Client: set class loop dependencies
    Call Client: set class loop dependencies
    Call Client: set class loop dependencies
    Call Client: set class loop dependencies
    Call Client: set class loop dependencies
    Call Client: set class loop dependencies
    Call Client: set class loop dependencies
    Call Client: set class loop dependencies
    Call Client: set class loop dependencies

    The assignment inside the parm method forces the AX runtime to traverse the object graph, and the object graph contains a client side instance.

    The alert reader would have recognized this as the Runbase pattern. The client side class is the operation progress bar. In Dynamics AX 2009 the operation progress bar framework regressed, as a client side reference was introduced - exposing all thousands of consumers to this specific problem. This got fixed in Dynamics AX 2012 R3.

    Symmetrical implementation

    The implementation of the GC and the supporting runtime is symmetrical on each tier – you can recognize them in action, when you come across these calls in the Trace Parser. Remember; they are always a consequence of the exercised X++ logic. I.e. something that can be addressed if required.

    Call Client: set class loop dependencies
    Call Client: test class loop dependencies
    Call Client: destruct class

    Call Server: set class loop dependencies
    Call Server: test class loop dependencies
    Call Server: destruct class

     

    Wrapping up

    There is only one way of understanding the impact the GC has on your implementation: Measure it!   The best tool for measurement is the Trace Parser. Alternatively, the Client/Server trace in Tools | Options | Development can be used – it will show all the RPC calls in the Message Window.

    The rule-of-thumb as a developer is to avoid class members that are living on the opposite tier. This will ensure your object graphs are single tiered, and it will make the life of the runtime and the GC much simpler, and your applications equally faster.

    There are situations where cross tier members seem unavoidable. However, there are techniques to avoid them, and achieve the same functional results. Take a look in the SysOperationProgress class in AX4 or AX 2012 R3 for an example.

     

    Code samples are attached. They are provided AS-IS and confers no rights.

  • mfp's two cents

    Inside Microsoft Dynamics AX 2012 @ the printer

    • 4 Comments

    The book is now being printed.

    Read more here:

    http://blogs.msdn.com/b/microsoft_press/archive/2012/10/10/rtm-d-today-inside-microsoft-dynamics-ax-2012.aspx

  • mfp's two cents

    10 reasons I love my Microsoft Surface

    • 4 Comments

    First things first – I work for Microsoft, and I will not claim to be unbiased. Yet, I bought my Surface out of my own pocket in a regular Microsoft Store – I was even in line for 3 hours to get it. Just like everyone else could.   

    Secondly, I primarily blog about AX – this is an exception, you don’t have to read it if you don’t want to.

    With the formalities out of the way, let me begin. I’ve had the device for about 1 year now. I wanted to use it primarily for entertainment – I did not go for any of the keyboard options. Let me share my experiences. 

    1. It is sturdy

    The Surface had not been in our home more than a few days when my 4 year old kid came running with it. He tripped over a toy, and the device came flying through the air towards our massive oak table. I’ve hit my toes many times on the table – always with the same result: Pain and Agony in well sized portions. Hearing the thud as the Surface collided with the table I closed my eyes. Game over. My kid was already crying. Bracing my self to clean up and comfort my kid – it was just a piece of hardware after all – I inspected the damages. The Surface was intact. I couldn’t even find the place where it had hit the table. It still worked flawlessly. The table – on the other hand – had lost a small chip of wood.  The small disaster turned into a simple “Ooops – up again!” situation.

    2. The kick stand

    First time I brought the Surface to some friends’ place, they said: “That is cool – how did you get that on your iPad?” I just smiled back.

    The kick-stand is amazingly pleasant as it allows for a much more convenient usage.

    3. User accounts and Picture login

    We have 3 users of the Surface. My now 8 year old girl and my now 5 year old boy – and myself. We each have an account, we each have our own apps, games and settings. I started out by just setting up one account, but quickly we ended up in situations where little-brother deleted (or moved) the games his sister liked. With 3 accounts that stopped right there.

    My 4 year old quickly learned how to login – just press your eyes and your nose. Had the system required a keyboard+password login it would have been usable for him.

    4. Family safety

    Both my kids accounts are monitored by the built in family safety feature in Windows 8. This means I get a weekly report showing how much they used the device and for what purposes.  And even better, the data is aggregated across all our Microsoft devices, so it also includes X-Box, the wall-mounted touch-all-in-one PC we have in the kitchen, and the regular workstation.   Here is a picture of some of the info the weekly report contains:
    image

    The system is highly configurable – you can enforce time limits, ratings etc – you can even excluded some apps (like those used for homework) to count against the time limit.  As a parent I feel in control – without feeling I’m spying (too much)

    5. The modern UI.

    I simply adore the UI – the amount of energy that has been put into the aesthetic look of Windows 8 leaves me humbled. The result leaves me with a feeling of being spoiled. If you haven’t read the story behind the design – you should do so. The competition is ages behind.

    Every time I visit Bellevue Square Mall I visit the Mac store – just to see what is brewing. Since Windows 8 came out I’ve not been able to find anything that awakes the even smallest desire in me in Mac land.

    I find the same experience elsewhere too: In my pocket (Windows 8 phone), at work (Windows Server 2012), at my Laptop (Windows 8.1) and my X-Box (360 – soon to be One).

    The tiles are extremely powerful. They give me information at a glance - I don’t waste my time opening apps to check empty in-boxes.. The Data Sense App (on my phone) tells me my current network usage, the Stock portfolio App tells me how Wall-Street is doing, the weather app tells me the weather, the People app tells me if I have new messages aggregated across social networks, like Facebook, Linked-in. Without even opening a single app I get all this info. That is sheer power!

    6. USB

    The Surface has a USB port. This enables me to attach my Kindle to upload documents and charge. This enables me to attach a mouse and keyboard. This enables me to attach a printer. This enables me to attached a USB Drive. This enables me to attach my phone.

    What impresses me is that everything just works. All drivers are available for all devices even on Windows RT.   I have a Keyspan USB to RS232 – and even that highly specialized niche product has a driver on Windows RT. Connect and use.

    7. Skydrive

    When I’ve taken a picture with my phone, it is immediately available on my Surface. When my kids ask: “Can I see the pictures you took?” – we look at them on the Surface – it is better than on the smaller phone.

    Skydrive enables many other scenarios too – the one with pictures is my favorite.

    8. Desktop

    The Surface has a desktop – just like you know it from any other version of Windows. You can open File Explorer, Control Panel, Regedit, Task Manager etc. All the built in functionality of Windows is available.  And on top of that you get Office. 

    Some find it limiting that you cannot install 3rd party apps on the desktop in RT mode. This does not concern me. I actually try to install as few as possible across all my PCs – it just makes them easier to maintain and less subject to malware.

    9. Battery

    For the past year we have not had any problems with the battery life time. I’m not sure how many hours we get out of it, but it is never a problem. Not even on our 3 week vacation in car across Europe this summer.

    10. Microsoft Store

    There are plenty of apps and games – at least for my taste.  There are a few titles missing – but then again, there are also some exclusive titles – like FreshPaint.

    WP_000337

  • mfp's two cents

    Cryptography API in X++

    • 4 Comments

    In version 3.0 the class TextBuffer had two methods: Encrypt and Decrypt. For version 4.0 the Encrypt method has been removed, and the Decrypt method renamed to DecryptOld.

    The change happened for security reasons.

    If you require to encrypt and decrypt strings in Dynamics AX 4.0, you can use the functionality provided in the .Net System.Security.Cryptography namespace.

    By doing so, you should be aware of the dangers, including:

    • A key is required to do encryption and decryption. Your encrypted data is never more secure than the key - so avoid storing the key (including hard coding it in X++) instead prompt the user for the key.
    • Use the Encryption algorithm as it is intended. Do not double-encrypt, it may make it easier to break the code.

    To help you get going, I've created an X++ Cryptography class. It uses the implementation of the encryption algorithm Rijndael from .Net. The class is attached to this thread.

    Here is an example on how to use it:

    static void main(Args _args)
    {
        Dialog dialog = new Dialog("Cryptography Demo");
        DialogField dfText = dialog.addField(typeid(description), "Text to encrypt");
        DialogField dfKey  = dialog.addField(typeid(description), "Key to encrypt with");
        str encryptedString;
        str decryptedString;    
        if (dialog.run())
        {
            encryptedString = Cryptography::Encrypt(dfText.value(), dfKey.value());
            decryptedString = Cryptography::Decrypt(encryptedString, dfKey.value());        
            info(strfmt("Encrypted string: %1", encryptedString));
            info(strfmt("Decrypted string: %1", decryptedString));
        }

    A big thank you to Ivan Medvedev for providing the C# implementation that I rewrote to X++. You can find the original article here - including more security considerations: http://www.dotnetthis.com/Articles/Crypto.htm 

    This posting is provided "AS IS" with no warranties, and confers no rights.

  • mfp's two cents

    What did you read during the holidays?

    • 4 Comments

    For years I had been planning to read Steve McConnell's Code Complete. It is one of these books that constantly is quoted. I remember the technical lead in Damgaard's early days had a copy of the book, he often referred to it, but didn't promote it within the organization. So last spring during a 10 week paternity leave, I read the whole thing, cover-to-cover. The only thing I regret is that I didn't do it earlier.

    This holiday season I planned a quick read-through of one of Steve McConnell's other works: Rapid Development. This book was published in 1996, and I expected the contents to be somewhat outdated by more recent development methodologies. However, Rapid Development is not another methodology, it is "just" a bible of common sense that can be applied during software development to achieve rapid (as in fast, speedy, not slow) development. I'm now half way through the book, and I find myself looking forward to opening the book each night. I've also caught my self rereading some of the paragraphs, not because they are poorly written, or because I'm half asleep, but because they are oh-so-true! This book deserves more than a quick skim, even in 2007.

    If you ever are going to write a single line of code, you must read: Code Complete.

    If you ever are going to manage, lead, or hire someone to do a software project, you must read: Rapid Development. 

    If this was true for all the people I interact with, my life would be so much more fun. I cannot recommend these books any clearer.

  • mfp's two cents

    Sneak preview - Code Upgrade Enhancements

    • 4 Comments

    Today is ZBB for Milestone 1 for the next version of Dynamics AX. ZBB is short for Zero Bug Bounce, which basically means all known defects introduced since last release must be fixed. For the Partner Productivity team it means that all known defects in the new Code Upgrade toolbox are fixed. It also means I get to do what I like the most: Share exciting technology with you!

    A big thank you is due to everyone who helped make this happen. All the cool ideas stem from talks with customers, partners and from online surveys. Thank you for providing us your valuable feedback!

    Please notice that the icons and text resources below are not finalized yet.


    Detecting upgrade conflicts

    This dialog replaces the dialog you used to get, when you click "Create upgrade project". As you can see, you now have more options. For the normal upgrade conflicts, you are still able to delete obsolete elements (those casting a shadow on an identical element in the lower layer). A new option is to "Auto-resolve property conflicts". Enabling this will automatically resolve conflicts where one property is changed in Your revision, and another property is changed in Their revision on the same AOT node. If the same property is changed in both Yours and Theirs it will still be marked as a conflict.

    With the new toolbox you can also create upgrade projects for stale code, that needs to be revisited. By stale code I mean code that violates certain practices, and must be updated before going live. Basically the feature runs the best practice tool on your code and looks for certain types of violations and creates an upgrade project with the violating elements.

     

    The Upgrade Project

    The upgrade project itself also offers new functionality. Each conflict, and resolved conflict will have a new icon on the individual node. This makes it quite easy to get an overview of where conflicts are, and where to pay attention. As you work your way through the conflicts, you can mark a conflict as resolved, and the conflict icon changes from a red alert to a green checkmark.

     

    Compare

    The compare dialog has also had a facelift. First off all the stylesheet has been updated to include some nice gradients. While this is merely eye-candy we also added many new cool features. First of all the compare dialog can now be started by a short-cut key (CTRL-G), and it is promoted to be at the same level as Find in the context menu. This should save you for some mouseclick. Secondly your preferences are now being stored, so the next time you open compare, you don't have to select (again) what you want to compare. And as if that wasn't enough, more information is now available to assist you making the right decisions more easily. For properties the Original value is now included, so you now can see both: Yours, Theirs and Original in the same window. 

     

    Estimation report

    Do you need to tell your boss when you'll be done with your work? I do. For code upgrade the help is near. You can now print a report, that is fully configurable with estimates for solving the detected conflicts of the various types. The estimates are broken down to the same granularity as the detected conflicts, which is on a per node level. Please note, that the data in the screenshot is staged, and not really meaningful.

    Convergence

    At Convergence in Dallas next week, my team will be present. They will share the same information as in this post. If you are there, make sure to pay them a visit.

     

    This posting is provided "AS IS" with no warranties, and confers no rights.

  • mfp's two cents

    Compiler warnings - and so what?

    • 4 Comments

    Every so often I find myself in a heated debate on what the quality bar should be for the code in the solution we are working on. This is an important debate, and for the project's success it should not be down prioritized. The quality bar may vary from project to project: If you are developing an internal tool for your team, you will have a completely different quality bar, than if you where writing software to control a spaceship. So in reality it all depends on the project you are working on. The important thing is to lock down on a quality bar and have all developers buy in and conform.

    A part of setting the quality bar for a project is to determine whether to treat warnings as errors. Warnings are an intrinsic part of the tools developers use everyday such as compilers, FXCop, X++ Best Practice Check, PreFast and StyleCop. And for this reason you can have a good, sound, opinionated and often long talk on this fine topic with almost any developer you may cross on your way.

    Being a devoted advocate for improving the code quality across any project, I want to share the following general considerations (courtesy of Ryan Harlicker) with you on why to treat warning as errors:

    1. They just look bad
      If your consumers are able to run the same tools as you are, and thus detect the same warnings, that you've chosen to ignore, it makes you look sloppy. For X++ code this is the case.
    2. Most warnings are really the tool reporting an error
      Most of the time a tool reports a warning it is really an error, but the tool cannot prove it. It is then reported as a warning so a human being can verify the issue and take appropriate actions.
    3. Too many warnings effectively means no warnings at all
      Warnings tend to breed exponentially.  It is best to deal with them at the time of creation as that person has the most context and knowledge of the right thing to do with the warning. If they aren’t handled right away then the knowledge barrier and the fact that they have always been there suppresses the urge to do the right thing and fix them (or suppress them if they are by design).
    4. They are there for a reason
      The warning detection code in the tools didn't come out of thin air. At some point in time someone felt strongly enough to invest time and money in improving the tool to report a warning. At the very least the reasoning for ignoring them should be well understood and not just ignored because they are a warning and not an error.
    5. Your project may become successful
      Even when you are working on a project for a small audience with a high level of tolerance for bugs, you may eventually be in a situation where your project evolves and will reach a broader audience. As the quality bar goes up, so does the cost of fixing warnings. Fixing them right away is cheaper than fixing them later.
    6. Hate to say I told you so!
      Have you ever been debugging a nasty problem for hours, and a split second after you finally reach the Eureka! moment, you realize you were already warned about the problem well in advance? You had just choosen to ignore the warning reported. Personally, I just hate when the tools laugh at me.

    If you are an X++ developer you can learn how to resolve X++ Compiler warnings here.

    If you are working on X++ development, but cant' figure out how many X++ Compiler warnings you have, you should read my blog post on AOT Metrics.

  • mfp's two cents

    Summer is over...

    • 4 Comments

    The summer is over, and you might have noticed I haven't been blogging much the past few months. You might also think I've been spending the last few months on a beach on an exotic island - but nothing could be further from the truth.

    Since the release of Dynamics AX 2009 I have been heads down on primarily two projects.

    The first project is a feature in AX6, that in the hallways at MDCC goes by the codename: "ID-Go-Away." Currently we have a plan for solving the element id problem. The plan includes both the technical aspects and the required organizational enablers, such as the right team, management buy-in, cross-team awareness and support etc. And what's even better: We have been executing on this plan the past 4-5 weeks.

    The second project is a book that goes by the name: "Inside Dynamics AX 2009". Yes, we are publishing an updated version of Inside Dynamics AX 4. Currently I have drafts lying in my top drawer of the chapters I'm responsible for. (These days my top drawer is a Sharepoint Server somewhere in a cellar in Ireland.) Next steps are editing and reviews.

    On a more personal note, I also have a third "project" going on, as my wife is due mid-September. We are very much looking forward to little sleep, diapers, and all the other joys of family bonding.

Page 3 of 19 (190 items) 12345»

mfp's two cents

...on Dynamics AX Development!