On my last blogpost on Source Code Analysis (which focused on the LineCount), I got the remark whether it would be interesting to drill into “statements”. I didn’t really know what he meant with it – but it made me think and drill down into the usage of the procedures.
You might remember we talked about the “places” in NAV where we were writing code, like: OnValidate trigger, custom functions, OnInsert, .. but also OnDrillDown on a control of a page .. these things. And the more you drill into it, the more things you wann find out ;-). So, the below on what came to my mind during this quest.
What are the places we write code?
In order to get some stats on that, we need to first define what we mean. Well, I’m interested in the procedure types, like “OnInsert”, “OnValidate”, but also the created functions. Well, here is the entire table – and you see, most code is on manually created functions, but still, there is a significant amount is on triggers:
Count | Name |
24676 | Procedure |
5948 | OnValidate |
4465 | OnAction |
2218 | OnDrillDown |
1907 | OnAfterGetRecord |
1281 | OnPreDataItem |
1063 | OnLookup |
982 | OnOpenPage |
476 | ExportOnBeforePassVariable |
442 | OnPreReport |
440 | OnRun |
398 | OnDelete |
375 | OnAssistEdit |
371 | OnInit |
311 | OnPostDataItem |
308 | OnAfterGetCurrRecord |
303 | OnInsert |
244 | OnNewRecord |
169 | OnModify |
162 | OnRename |
146 | OnFindRecord |
130 | OnQueryClosePage |
122 | Event |
114 | OnDeleteRecord |
111 | OnInitReport |
94 | OnNextRecord |
74 | OnPostReport |
65 | ExportOnBeforePassField |
63 | OnInsertRecord |
49 | Documentation |
48 | ExportOnAfterGetRecord |
44 | OnModifyRecord |
24 | ExportOnPreXmlItem |
23 | OnClosePage |
18 | ImportOnBeforeInsertRecord |
16 | ImportOnAfterAssignVariable |
13 | OnPreXmlPort |
9 | ImportOnAfterAssignField |
8 | OnPostXmlPort |
7 | OnBeforeOpen |
6 | ImportOnAfterInsertRecord |
4 | OnInitXmlPort |
2 | ImportOnAfterInitRecord |
The most used functions
Well, to be honest, this isn’t going to be very “true” stats, because I was not able to measure the amount of “OnModifies” or “OnInserts” or any of these trigger-calls for that matter. So I’m just focusing on all created functions/procedures – you know, the ones you can create yourself. Here is the Top 10 functions mostly used “somewhere” in C/AL:
FullNameWithID | UsedByCount |
Table<Currency Exchange Rate>.PROCEDURE<ExchangeAmtFCYToLCY> | 156 |
Report<General Journal – Test>.PROCEDURE<AddError> | 155 |
Codeunit<Reservation Engine Mgt.>.PROCEDURE<InitFilterAndSortingFor> | 150 |
Table<Currency>.PROCEDURE<InitRoundingPrecision> | 148 |
Codeunit<Calc. G/L Acc. Where-Used>.PROCEDURE<InsertGroup> | 126 |
Codeunit<CalendarManagement>.PROCEDURE<TimeFactor> | 124 |
Codeunit<AccSchedManagement>.PROCEDURE<GetDimTotalingFilter> | 120 |
Codeunit<XML DOM Management>.PROCEDURE<AddElement> | 113 |
Report<Vendor Pre-Payment Journal>.PROCEDURE<AddError> | 111 |
Codeunit<Job Calculate Statistics>.PROCEDURE<ShowLedgEntry> | 108 |
Note: It does NOT count the OnRun-trigger of a codeunit – so the Sales-Post.OnRun is not taken into account, or any “CODEUNIT.RUN” for that matter. But let’s be honest – we shouldn’t be calling code like that anyway! (no, we shouldn’t!)
Most used function names
So, let’s drill into naming conventions. First, just as a teaser, I like to know what the most used function name is – no – let’s show the Top 10 of most used names:
Count | Name |
238 | InitializeRequest |
104 | Code |
93 | ShowDimensions |
77 | GetLocation |
75 | Initialize |
69 | Caption |
57 | ValidateShortcutDimCode |
50 | Load |
50 | SetUpNewLine |
48 | GetItem |
Surprised? I asked this question on Twitter, you here you see the results – most of them were completely wrong :-).
To try to not confuse you (too much), there is a difference between the amount of times someone used a certain name to create a function (the above table), and the amount of times a certain function was used in some code.. . Let’s see about the latter one. Here are the function names, that are most used in C/AL code:
Name | UsedByCount |
AddError | 869 |
MATRIX_OnDrillDown | 596 |
ValidateShortcutDimCode | 454 |
MatrixOnDrillDown | 440 |
ShowDimensions | 310 |
GetLocation | 267 |
FilterReservFor | 264 |
AddElement | 264 |
MATRIX_GenerateColumnCaptions | 212 |
UpdateSubform | 192 |
GetItem | 185 |
Initialize | 176 |
Most Used Function prefixes
That made me think – what about prefixes. Well, that’s somewhat more difficult, because function prefixes can consist of a variaty of number of chars. So I decided to:
- Only focus on prefixes with 2,3,4,5 and 6 characters
- Don’t include the events (which basically start with “On”)
- And only take the ones that make sense to me, like exclude “Ge”, because it most likely “Get” is the intended prefix.
3207 | Get |
2373 | Set |
1233 | Update |
1093 | Calc |
1079 | Check |
869 | Show |
845 | Insert |
842 | Init |
822 | Create |
700 | Export |
507 | Is |
This is the top – and I like all of them ;-).
Unused functions
Vjeko came to me, and said – hey – you should try to list the functions that are NOT used anymore. Well, yeah, he kind of has a point – but I didn’t really think it was useful to do that, as Microsoft probably does their own analysis .. but still, it triggered me, so I did some queries. And I was amazed by the outcome. Really .. the amount of unused functions is a dazzling 1543, spread over 413 Pages, 416 Codeunits, 356 Tables and 358 Reports. And this is what i have taken into account:
- Only self created functions/procedures
- Left out the event subscribers
- Left out all functions from Codeunit 1 (as these are called from the runtime)
- Left out all the functions from “library-Random”, as there are functions for the testability framework
And still that many. Probably all of them having their own story, I’m sure, but I’m also sure that a lot of them are quite frankly “boat anchors“. I can’t just print them all here on the blog, but let’s just shed a light on two random cases:
Codeunit<Sales-Post>.PROCEDURE<CheckWarehouse>
As said, this function is never used .. although it has quite a lot of code! For me, this is a real boat anchor. Because we can find a “CheckWarehouse” at many locations – also on SalesLine – so my assumption is that it was redesigned, but left in CU80 .. . We can find more in CU80, by the way.. .
Codeunit<G/L Account Category Mgt.>.PROCEDURE<GetIncomeSalesReturns>
This is a type of function that I come across quite frequently. This function only returns the value of a text constant, by:
EXIT(myTextConstant);
Thing is, the function is never used, but the text constant is used all over that codeunit. So – what is the point of the function?
Local or global functions
We always advocate “be as local as possible”. Only methods should be global, all the rest should be local. Well, at least that’s the guideline .. so I though – let’s see how many are local and how many are global. These are the results:
- Local Functions: 13481
- Global Functions: 11195
Download
I exported the object-collection that I created to create this blog. You can find all results in that. So if you’re interested in all unused functions, you can figure that out from this download: NAV_10_15140_BE_ProcsFunctions
Disclaimer
As I put in my previous blogpost, all this data was crunched by an internal tool that I can’t share, and is still in BETA. Although I have no reasons to doubt the outcome (and believe me, when I saw the unused functions, I sure doubted our tool but after quite a lot of checks, conclusion was that it has to be right), I just can’t officially guarantee the 100% correctness of the results. If you have any reason to doubt, please contact me :-).