1. Ansible is an orchestration tool, i.e. for execution, not for state description. Use Ansible for managing of other tools that lead your server to the desired state, do not describe the state itself inside Ansible.
2. Any complex scripts or programs should be wrapped into modules. Use the power of built-in Ansible features for interface creation between your tool and end user.
3. Use the same structure for your roles and plays according to the best practices.
4. Try to avoid using module shell directly. Analyze whether it is possible to wrap it into module first.
5. Use "include" directive + conditional statement to select between optional tasks.
6. Unite small tasks into blocks when it is necessary and looks rational.