Skip to main content
Dart, despite being a modern and well-designed language, has several common anti-patterns that can lead to performance issues, maintenance problems, and bugs. Here are the most important anti-patterns to avoid when writing Dart code.
Always use Dart’s null safety features to prevent null reference exceptions. With sound null safety (Dart 2.12+), you can catch null reference errors at compile time rather than runtime.
Avoid excessive nesting of callbacks. Use async/await for more readable and maintainable asynchronous code.
Use const constructors for immutable objects to improve performance by reusing instances rather than creating new ones each time.
Avoid calling setState() multiple times in succession. Batch your state changes into a single setState() call to reduce unnecessary rebuilds.
Always use keys when building lists of widgets to help Flutter efficiently update the UI when the list changes.
Don’t ignore the results of Futures. Either await them and handle errors, or use .then() and .catchError() to process results and handle errors.
Avoid using dynamic type excessively. Use specific types to catch errors at compile time and make your code more self-documenting.
Use named parameters for functions with multiple parameters to make your code more readable and self-documenting.
Be careful with late initialization. Only use late when you’re certain the variable will be initialized before it’s accessed.
Use factory constructors when you need to control instance creation, such as for caching or returning instances of subclasses.
Always cancel stream subscriptions when they’re no longer needed to prevent memory leaks and unexpected behavior.
Implement comprehensive error handling to make your code more robust. Handle specific exceptions separately and provide meaningful error messages.
Use dependency injection to make your code more testable and flexible. Pass dependencies to classes rather than creating them internally.
Organize your code into separate files and folders based on functionality. Follow a consistent project structure to make your codebase more maintainable.
Use extension methods to add functionality to existing classes in a clean and type-safe way.
Use proper state management solutions like Provider, Riverpod, Bloc, or GetX instead of passing data through deep widget trees.
Use immutable model classes with copyWith methods to create modified copies instead of mutating objects directly.
Use code generation for repetitive tasks like JSON serialization, immutable classes, and equality implementations.
Break down large widgets into smaller, reusable components to improve readability, maintainability, and testability.