Q:

When to use .first() and why?

Can someone explain why and when we need to use .first()?
An example to use would be this code.
{% set featuredProductsHome = craft.entries.id(2).first() %}
{% for product in featuredProductsHome.featuredProducts %}
    {% import '_macros/_product' as m_product %}
    {{ m_product.teaser(product, 500, "product-teaser--featured") }}
{% endfor %}

The above works, but when I had {% set featuredProductsHome = craft.entries.id(2) %} without calling .first() it returned nothing.

A:

By default, when you query elements you get back an array of Elements. Craft assumes you are using find() to query your elements if you don't explicitly say otherwise. You can loop through those elements and display attributes of those elements like you are doing:
{% for entry in craft.entries.find() %}
    {{ entry.title }}
{% endfor %}

More generally, here an abstract example of what you are getting back from your query:
{# A query for several Entry elements #}
craft.entries.find()

{# Results are an array of Entry Models #}
array(
  EntryModel,
  EntryModel,
  EntryModel
)

And in the case, you are only querying a single entry, you still get it back in the format of an array when using the default find() behavior.
{# A query for a single Entry element using find() #}
craft.entries.id(11).find()

{# Results are an array of a single Entry Model #}
array(
  EntryModel
)

However, if you update your query to use first(), you get back the Model directly:
{# A query for a single Entry element using first() #}
craft.entries.id(11).first()

{# Results are the Entry Model itself (not within an array) #}
EntryModel

There is one more scenario to consider when using first(). If you happen to be Eager Loading Elements, the results that you get back for your Element fields are not ElementCriteriaModels, but just normal arrays. So, in the case of accessing the data returned from Eager Loaded Elements you will not be able to use first() as the first() method is only available when you interact with ElementCriteriaModels.
In these cases, or in cases where you are sharing a partial template between two pages, one which uses eager loading and one that doesn't, you will need to access your first entry in an array using array syntax.
{% set entry = entry.entryRelationsFieldHandle[0] ?? null %}

In the above example, since we are accessing the first element in the array directly [0], if it doesn't exist, we will get an error (The first first() method is a bit smarter and will not throw an error). So, in the above example we have to explicitly plan for the situation of having no results using the null-coalescing operator ?? and falling back to null. 
A longer form discussion of this scenario can be found in the article Examples of Eager Loading Elements in Twig and PHP.

A:

It's because craft.entries.id(2) could be an object/array containing many entries. .first() gets the first object within it, which in your case is the 1 entry.
Edit*: I'm wrong, see the comment beneath.

