Can you try to clarify which part is non-intuitive? In those scenarios I usually ask myself: would I dislike the new approach if I had learned it first? It helps you remove any bias and put what is non-intuitive into words.
If I had to guess, you don’t like that the definition is now a bit more hidden away from you. Although between worker(Foo) and Foo, the only information being hidden is the type of worker.
The new syntax always uses Foo.start_link/1 and completely removes the argument dance.
Finally, the fact the user of the module had to pass the supervision specification led to misuses. For example, earlier versions of Phoenix used worker(Ecto.Repo) instead of supervisor(Ecto.Repo). I have seen folks using tasks but forgetting to declare them as temporary, etc. In most cases, I would say it makes the most sense for the service to declare how it is supervised and not otherwise.
If you look at the six fields in a child only two are really only dependent on the child itself and they are whether it is a worker or supervisor and its dependent modules wrt code upgrading. All the others are really dependent on the supervisor which manages the child. So having them in a child callback seems a bit misplaced, that’s all.
Since child specs are maps, you can also use the functions in the map modules, but the child_spec/2 makes sure you are using the proper keys and setting the proper values.
Yes, of course, but it just seems out of place to specify things in the child code which is supervisor specific. It gives the impression that there is only one way to use this child.
Many of child specification options tie directly with how the process is implemented. If you are using {:stop, :shutdown, state} for clean shutdown of your GenServer, you likely do not want your supervisor to restart it on shutdown signals. If you need to do something that may take more than 5 seconds on terminate, the supervisor shutdown time needs to reflect that.
That’s why many libraries including poolboy and a couple modules in OTP expose their own child_spec function that returns the child specification. The child specification they return is not set in stone but it should be considered as the default way to run those processes unless you know what you are doing.
Luckily the impression there is only one way to use those children is easily solvable and we do mention such mechanisms in the Supervisor docs.