In forms and reports, code can only be executed as the result of an Event. In a truly compiled program, you write a MAIN section and can add one or more sections that contain subroutines. But for Access, you cannot write a MAIN because Access itself is the MAIN code segment. Your code in the form/report class module is based on the kindness of Access to provide you with HOOKS - places where you can declare specialty code to in some way customize the class object appearance and/or behavior.
There is a form event called FORM_OPEN - which is to say, when you launch a form, Access has to open it, and so what it kindly does is that it does its part and then gives you a place where you can identify a subroutine entry point. IF you do identify an entry point, Access calls that subroutine at the time that it finishes with ITS part of opening a form. The most common use of FORM_OPEN is to see whether you wanted to cancel the OPEN action (prevent the form from launching) because at that point, you haven't even loaded the controls of the form. You have just opened that form's form descriptors.
The question was asked, "Is it necessary for a form to have VBA code?" The answer is "No." And in fact, statistically speaking, the odds are quite good that most of the places where a form (OR a report) COULD have code, WON'T have code.
If you look at all of the EVENT properties of forms and reports and controls, you would realize that every visible thing on forms and reports (which includes controls on either) has anywhere from half-a-dozen to over fifty event entry points, most of which you will never use. But if you DID declare code for each one, Access would manage the stated event and then, before going on to the next thing to do, it would call your code. Whether you used the code for security, appearance, data or procedural validation, or general behavior issues, that code changes what users see or experience.
But do you need it? No, because remember that Access "does its thing" first, and THEN calls your event code before going on to the next thing. All events occur whether you have entry points or not. And if you are content that the "vanilla" behavior of Access does what you wanted anyway, you never need to write code behind those events.