The MorphX Development Environment and Tools
- 8/11/2014
Best Practices tool
Following Microsoft Dynamics AX best practices when you develop applications has several important benefits:
- You avoid less-than-obvious pitfalls. Following best practices helps you avoid many obstacles, even those that appear only in borderline scenarios that would otherwise be difficult and time consuming to detect and test. Using best practices allows you to take advantage of the combined experience of Microsoft Dynamics AX expert developers.
- Your learning curve is flattened. When you perform similar tasks in a standard way, you are more likely to be comfortable in an unknown area of the application. Consequently, adding new resources to a project is more cost effective, and downstream consumers of the code can make changes more readily.
- You are making a long-term investment. Code that conforms to standards is less likely to require rework during an upgrade process, whether you’re upgrading to AX 2012, installing service packs, or upgrading to future releases.
- You are more likely to ship on time. Most of the problems developers face when implementing a solution in Microsoft Dynamics AX have been solved at least once before. Choosing a proven solution results in faster implementation and less regression. You can find solutions to known problems in both the Developer Help section of the SDK and in the code base.
The AX 2012 SDK contains an important discussion about conforming to best practices in AX 2012. Constructing code that follows proven standards and patterns can’t guarantee a project’s success, but it minimizes the risk of failure because of late, expensive discovery, and it decreases the long-term maintenance cost. The AX 2012 SDK is available at http://msdn.microsoft.com/en-us/library/aa496079.aspx.
The Best Practices tool is a powerful supplement to the best practices discussion in the SDK. This tool is the MorphX version of a static code analysis tool, similar to FxCop for the Microsoft .NET Framework. The Best Practices tool is embedded in the compiler, and the results are reported in the Compiler Output window the same way as other messages from the compilation process.
The purpose of static code analysis is to detect defects and risky coding patterns in the code automatically. The longer a defect exists, the more costly it becomes to fix—a bug found in the design phase is much cheaper to correct than a bug in shipped code running at several customer sites. The Best Practices tool allows any developer to run an analysis of his or her code and application model to ensure that it conforms to a set of predefined rules. Developers can run analysis during development, and they should always do so before implementations are tested. Because an application in AX 2012 is much more than just code, the Best Practices tool also performs static analysis on the metadata—the properties, structures, and relationships that are maintained in the AOT.
The Best Practices tool displays deviations from the best practice rules, as shown earlier in Figure 2-15. Double-clicking a line on the Best Practices tab opens the X++ code editor on the violating line of code or, if the Best Practices violation is related to metadata, it will open the element in an AOT window.
Rules
The Best Practices tool includes about 400 rules, a small subset of the best practices mentioned in the SDK. You can define the best practice rules that you want to run in the Best Practice Parameters dialog box: on the Tools menu, click Options > Development, and then click Best Practices.
The best practice rules are divided into categories. By default, all categories are turned on, as shown in Figure 2-16.
FIGURE 2-16 The Best Practice Parameters dialog box.
The best practice rules are divided into three levels of severity:
- Errors The majority of the rules focus on errors. Any check-in attempt with a best practice error is rejected. You must take all errors seriously and fix them as soon as possible.
- Warnings Following a 95/5 rule for warnings is recommended. This means that you should treat 95 percent of all warnings as errors; the remaining 5 percent constitute exceptions to the rule. You should provide valid explanations in the design document for all warnings you choose to ignore.
- Information In some situations, your implementation might have a side effect that isn’t obvious to you or the user (for example, if you assign a value to a variable but you never use the variable again). These are typically reported as information messages.
Suppressing errors and warnings
The Best Practices tool allows you to suppress errors and warnings. A suppressed best practice deviation is reported as information. This gives you a way to identify the deviation as reviewed and accepted. To stop a piece of code from generating a best practice error or warning, place a line containing the following text just before the deviation:
//BP Deviation Documented
Only a small subset of the best practice rules can be suppressed. Use the following guidelines for selecting which rules to suppress:
- Dangerous API exceptions When exceptions exist that are impossible to detect automatically, examine each error to ensure the correct implementation. Dangerous application programming interfaces (APIs) are often responsible for such exceptions. A dangerous API is an API that can compromise a system’s security when used incorrectly. If a dangerous API is used, a suppressible error is reported. You can use some so-called dangerous APIs when you take certain precautions, such as using code access security (CAS). You can suppress the error after you apply the appropriate mitigations.
- False positives About 5 percent of all warnings are false positives and can be suppressed. Note that only warnings caused by actual code can be suppressed this way, not warnings caused by metadata.
After you set up the best practices, the compiler automatically runs the best practices check whenever an element is compiled. The results are displayed in the Best Practices list in the Compiler Output dialog box.
Some of the metadata best practice violations can also be suppressed, but the process of suppressing them is different. Instead of adding a comment to the source code, you add the violation to a global list of ignored violations. This list is maintained in the macro named SysBPCheckIgnore. This allows for central review of the number of suppressions, which should be kept to a minimum. For more information, see “Best Practice Checks” at http://msdn.microsoft.com/en-us/library/aa874347.aspx.
Adding custom rules
You can use the Best Practices tool to create your own set of rules. The classes used to check for rules are named SysBPCheck<Element type>. You call the init, check, and dispose methods once for each node in the AOT for the element being compiled.
One of the most interesting classes is SysBPCheckMemberFunction, which is called for each piece of X++ code whether it is a class method, form method, macro, or other method. For example, if developers don’t want to include their names in the source code, you can implement a best practice check by creating the following method on the SysBPCheckMemberFunction class:
protected void checkUseOfNames() { #Define.MyErrorCode(50000) container devNames = ['Arthur', 'Lars', 'Michael']; int i; int j,k; int pos; str line; int lineLen; for (i=scanner.lines(); i>0; i--) { line = scanner.sourceLine(i); lineLen = strLen(line); for (j=conLen(devNames); j>0; j--) { pos = strScan(line, conPeek(devNames, j), 1, lineLen); if (pos) { sysBPCheck.addError(#MyErrorCode, i, pos, "Don't use your name!"); } } } }
To enlist the rule, make sure to call the preceding method from the check method. Compiling this sample code results in the best practice errors shown in Table 2-5.
TABLE 2-5 Best practice errors in checkUseOfNames.
Message |
Line |
Column |
Don't use your name! |
4 |
28 |
Don't use your name! |
4 |
38 |
Don't use your name! |
4 |
46 |
Variable k not used |
6 |
11 |
Method contains text constant: ‘Don't use your name!’ |
20 |
59 |
In an actual implementation, names of developers would probably be read from a file. Ensure that you cache the names to prevent the compiler from going to the disk to read the names for each method being compiled.