One of Angular's greatest strengths is code organization. Through dependency injection, Angular forces client side code to adhere to MVC principles. This keeps code clean and organized. The use of controllers, services, and other modules emphasize a strong separation of concerns in Angular 1.
Despite such strengths, things can get messy when developers put logic in the wrong place. This is especially true with Angular's controllers. If you've worked with traditional MVC, then you understand that controllers handle all of the application's 'business logic'. Coming from other web frameworks (like Ruby on Rails) where routes and database calls are all defined in the controller, it's understandable how developers can accidentally abuse client side controllers.
Controllers should simply connect other dependencies to view templates. They shouldn't handle requests or define data objects that you want to use elsewhere. For example, a common mistake is using the $http service in an Angular controller to retrieve JSON data from a REST url. While this may give you a nice $scope variable that's bound to a view template, it restricts your ability to use that data elsewhere. What if you wanted to use that same data in a different controller? There would be ways to make this work, but it may involve another HTTP request or more lines of code.
Instead of using controllers as your one stop shop for application logic, move shared functionality to Angular services. Services are singletons that can be injected into any controller. This means that you can access the same variables and functions from anywhere in your Angular app. By using services, you can make one HTTP request, retrieve data, and reference it across multiple controllers. This keeps your code DRY and improves performance.
Be sure to wrap all of your DOM manipulation in directives. While it may be tempting to throw some jQuery into a controller $scope function, it meshes your view logic with your data model logic. As your app grows more complex, the DOM tree can become unnecessarily dependent on the controller. By strictly using directives, you are maintaining a more strict separation of concerns between the front end / back end.
Software design often boils down to personal preference. It's important to understand the fundamental difference in Angular's client side MVC compared to more traditional frameworks. Although everyone can agree that the controller should house most of your app's 'business logic', don't forget about other Angular components (directives, services, factories) when building out your controllers.