What are your tips on reading source code containing macros?

Macros are always a contentious feature and that is never going to change. In our case, Elixir wouldn’t be Elixir without macros, so regardless of how one may feel about them, to write Elixir is to accept macros. Key constructs like defmodule, and def are macros! They allow Elixir to stay very close to Erlang while reducing a lot of the boilerplate that comes with writing Erlang (the first chapter of Elixir in Actions gives a good example of this). Otherwise, as you touched on, they allow the language itself to stay incredibly simple while allowing for really flexible extensibility. One of the best things about Elixir is that the language itself doesn’t change much (it’s often repeated how there will likely never be a 2.0, at least not in foreseeable future).

Personally I really like macros but I live by the advice I learned from the Ruby world: any form of metaprogramming should only be used in libraries, never ever in business logic. It does mean you need to somewhat understand macros if you want to read library code, though since Elixir macros are compile-time, running Macro.expand on any piece of macro code will give you exactly what you’re going to get at compile time. It’s an annoying extra step for sure but I know there are editor plugins that will do it for you.