One of good practices of writing C/AL Code for Microsoft Dynamics NAV since the dawn of civilization was annotating (commenting) code changes. If you are not sure what I mean by that, this is what I am talking about:
While standards varied about > vs +, or < vs -, or what the annotations should include, there was absolute consensus that annotating changes is an absolute must.
And it was a must. It was such an important rule that everyone followed it without questions asked. In my career, I’ve seen one or two situations of somebody changing or deleting a line of code without leaving any comment, and I’ve seen quite a lot of code, believe you me. It was that important.
It was that important in fact that it was one of the first things developers learned when they signed up for the job, and it was one of the rules they all followed from their first day.
Rules and habits
But as it often happens with rules, this rule slowly turned into a habit. Rules get introduced because they are needed. They all have a why part to them. Then they spread around and gain wide adoption because they are good, and they work. But then, at some point, they turn into habits, because people keep applying them even after their why part has been long forgotten.
Sure, nobody really forgot the why of this particular rule. Every developer worth their salt will tell you right off the bat that these annotations were necessary because that way we can track code changes from version to version, and it pays off when doing upgrades and merges.
But no single why ever comes alone. That’s what Sakichi Toyoda figured out a hundred years ago when he developed his Five Whys technique of getting to the root cause of anything. One why is shallow, it tells you an immediate cause. But five whys will get you to the root cause of any problem, he postulated.
In our case, we don’t really need five whys to get to the root reason of why we really needed code modification annotations. And the answer is as astoundingly simple, as it seems to be much forgotten: because we had no other way of tracking code.
You know, our development tools of old, the rest-in-peace C/SIDE and C/AL, were developed in another millennium, long, long before any source control management was invented.
The root reason why we annotated our code was because NAV had no built-in way, and no easy way of tracking code changes. The only way of being always able to track a code change together with the who, when, what, and why of that change was to put those annotations in there and keep them sacrosanct. Yes, there were tools, and there were attempts by many (even I did it, and it gained quite some traction back in the day and people apparently still download it – what the heck they use it for I have no clue…), but they were just that – attempts. The sad truth is – we never ever had anything close to a true source control management tool that just worked.
Fast forward a quarter century, and there is a new kid on the block: git. Git can do all those things we dreamed about. And more. A lot, lot more. Git can track a code line from the beginning of time to the end of it, it can tell you who ever changed it, when, why. It allows you to compare, merge, automatically, manually, you name it. It comes with so many powerful options that it practically displaced all other source control tools out there (when did you last see someone use SVN, or Mercurial; heck – even TFS is practically unheard of these days).
And guess what? With git, all the reasons for code annotations are gone.
Still, a few days ago, while handling a pull request on a Business Central extension project, I was flabbergasted to find it full of code annotations. Every single smallest change was duly annotated, as in the heyday of Navision Attain. Needless to say, merging that pull request took some manual time to get the changes properly into the repo, because git couldn’t handle it itself and it kindly asked for my manual attention. Mind you, none of the changes were actual conflicts – all of them were extremely simple line modifications or block additions.
And then I decided to do two things. Three things, in fact. The first one was to write this blog post and share my firm
opinion conviction about this practice. The second one was to create a git repo with a bunch of examples of what can happen if you keep this practice alive in the git world, as opposed to what it all looks like when done cleanly. And the third one was to ask around and see if this was an isolated case or something that people still just do.
Yes, I am completely convinced that in the world of git, this practice is completely obsolete, unnecessary, wasteful, and even harmful.
Ask any C# developer, C++ developer, Ruby developer, Python developer – heck, just about any other kind of developer there is – what they think about this practice. The best response you will get is probably along the lines, of: “Huh, what again?”
You see, those guys, they never annotate their code changes. That’s because it’s unnecessary. Why would you do that? When you need to change a line of code, you change it. When you need to delete a line of code, you delete it. No big deal, no ceremony, no fanfare. Just change, and move on. When you commit that change, git will take care of everything. It will tell you who changed it and when, and with good git commit comment practice in place, it will tell you why, too.
And please, don’t give me that “but we are different, AL is different than C#, maybe they don’t need it, but we do” line of reasoning. It’s bollocks. Code is code. Git is git. Git doesn’t care about the language you use, and git can handle any language. And AL is not the most complex language out there, take my word for that if that’s not already as obvious as the nose on your face. No special treatment needed for AL.
Let’s try to delve into the original whys of our code annotation practice. We needed it so we could trace who changed something and when. Cool, git tells you all of these without you having to do anything at all. Git allows you to compare between commits, and see the results of those comparisons side by side. If you don’t feel comfortable with git diff (and why should you), then there are a bunch of tools like GitLens, that can automate this and similar tasks. You have git blame to tell you who and when changed what, and VS Code can give you a nice overview of that, right out of the box. No need for annotations.
But what about merge, you ask? Yes, what about it? Git merges things automatically. You change something in your branch, then you merge that to another branch. If your branch started off from the branch you want to merge into, then it’s a no-brainer, your changes just go there. Just like that. If somebody merged something else to the target branch in the meanwhile, and target is ahead of you now, or if you merge across branches, you still stand good chances of git never asking a thing. Git is amazingly good at handling conflicts. Unless the target branch was modified at exactly the same places in code, git will be able to merge it just fine. You can have five people change the same file in five different branches, and you can then merge all of those branches into the same target using octopus strategy, and git won’t complain unless different branches changed the same lines of code. If each branch changed a different place in code, merge will just work. The only situations when merge will fail is if one branch changes the same region of code that was changed or deleted by another branch after the source branch was branched off the target branch, and that’s it. And even when there is a conflict, git will clearly show you what the conflict consists of, and VS Code allows you to resolve most conflicts in a single click. No annotations needed.
But every time I said “no annotations needed”, it was an understatement. Your annotations are not merely not needed. They are actually harmful.
When you introduce annotations in your code, you are actually making it far more likely for conflicts to occur. When multiple people work with the same file and don’t annotate the code, then git will most often be able to merge those changes without a conflict. However, once you introduce annotations, you are increasing the potential conflict surface and merge conflicts will start occurring where there should be none. And it’s dangerous, because it will cause you downtime. You’ll have to manually handle all those situations that normally require no human attention, because git is designed to handle these situations for you.
//> Mess.v3 // // > Mess.v2 // // // > Mess.v1
The ugliest consequence of code annotations always was the fact that after two or three cycles of changes, your code becomes unreadable. Heavily annotated code maybe helps you gain insight into who, what, when, and why (all of which are already answered by git), but the answer is not straightforward, it’s actually messy and complicated. The following screenshot tells it all:
Can you really tell what’s going on in here? Compare it to this:
With a little bit of GitLens…
… and click-to-compare (still from GitLens)…
… everything is far, far, far more clear than any annotations can tell. Especially because that annotation mess above is only three layers of changes; I’ve seen six, seven, even more, and not once.
I wasn’t lazy – I actually built an entire repo with 18 branches in total, where I show in parallel what happens with an annotated “tree” (I don’t know if that’s a correct term for a hierarchy of branches) and what happens with a normal, non-annotated, natural git kind of “tree”. I also show there how conflicts occur with annotated branches, where non-annotated counterparts happily merge without a sound.
However, I want to explain that repo with the branches in there, and what’s being done in each step, and what’s going on when you merge, and that would make this post far too long, and would veer a bit too sharply towards level 400. So I’ll do it in a follow-up post.
I was really curious about whether the case I experienced was isolated, or if there is this still a practice out there. I talked to a few people (but really actual people, not “a friend of a friend”) and apparently there are developers out there who still do this.
This reminds me of the Five Monkeys story I blogged about eleven years ago, and it’s a typical example of when a practice becomes so common that everyone stops thinking about it, and then people come and go, and the practice survives everyone that remembers why, in the first place, it was even started. We often mock this kind of practices when we encounter them with our customers – so often their business processes are ages old, and make no sense at all in the present, but they are still doing it because that’s how things are done around there. Don’t fall victim of this yourself.
Be smart. Be efficient.