Create the module skeleton
Let's say our client wants to add a new page for best selling products. They also want to be able to override which products are displayed first on this page.
This functionality isn't really client-specific, so there really isn't a good reason we can't also use this module on other Magento projects. Because of this, we'll use our company name as the vendor name: Macademy. So we'll create a folder under app/code named Macademy.
Since the module deals with best selling products, the obvious name would be BestSelling. Note how we aren't naming it something like BS, because that doesn't tell us anything about the module. We're also keeping the name pretty generic and short, but not too specific, as that will allow us to change around the functionality a bit in the future. Since the module name is always referenced with our vendor name, we don't need to worry about naming collisions with other modules possibly named BestSelling. Let's go ahead and create a folder under Macademy named BestSelling.
Note that we are capitalizing the S for readability, but by doing so we always need to use the same casing everywhere when we reference the module.
For modules to be recognized by Magento, they need to contain both a registration.php file, and a module.xml file. The registration.php file is what is responsible for registering the module with Magento, meaning that it will now be aware of files and folders at this specific location. Without this file, Magento wouldn't know our module exists at the PHP-include level.
Let's go ahead and create a registration.php file within the root of our module. Modules, libraries, themes, language packs and setup scripts are all known as components, and need to be registered in the same way.
We'll import the ComponentRegistrar class from the Magento framework. Next, we'll call the register method statically.
If we command click into the register function, we can see that it accepts three parameters: the type of component, the component name, and the path, and they are all strings. For the component type, it's standard practice to use one of the constants defined within the ComponentRegistrar class.
In this case, we'll use the MODULE constant. Our component name will be the string version of the vendor and module name, which is Macademy_BestSelling.
The path will be the current directory. PHP has a built-in constant of __DIR__ which will return the directory of the current file.
At this point our registration.php file is complete. Next is the module.xml file. Magento expects this file to be located within an etc directory, so let's go ahead and create the etc folder. Then inside it, we'll create a file named module.xml.
It's always a mouthful to try to remember and type out all of the properties within XML files, so I usually create a live snippet within my IDE which generates most of the contents of this file. You can also look up an existing module for this data. Let's go to the Magento Catalog module at vendor/magento/module-catalog. This module controls everything about products. Open up the etc/module.xml file, and copy this file to your clipboard. You'll then paste the contents into your module.xml file.
Remove the Magento copyright comments, as this is our module, not Magento's. The sequence nodes here tell Magento that this module depends on these other modules. Since we won't have any dependencies at this time, we can remove these.
Within the root node config is a node named module. module nodes must contain a name property, which is the name of our module in that special syntax: Macademy_BestSelling.
Let's quickly take a look at the noNamespaceSchemaLocation property. This property references an XSD file, whose sole purpose is to validate the XML tree structure and properties of this file. This makes sure the XML follows a this very specific set of rules. If you ever need to find out the properties which are available for a specific XML file, check out its XSD file.
Upon saving the file, the basic creation of the module skeleton is complete.