Both ways offer a great variety of possibilities to create a huge mess.
Usually the best option is a mix of both - predefined logic bricks and custom python controllers. The trick is to know when to use what and when to separate aspects from each other ;).
The worst case is to create a “god object” that want to care about everything.
When you calculate damage you can focus on the calculation, or you can do calculation and mix it with showing the result and mix it with the influence on the character in combination with all possible participants.
I prefer to focus on the pure calculation. It would get input from a defined interface (e.g. messages and/or properties and/or function arguments). It calculates the result and provides it over another defined interface (e.g. messages and/or properties and/or function arguments).
My aspect does not care how and if the result is shown
-> freaking simple
-> minor dependencies
Other aspects (like the health bar) do not care how the damage is calculated, they focus on showing the health provided via their defined interface.
just some thoughts