In our previous blog posts on best practices (found here and here), we covered multiple ways to improve the performance of your code by reducing the number of calls to and from the database. We are going to take a bit of deviation away from improving performance in this post and instead focus on another key area of development: maintenance. When writing maintainable code, there are some different goals that we want to achieve.
- Reduce the number of custom methods in your database.
- Reduce the size of the custom methods in your database.
- Make it easy to update the code that you do need to write.
Use the Innovator API
Aras Innovator ships with a few standard libraries that are accessible from any server-side Method. These libraries are already tested by the Aras QA department, and they very rarely change between the different versions of Innovator. Especially for server-side code, it's not uncommon for Methods originally written in Aras Innovator 9.4 to still work exactly as expected in the currently latest version of 12.0.
Apart from the added peace of mind of knowing that your code can be easily ported to a newer version, there's an even better reason to use the Innovator API wherever you can. It's already written! The best code is no code after all, so if we can save the time of needing to write our own functionality, we should. You can take a look at the Innovator API and the objects and functions within it by logging into your instance as an admin and selecting Admin > API Reference (.NET).
Use Shorthand Functions
The IOM at its core is just a wrapper for writing AML queries, and if you have any experience with writing AML queries manually, you know that you tend to use certain properties and attributes more than others. Our development team also knows this and thus they've added a few useful shorthand functions to accomplish specific tasks with a smaller amount of code.
One of the simplest examples of these shorthand functions that we can look at are the functions that cover getting and setting attributes. As you may know, you can set and get any attribute from a request by using the setAttribute and getAttribute functions respectively. However, for some of the most common attributes you will use like type, action, and id, you can use shorthand functions unique to each of those attributes like getType, getAction, and getID. You can see how to use these functions in code as well as their comparison to the standard way in the example below.
Each use of these shorthand functions will only save a few characters each time, but in the scope of all of your methods, the amount of code saved will add up quite a bit. Using these shorthand functions has an added benefit of throwing an error at compilation time if you happen to misspell one of the attributes since the name is directly in the method. If you misspell one of the attributes that you pass in to the getAttribute or setAttribute functions, your code will instead run and fail, and it may take longer to diagnose what the issue is.
There are also shorthand functions for appending items to a query. Most commonly you might want to do this when you're trying to get both a parent item and some relationship structure underneath it. You can see some examples of these Item shorthand functions compared to their longer-form counterparts below.
If you've developed software outside of Aras Innovator, you may have heard the term "magic number" before. A magic number is some integer value that appears directly in your source code, usually multiple times. This is considered bad practice because if the logic ever needs to change, you will need to update that value at every instance it is being used. A better practice would be to define a named variable to store the value instead of using it directly. Not only does this mean you can update the logic by changing just one section of your code, but giving the variable an appropriate name also helps the readability of your code.
Within Innovator, you should also avoid hardcoding values as much as possible. When we write custom methods, they often times start development to solve a problem for a particular ItemType. Because of this, we may hard-code the name of that ItemType into our logic so that our method works only for the specific use case we were trying to solve. With just a little extra work, we can often times expand that method to solve problems people just haven't thought of yet.
Let's look at an example where one of our users has complained that someone is claiming Parts and never un-claiming them. They want to be able to run an action on a Part to find out who currently has it claimed, so they can send a friendly reminder to un-claim it. Our first pass at solving this will probably result in a method similar to the one below.
This works well enough to make that specific user happy, but we can easily envision a world where the user comes back to report that the same problem is now happening with Documents and CAD. We could write two more custom methods to work for those two ItemTypes respectively, but then we have three methods that are all effectively accomplishing the same thing. If the logic ever needed to be updated, we would need to update it in three different locations. Instead, let's try to rewrite our existing method to remove the hard-coded reference to the Part ItemType inside of our newItem function.
We'll define a variable to store this value instead, and while we're at it, we can also look up what ItemType this method is currently running on from this. With that in place, we end up with a generic Method that could run on any ItemType in our database. If the logic ever needed to change, we would only need to update it once.
When it comes to maintaining code, putting the effort in early will save you an exponential amount of time in the future. Do you already try to use these tips in your day-to-day coding? Are there other practices you or your company use in addition to these? Let us know in the comments below.