When creating an application from scratch it is easy to plan out and create the required components in order to achieve the MVP (Minimum Viable Product) that meets the requirement. This application could be so simple that is just surfaces coffee to the UI. At this point there is only one feature, so you might consider registering the CoffeeComponent into the app root (app.module).
This is fine, it will work but consider the following example, originally we only had a requirement for one feature however over time the business grew and required extra functionality.
This small application that had just a simple CupComponent that surfaced our CoffeeComponent now needs to also surface our SugarComponent and MilkComponent and so on. Because these components originally were not grouped in anyway, it can become extremely tempting for Developers to add this functionality the same way it was added before. Straight into the root module (App.module). Eventually this module will grow in size and become difficult to read and understand. We have also added complexity because our app.module now depends on all of these components, and it looks messy!
This is where we can utilize feature modules, all our app should care about at this point is the cup, which actually contains everything required to make a coffee. A feature module can expose or hide it’s implementation from other modules. In theory, if we create a new module named cup.module all we then need is, milk, sugar and most importantly coffee. This will allow all the components in this feature and the routing to be grouped nicely inside the cup.module allowing them to be isolated and contained. If we ever need to make a good cup of coffee in this app or in an external app it’s nice and easy we just import our cup.module where required.
Lets dive right into an example of what we discussed above.
Our app.module now looks more organised and from a glance we can see from our folder structure that coffee, milk and sugar are nested within a cup feature.
Feature Modules can set a path so other developers continue to develop following this pattern going forwards. It can help aid debugging, allows isolation, structure, portability and lazy loading.