Why is it sometimes $node->field_name[0], and sometimes $node->field_name['und'][0]?
The lack of the 'und', or LANGUAGE_NONE level data seems to indicate that the field has lost the ability to be translated. I've never encountered such a field.

field_get_items() as already pointed out is the canonical way to safely retrieve field data. Any fields that don't work with field_get_items should be considered broken.

I would hazard a guess that you either


Have a broken contrib module that re-arranges field data and doesn't know better than to sometimes remove the language level.
Your field settings have just broken somewhere along the way. Potentially because of a reason similar to above.


Does the problem keep happening on newly created fields?

Can you reproduce on a clean install?