Quick Tip: Use Macros Wisely
Macros are one of the most powerful aspects of Kentico, and developers can use them throughout the platform. While macros are very capable, it’s important to remember what is happening behind the scenes when you use them so you know the impact they may have on the system. Because this code is compiled on the fly, it may have significant repercussions on your site’s performance. In this blog, I’ll show you a good example of how and when to use your macros the right way.
Macros are pretty awesome. With them, you can add custom functionality to nearly any area of the application and execute code to get dynamic results. They are a great way to build up parameters on web parts, customize transformations, and simplify your code with reusable components. Much like with standard C# code, developers should always be trying to simplify their work and code efficiently.
Often, our Support team sees lines upon lines of macros, many of which could be greatly simplified to a few simple calls. While the code may work for the partner, there is usually a more efficient implementation available. Take, for example, the following scenario:
Scenario
The partner is attempting to build a dynamic menu of links from pages stored in the content tree. This code is being used in several areas of the site, which is causing performance issues on several pages.
Original Code
if(Documents["/navitems"].Published=true && Documents["/navitems"].DocumentMenuItemHideInNavigation=false){if(!string.IsNullOrEmpty(Documents["/navitems"].Entry1)&& Documents["/navitems"].Link1!=null && Documents["/navitems"].Link1!=string.Empty ){print(""+Documents["/navitems"].Entry1 +"")};if(!string.IsNullOrEmpty(Documents["/navitems"].Entry2)&& Documents["/navitems"].Link2!=null && Documents["/navitems"].Link2!=string.Empty ){print(""+Documents["/navitems"].Entry2 +"")};if(!string.IsNullOrEmpty(Documents["/navitems"].Entry3)&& Documents["/navitems"].Link3!=null && Documents["/navitems"].Link3!=string.Empty ){print(""+Documents["/navitems"].Entry3 +"")};if(!string.IsNullOrEmpty(Documents["/navitems"].Entry4)&& Documents["/navitems"].Link4!=null && Documents["/navitems"].Link4!=string.Empty ){print(""+Documents["/navitems"].Entry4 +"")}; |(user)administrator|(hash)XXXXXXXXXXXXXXXX
Yikes! Not only is this a lot of code, but it’s also definitely hard to read. Here is a formatted version so you can see what each call is doing:
Original Code - Formatted
if(Documents["/navitems"].Published=true && Documents["/navitems"].DocumentMenuItemHideInNavigation=false){
if(!string.IsNullOrEmpty(Documents["/navitems"].Entry1)&& Documents["/navitems"].Link1!=null && Documents["/navitems"].Link1!=string.Empty ){
print(""+Documents["/navitems"].Entry1 +"")
};
if(!string.IsNullOrEmpty(Documents["/navitems"].Entry2)&& Documents["/navitems"].Link2!=null && Documents["/navitems"].Link2!=string.Empty ){
print(""+Documents["/navitems"].Entry2 +"")
};
if(!string.IsNullOrEmpty(Documents["/navitems"].Entry3)&& Documents["/navitems"].Link3!=null && Documents["/navitems"].Link3!=string.Empty ){
print(""+Documents["/navitems"].Entry3 +"")
};
if(!string.IsNullOrEmpty(Documents["/navitems"].Entry4)&& Documents["/navitems"].Link4!=null && Documents["/navitems"].Link4!=string.Empty ){
print(""+Documents["/navitems"].Entry4 +"")
}; |(user)administrator|(hash)XXXXXXXXXXXXXXXX
As you can see, the code is looking at the pages in the content tree and determining whether or not they should be included in the list. For each page that is to be included, it is appending it to the output so that the final result has all of the links. It is a lot of work on the platform to evaluate each one of these calls because macros (especially those dealing with the content tree) can return a lot of data for each execution and load many items into memory.
Optimized Code
Here is an optimized version of the code above. It accomplishes the same functionality but with a much simpler implementation of iterating through the content tree and evaluating each page. For each included link, the content is appended to the output for the final result.
doc = Documents["/navitems "];
if (doc.Published = true && doc.DocumentMenuItemHideInNavigation = false) {
return doc.Entry1+doc.Entry2+doc.Entry3+doc.Entry4;
}
The result is a cleaner, more efficient use of the macro engine and a smoother implementation. Note that the optimized code is assuming the Link fields are set to Required so we don't have to check for NULL.
Moving Forward
It’s important to remember that while macros can be used almost anywhere, you have to do so wisely. Always be sure to think through your code and implement it in the most efficient way possible.
Here are a few more tips when using macros:
- Use macros when you want to resolve dynamically in properties.
- If a macro is more than three lines, consider a code behind or custom macro method.
- Use the Macro Benchmark utility in the System Module to test the performance of your macro.
- Use the Macro Report in the System Module to find out where your macro is being used.
I hope this blog helps you understand the macro engine and think about how to implement them. Always test your code to see the impact it will have on your site’s performance. Good Luck!
This blog is intended for informational purposes only and provides an example of one of the many ways to accomplish the described task. Always consult Kentico Documentation for the best practices and additional examples that may be more effective in your specific situation.