Ansible is agentless, making it quick and painless to setup. Ansible has clear and detailed documentation and provides plenty of built-in modules. Its DSL is obtained using YAML and a familiar template system.
Ansible is still relatively new, as far as server automation tools go. This is the reason that many users have found it's documentation lacking in some parts. Although this is mitigated by the fact that it's very easy to learn to use.
Despite being written and taking good advantage of the python environment, Ansible offers no python api for programming, and does not make it possible to follow best practices for writing custom Ansible modules.
Chef has a relatively large community. One of the reasons for it is the fact that it's a pretty old and mature tool. Chef, originally released in 2009, is a more mature product. Being popular and with a large and dedicated community means that Chef has lots and lots of resources and guides from
Chef was released in 2009, which is relatively a long time ago for software. Since then it has been through several versions and many bug fixes and tests. All of this can make Chef more appealing to teams who are looking for stability and maturity, which are things that Chef brings on the table.
Chef is written in Ruby and its CLI uses a Ruby-based DSL. In order to fully use and customize it you need to use Ruby as Chef does not give users any other choice when it comes to languages to use to configure it.
Chef has a steeper learning curve than many of its competitors, making it a more difficult tool for the non-devs of a team (such as sysadmins) to work with. For some teams, the added cost of teaching Chef to the team may outweigh the benefits.
You define the state the server should be in and Puppet transforms it that state. This is opposed to explicitly declaring a list of actions to be performed. If a developer wants more flexibility and control there's always the option of falling back to explicitly running commands but that's
Due to it's out of order execution you can easily get into race condition between different modules. You have to be very careful declaring pre-requisites for the tasks so they don't step on top of each other. On the other hand when you get this lets you deploy things much faster than...
Modules and configurations are written in a specific language based on Ruby or in Ruby itself. So in order to be able to create custom configuration and modules you need a solid knowledge of Ruby. Although it's fair to mention that there are many modules already available for every use-case.