Mejores Practicas
## Objetivos de Aprendizaje
- Seguir la guia de estilo de Dart
- Escribir codigo limpio y mantenible
- Dominar patrones efectivos
- Aprender practicas especificas de Flutter
## Convenciones de Nombres
### Variables y Funciones
```dart
// Variables: camelCase
var userName = 'Alice';
var isActive = true;
var itemCount = 42;
// Funciones: camelCase
void fetchUserData() {}
int calculateTotal() {}
// Miembros privados: guion bajo al inicio
class User {
String _privateField = '';
void _privateMethod() {}
}
```
### Clases y Tipos
```dart
// Clases: PascalCase
class UserAccount {}
class HttpClient {}
class ApiResponse {}
// Enums: PascalCase
enum Status { pending, active, completed }
enum Color { red, green, blue }
// Alias de tipos: PascalCase
typedef UserId = String;
typedef Callback = void Function();
```
### Constantes
```dart
// Constantes de tiempo de compilacion: PascalCase
const int maxItems = 100;
const String appName = 'MyApp';
// Valores de enum: camelCase (pero mantener enum PascalCase)
enum Status {
isPending,
isActive,
isCompleted,
}
```
### Archivos
```dart
// lowercase_with_underscores.dart
// user_repository.dart
// api_client.dart
// constants.dart
```
## Organizacion del Codigo
### Estructura de Archivos
```dart
// person.dart
class Person {
String name;
int age;
Person(this.name, this.age);
void greet() => print('Hola, soy $name');
}
```
### Organizacion de Importaciones
```dart
// Orden: SDK, paquete, relativo
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import '../models/user.dart';
import 'constants.dart';
```
## Variables
### Preferir var para Variables Locales
```dart
// Bien: el tipo es claro desde el lado derecho
var name = 'Alice';
var count = 0;
var items = ['a', 'b', 'c'];
// Aceptable: explicito cuando el tipo no es obvio
var points = [];
var mapping = {};
```
### Final Cuando Sea Posible
```dart
// Usar final para valores que no cambian
final name = 'Alice';
final items = ['a', 'b', 'c'];
// Usar const para constantes de tiempo de compilacion
const maxRetries = 3;
const defaultTimeout = Duration(seconds: 30);
```
### Evitar var para Campos Publicos
```dart
// Bien: tipo explicito para API publica
class User {
final String name;
final int age;
User(this.name, this.age);
}
// Aceptable: var para variables locales con contexto claro
var result = computeResult();
```
## Funciones
### Preferir Funciones Flecha para Funciones Cortas
```dart
// Bien
int square(int x) => x * x;
String capitalize(String s) => s.isEmpty ? '' : s[0].toUpperCase() + s.substring(1);
// Evitar para logica compleja
void process() {
// Logica compleja aqui
// Multiples sentencias
// No usar flecha para multi-linea
}
```
### Usar Void Solo para Efectos Secundarios
```dart
// Bien: devuelve valor
Future fetchUser(String id) async { ... }
// Bien: void para efectos secundarios solamente
Future saveUser(User user) async { ... }
// Evitar: devolviendo valor pero declarado void
// void process() => computeResult(); // Confuso
```
## Clases
### Preferir Constructores con Lista de Inicializacion
```dart
class Point {
final double x;
final double y;
Point(this.x, this.y); // Bien
// Evitar: parametros nombrados innecesarios para casos simples
// Point({required this.x, required this.y}); // Exceso aqui
}
```
### Usar Constructores Nombrados para Claridad
```dart
class Date {
int year;
int month;
int day;
Date(this.year, this.month, this.day);
// Constructores nombrados para claridad
Date.today() : this(DateTime.now().year, DateTime.now().month, DateTime.now().day);
Date.fromJson(Map json) : this(json['year'], json['month'], json['day']);
}
```
### Campos Privados para Encapsulacion
```dart
class BankAccount {
String _accountNumber; // Privado
double _balance; // Privado
BankAccount(this._accountNumber, this._balance);
double get balance => _balance; // Acceso solo lectura
void deposit(double amount) {
if (amount > 0) _balance += amount;
}
}
```
## Seguridad Null
### Evitar Desenvoltura Forzada (!)
```dart
// Mal
String name = getName()!;
// Bien: manejar null explicitamente
String? name = getName();
String displayName = name ?? 'Desconocido';
```
### Preferir Late con Moderacion
```dart
// Bien: cuando se necesita inicializacion perezosa
class DataService {
late String data; // Diferir inicializacion
Future load() async {
data = await fetchData();
}
}
// Mejor: si es posible, inicializar en el constructor
class User {
final String name;
User(this.name);
}
```
## Colecciones
### Preferir Literales de Coleccion
```dart
// Bien
var list = [1, 2, 3];
var map = {'a': 1, 'b': 2};
var set = {1, 2, 3};
// Evitar: constructor List<>()
// var list = List.of([1, 2, 3]); // Verbose
```
### Usar Operadores de Propagacion
```dart
var base = [1, 2, 3];
var combined = [0, ...base, 4]; // [0, 1, 2, 3, 4]
var defaults = {'a': 1, 'b': 2};
var overrides = {'b': 3, 'c': 4};
var config = {...defaults, ...overrides};
```
### Condicionales en Colecciones
```dart
var isPremium = true;
var items = [
'Inicio',
if (isPremium) 'Caracteristica Premium',
'Acerca de',
];
var filtered = [1, 2, 3, 4, 5]
.where((n) => n % 2 == 0)
.map((n) => n * 2)
.toList();
```
## Programacion Asincrona
### async/await Sobre Futures
```dart
// Bien: flujo asincrono claro
Future loadData() async {
try {
var user = await fetchUser();
var posts = await fetchPosts(user.id);
print('Publicaciones: $posts');
} catch (e) {
print('Error: $e');
}
}
// Evitar: encadenamiento excesivo de then
// fetchUser().then((user) => fetchPosts(user.id)).then(...);
```
### Cancelar Futures No Usados
```dart
class MyWidget extends StatefulWidget {
@override
State createState() => _MyWidgetState();
}
class _MyWidgetState extends State {
Future? _future;
@override
void initState() {
super.initState();
_future = loadData();
}
@override
void dispose() {
_future = null; // Ayudar a garbage collection
super.dispose();
}
}
```
## Manejo de Errores
### Excepciones Especificas
```dart
try {
await fetchData();
} on NetworkException {
// Manejar errores de red
showNetworkError();
} on ServerException catch (e) {
// Manejar errores de servidor con contexto
showServerError(e.message);
} catch (e, stack) {
// Errores inesperados
reportError(e, stack);
}
```
### Patron Result
```dart
class Result {
final T? data;
final String? error;
Result.success(this.data) : error = null;
Result.failure(this.error) : data = null;
bool get isSuccess => data != null;
}
Future> fetchUser() async {
try {
var user = await _api.getUser();
return Result.success(user);
} catch (e) {
return Result.failure(e.toString());
}
}
```
## Especifico de Flutter
### StatelessWidget vs StatefulWidget
```dart
// Usar StatelessWidget cuando sea posible
class Counter extends StatelessWidget {
final int count;
const Counter({required this.count});
@override
Widget build(BuildContext context) {
return Text('Conteo: $count');
}
}
```
### Widgets Const
```dart
// Bien: const cuando sea posible
return const Text('Hola');
// Bien: constructor const
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
return const Text('Hola');
}
}
```
### Evitar setState Cuando Sea Posible
```dart
// Bien: derivar de estado existente
Text('Conteo: $props.count');
// Considerar: Riverpod, Provider, Bloc para estado complejo
```
## Documentacion
### Usar Comentarios de Documentacion
```dart
/// Calcula la suma de dos numeros.
///
/// [a] El primer numero
/// [b] El segundo numero
///
/// Devuelve la suma de a y b
int sum(int a, int b) => a + b;
```
## Resumen
- Seguir nombres: camelCase (vars), PascalCase (tipos)
- Usar final para inmutable, const para tiempo de compilacion
- Preferir var para variables locales con tipos claros
- Usar constructores const en Flutter
- Manejar null安全的: preferir `??` sobre `!`
- Usar async/await sobre Future.then
- Ser especifico con excepciones
- Documentar APIs publicas con comentarios de documentacion
- Mantener archivos cortos y enfocados
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →