AX Development habits (Part 1)

0

Posted by Alexandr Malapheev | Labels: development, dynamics ax 2009 | Posted on Thursday, March 11, 2010

I want to start several discussions about some design/architecture issues we have in AX, and I think it is pretty important for each developer or tester who is responsible for the final quality of AX to read this article. After reading this you can say that it is all evident for you - but why you don’t using it then? ;)

The problem that we are using several development or design practices (or you can name it AX development habits) which are wildly used and considered normal in AX but in the "outside world" of enterprise development are well known bad practices, and have a number of different "correct" solutions, which described in a lot of literature, and successfully used by many companies.

So as I said I have several topics to discuss, but today I want to start with only one:
When do we need to use static methods in AX?

My answer to this question is: Never, or almost never

Now I can try to explain my point of view, I'm going to show several "common" examples and will show why they are bad:

Example 1:

Let consider common situation where we have 2 classes, class Foo and class Bar. They have following code:

class Bar
{
     public static int GiveMeIntValue()
     {
          //some query which goes to AOS and retrieve some data
     }
}
 
class Foo
{
     public void DoBusinesLogic()
     {
          //do something
          Value = Bar::GiveMeIntValue();
          //do something with value
     }
}

Before reading text below just try find at least 2 severe issues with the code.

Writing such code you are introducing a certain amount of coupling[1] into a system - coupling which is almost unnecessary. You are saying that your class can only collaborate with one particular implementation of a method. You will allow no substitutes. This makes it difficult to test your class in isolation. The very nature of test isolation assumes the ability to substitute alternative implementations.
And below I just want to summarize it in the context of our example:
  1. You can't write unit test for the method DoBusinesLogic, because if you will try to do it you will end up with integration[2] test not with unit test.
  2. If you will write test for the both methods GivemeIntValue and DoBusinesLogic - method you will get redundancy, because if GiveMeIntValue method start to work incorrectly (due to application changes), both test will fail, even if nothing wrong with DoBusinesLogic. Do you really want to spend your time with debugger to analyze a lot of tests if you can just look on the error message of one test?
  3. You will enforce ISV, partners or/and other teams to write bad code, and complicate upgrade to the future versions of AX. Because instead of using inheritance/aggregation and instance substitution to customize your code they will have to overwrite your code in upper layers.
    Note: This example is also valid for the static table's methods, but data access is a theme for another discussion. Here I just want to say never, never, never create static table methods.

Example 2:

Several times I've heard: "We need to use static method to make server call...".
This statement is partially correct. In a lot of AX classes I saw following pattern: there was a class Foo which have instance state, and during optimization somebody decided to create one or several "server static" methods on it, to reduce chattiness. This is in most cases a design issue - single responsibility principle[3] violation. Before creating such static methods you need to stop and think - is it right place to put a method or do I need to create a separate class for it.
I don't want do discuss technics of development client server application in details here (it is a topic for one of the next discussions). But here I want to mention that you can use static methods to create stateless service - the class which:

  1. Have only server methods;
  2. Doesn’t contain any business logic and just redirects method call to a separate class.
You use such class only to define a bridge[4] between client and server. But again it is preferable to use an instance class in this case which is marked as server.

Example 3:

Factory methods. I think that it is nothing wrong with factory methods, but there is another related problem - instantiation of an external dependencies in the business logic methods. Let’s again consider class Foo and Bar from example 1, if we for example change GiveMeIntValue method to make it instance and then will change Foo class:

class Foo
{
     public void DoBusinesLogic()
     {
          Bar bar = Bar::create();
          //do something
          Value = bar.GiveMeIntValue(); // now it is instance call
          //do something with value
     }
}
In this case you will still have all disadvantages from Example 1.

Some technics to avoid static methods

In an ideal world, an object should be able to interact only with other objects which were directly passed into it (through a constructor, or method call). Usually it can be solved by using inversion of control[5] principle and dependency injection, but AX is different so below you can find several ways to solve problems described above:

  1. To solve the issue described in the example 1, you need to change both classes
    You need to change all method in the Bar class to make them instance.
    In the Foo class you need to define an instance variable of the type Bar, and create a way to substitute it, it can be another factory method with parameter:
    class Foo
    {
         private Bar bar;
         public static Foo create()
         {
              return createWithBar(new Bar());
         }
         public static Foo createWithBar(Bar _bar)
         {
              Foo foo = new Foo();
              foo.bar = _bar;
              return foo;
         }
         public void DoBusinesLogic()
         {
              //do something
              Value = bar.GiveMeIntValue(); // now it is instance call
              //do something with value
         }
    }
    
    Or just parm method:
    class Foo
    {
         private Bar bar;
         public static Foo create()
         {
              Foo foo = new Foo();
              foo.parmBar(new Bar());
              return foo;
         }
         public Bar parmBar(Bar _bar = bar)
         {
              bar = _bar;
              return bar;
         }
         public void DoBusinesLogic()
         {
              //do something
              Value = bar.GiveMeIntValue(); 
              //do something with value
         }
    }
    
    Or it can be protected method which just creates and returns an instance of the Bar class, so you can override the method for unit test development purposes:
    class Foo
    {
         protected Bar createBar()
         {
              return new Bar();
         }
     
         public void DoBusinesLogic()
         {
              Bar bar = createBar();
              //do something
              Value = bar.GiveMeIntValue(); 
              //do something with value
         }
    }
    
  2. For the example 2 you have to separate responsibility and create to different classes , both are instance but one of them marked as server.
  3. Example 3 can be solved by using external factory class, or again by using a new protected method which will create an instance of required class.
    Wrong way:
    class Foo
    {
         public void DoBusinesLogic()
         {
              Bar bar = Bar::create(); // Bad code
              //do something
              Value = bar.GiveMeIntValue(); 
              //do something with value
         }
    }
    
    Correct way:
    class Foo
    {
         public Bar createBar()
         {
              return new Bar();
         }
     
         public void DoBusinesLogic()
         {
              Bar bar = createBar(); // Good code
              //do something
              Value = bar.GiveMeIntValue(); 
              //do something with value
         }
    }
    With external factory it is a bit difficult to create an example because it is very difficult to create such factory in a nice not "hacky" way within AX.

    The good solution for this problem is using IoC container - which is actually doesn’t exists in AX :)

Conclusion

You can say that all I described here is a pretty academic, and don't fit into real world. But it is not true there are a lot of successful examples of following these principles. Also you can say that it is so rapid and convenient to just define static method and use it, but again think about testability, extensibility and maintainability of your code.
I agree that it is not a silver bullet and there some rare exceptional cases where you can't follow this rules, also we have a lot of legacy code - but I think our goal is to go in the right direction, and write high quality code which follows all modern standards and practices.

P.S. I didn't say something new in this article. I just want you to start thinking about it. And I want you to share your opinion, so please send response if you are not agree or agree with me. :)

References:

1. http://msdn.microsoft.com/en-us/magazine/cc947917.aspx
2. http://en.wikipedia.org/wiki/Unit_testing
3. http://en.wikipedia.org/wiki/Single_responsibility_principle
4. http://en.wikipedia.org/wiki/Bridge_pattern
5. http://en.wikipedia.org/wiki/Inversion_of_control

SysMock for Dynamics AX 2009

2

Posted by Alexandr Malapheev | Labels: dynamics ax 2009, mock | Posted on Tuesday, September 8, 2009

What is the mock object?

In object-oriented programming, mock objects are simulated objects that mimic the behavior of real objects in controlled ways. Mock objects help you design and test the relations between the objects entangling the whole system.

Reasons to use

Developing with Mock objects helps on building a loosely coupled, and therefore maintainable, reusable, and testable code.
In a unit test mock objects can simulate the behavior of complex real (non-mock) objects and are therefore helpful when a real object is impractical or impossible to incorporate into a unit test. If the object has any of the following characteristics, it may be useful to use a mock object in its place:

  1. Supplies non-deterministic results;
  2. Has states that are difficult to create or reproduce;
  3. Is slow (e.g. a complete database, which would have to be initialized before the test);
  4. Does not yet exist or may change behavior;
  5. Would have to include information and methods exclusively for testing purposes (and not for its actual task).

Technical details

Mock objects have the same interface as the real objects they mimic, allowing a client object to remain unaware of whether it is using a real object or a mock object. AxMock allows the programmer to specify which, and in what order, methods will be invoked on a mock object and what parameters will be passed to them, as well as what values will be returned. Thus, the behavior of a complex object can be mimicked by a mock object, allowing the programmer to discover whether the object being tested responds appropriately to the wide variety of states such objects may be in.

The common coding style for testing with mock objects is to:

  1. Create instances of mock objects
  2. Set state and expectations in the mock objects
  3. Invoke domain code with mock objects as parameters
  4. Verify consistency in the mock objects

Example:

Consider we have this useless class we need to test:
class ClassToTest
{
     ClassToMock class2Mock;

     void new(ClassToMock _class2Mock)
     {
          class2Mock = _class2Mock;
     }

     public void doAction()
     {
          class2Mock.method1();
          if(class2Mock.method2() != "hello mock!")
          {
               throw error("error message");
          }     
     }
}


Let’s create unit test for this class using AxMock framework:
public void testClassToTest()
{
     SysMockRepository mocks = new SysMockRepository();
     ClassToMock mock = mocks.strictMock(classStr(ClassToMock));
     ClassToTest class2test = new ClassToTest(mock);

     // setting expectations
     mock.method1();
     SysMockExpect::call(mock.method2()).return("hello mock!");

     mocks.replayAll();

     class2test.doAction();

     mocks.verifyAll();
}

In this test we are creating strict mock object (line 4), creating the class to test (line 5), setting expectations (lines 8, 9), move the mock object to the replay state (line 11), run method we want to test (line 13), verify that all expectations are met (line 15).

Types of mock objects

AxMock framework supports 3 different types of mock objects:
- Strict. Strict semantics means that any call that wasn’t explicitly recorded is considered as error and would cause an exception to be thrown.
- Dynamics. Dynamic semantics means that any call that wasn’t explicitly recorded is accepted and a null or zero is returned (if there is a return value).
- Partial. Means that any call that wasn’t explicitly reordered calls original class method.

Setting expectations:

To set expectation you just need to call a method of a mock object. Or, if you want to set action to the calling method you have to use the Expect class. This class has only one method – “call”, this method takes one parameter of type anytype, and returns interface IMethodOptions.
Using this class you can set a value which will be returned from the method in replay state:
SysMockExpect::call(mock.method2()).return("hello mock!");
Or you can specify the text of error to be thrown:
SysMockExpect::call(mock.method2()).error("error message");
Or you can ask mock object to call original method:
SysMockExpect::call(mock.method2()).originalMethod();