Component Referencing

There are many different ways of communicating from one script to another in Unity, each with their own advantages and disadvantages.

Get Component Call the GetComponent method whenever you need another component.
Get Component Cached Call the GetComponent method on startup and store it in a field.
Require Component Use a [RequireComponent] attribute so Unity will ensure that the other component exists.
Serialize Field Use a serialized field and assign the reference in the Inspector.
Reset Method Use a Reset method to automatically assign a serialized field.
On Validate Method Use an OnValidate method to automatically assign a serialized field.
Extension Methods Use extension methods to simplify the OnValidate approach.

Conclusion

Each approach has its merits, but I personally find using Extension Methods in the OnValidate Method to be the most effective because it gives flexible code that isn't directly tied to a specific hierarchy configuration and also makes it easy for non-programmers to use the scripts because they can easily see when other components are required but it will still try to automatically find those components so they don't need to be assigned manually.