Bangs in Elixir, as well as Ruby, are a way of indicating there is a similar, safer way to perform an operation. The intuition I’ve developed around them is:
When writing an API, present bang variants of functions for operations where both safe and unsafe versions have strong use-cases.
When choosing a variant, use the existence of the bang as an opportunity to ask yourself if you might really want the safer version.
When reading code with a bang variant, assume the author assessed the risk/failure modes in play, and chose the bang variant for some hopefully evident and important reason.
Not much more to it than that! It’s mostly a convention for developers to communicate a decision of caution and careful thought across time and space.
The only real rule is that there shouldn’t be a bang function without a non-bang equivalent. The bang doesn’t represent danger so much as an important decision made with intent, so it must be something that you decided to do in contrast to a more benign option.