Convention de code - ApplETS/Notre-Dame GitHub Wiki

📐 Conventions de Code

Vue d'Ensemble

Ce document définit les standards de code pour maintenir la cohérence et la qualité du projet.


🎨 Style & Format

1. Formatage Dart

# Formater automatiquement le code
dart format lib test

Configuration : Utiliser les paramètres par défaut de Dart.

Indentation : 2 espaces (standard Dart)

// ✅ BON
Widget build(BuildContext context) {
  return Container(
    child: Text('Hello'),
  );
}

// ❌ MAUVAIS (4 espaces ou tabs)
Widget build(BuildContext context) {
    return Container(
        child: Text('Hello'),
    );
}

2. Longueur de Ligne

Maximum : 80-100 caractères (convention Dart)

// ✅ BON (lisible sur 100 caractères)
const String veryLongVariableName = 'This is a moderately long string';

// ❌ MAUVAIS (trop long)
const String veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongVariableName = 'This is a string';

3. Imports

Ordre des imports :

  1. Dart standard library
  2. Packages Flutter
  3. Packages externes
  4. Imports relatifs (du projet)

Utiliser : import_sorter pour l'automatisation

# Rouler import sorter
dart run import_sorter:main

📝 Nommage

Classes et Interfaces

// ✅ PascalCase
class CourseViewModel {}
class UserRepository {}
abstract class DataService {}

// ❌ MAUVAIS
class courseViewModel {}
class user_repository {}
class dataservice {}

Variables et Fonctions

// ✅ camelCase
String userName;
void loadCourses() {}
int getUserAge() {}

// ❌ MAUVAIS
String user_name;
void loadcourses() {}
int GetUserAge() {}

Constantes

// ✅ Const globals en camelCase ou UPPER_SNAKE_CASE
const String appName = 'ÉTS Mobile';
const String apiBaseUrl = 'https://api.signets.ets.org';

// Ou pour les constantes très importantes
const int DEFAULT_TIMEOUT = 30;

// ❌ MAUVAIS
const String AppName = 'ÉTS Mobile';
const string API_BASE_URL = 'https://...';

Fichiers

// ✅ snake_case avec underscore
lib/ui/schedule/view_model/schedule_viewmodel.dart
lib/data/repositories/course_repository.dart
lib/domain/models/course.dart

// ❌ MAUVAIS
lib/ui/schedule/ScheduleViewModel.dart
lib/data/repositories/CourseRepository.dart

Routes et Chemins

// ✅ Dans RouterPaths class
class RouterPaths {
  static const String schedule = '/schedule';
  static const String newsDetails = '/news/:id';
}

// ❌ MAUVAIS
final scheduleRoute = '/schedule';  // Variable globale

🏛️ Structuration du Code

1. Ordre des Éléments dans une Classe

class MyWidget extends StatelessWidget {
  // 1. Constantes statiques
  static const String defaultValue = 'default';
  
  // 2. Variables finales (immutables)
  final String name;
  final int age;
  
  // 3. Variables privées (mutable)
  late String _status;
  
  // 4. Constructeur principal
  const MyWidget({
    required this.name,
    required this.age,
  });
  
  // 5. Constructors nommés
  MyWidget.empty()
    : name = '',
      age = 0;
  
  // 6. Getters et Setters
  String get displayName => name.toUpperCase();
  
  // 7. Méthodes publiques
  @override
  Widget build(BuildContext context) {
    return Container();
  }
  
  // 8. Méthodes privées
  void _initialize() {}
  
  // 9. Overrides
  @override
  String toString() => 'MyWidget($name, $age)';
}

2. Longues Fonctions

Diviser les longues fonctions :

// ❌ MAUVAIS (150 lignes dans build())
Widget build(BuildContext context) {
  // ... 150 lignes de code ...
}

// ✅ BON (extraire en méthodes privées)
@override
Widget build(BuildContext context) {
  return Column(
    children: [
      _buildHeader(),
      _buildContent(),
      _buildFooter(),
    ],
  );
}

Widget _buildHeader() => /* ... */;
Widget _buildContent() => /* ... */;
Widget _buildFooter() => /* ... */;

📚 Documentation

Documenter les classes, méthodes et parties de codes qui peuvent être plus complexes

Variables et Propriétés

/// True si la session est actuellement en cours
bool get isActive => DateTime.now().isAfter(startDate);

/// Cache des cours par sessionCode pour éviter les appels API répétés
final Map<String, List<Course>> _courseCache = {};

/// TODO: Implémenter le rafraîchissement automatique du cache
void _cacheRefresh() {}

✅ Bonnes Pratiques Dart/Flutter

1. Const par Défaut

// ✅ TOUJOURS utiliser const si possible
const Text('Hello')
const SizedBox(height: 16)

// ❌ ÉVITER
Text('Hello')
SizedBox(height: 16)

2. Type Safety

// ✅ BON : Spécifier les types
List<Course> courses = [];
Map<String, String> headers = {};

// ❌ MAUVAIS : Utiliser var ou dynamic
var courses = [];
dynamic headers = {};

4. Immutabilité

// ✅ BON : Utiliser final
class User {
  final String name;
  final String email;
}

// ❌ MAUVAIS : Variables mutables
class User {
  String name = '';
  String email = '';
}

5. Gestion des Erreurs

// ✅ BON : Attraper les exceptions spécifiques
try {
  await apiClient.getUser();
} on DioException catch (e) {
  print('Network error: $e');
} catch (e) {
  print('Unexpected error: $e');
}

// ❌ MAUVAIS : Attraper tout génériquement
try {
  await apiClient.getUser();
} catch (e) {
  // On ne sait pas ce qui s'est passé
}

🧪 Tests

Convention de Nommage des Tests

// Fichier: test/domain/models/course_test.dart
void main() {
  group('Course', () {
    group('constructor', () {
      test('creates instance with valid data', () {
        expect(() => Course(code: 'LOG123', title: 'Prog'), returnsNormally);
      });
      
      test('throws AssertionError when code is empty', () {
        expect(
          () => Course(code: '', title: 'Prog'),
          throwsAssertionError,
        );
      });
    });
    
    group('getLetterGrade', () {
      test('returns A for score >= 85', () {
        final course = Course(code: 'LOG123', title: 'Prog');
        expect(course.getLetterGrade(90), equals('A'));
      });
    });
  });
}

🔍 Linting & Analysis

Exécuter l'analyse

# Analyser le code
flutter analyze

# Ou avec Dart
dart analyze

🚀 Commandes Utiles

# Formatter tout le code
dart format lib test

# Analyser les warnings/errors
flutter analyze

# Générer le code (build_runner)
flutter pub run build_runner build

# Trier les imports
flutter pub run import_sorter:main

# Exécuter les tests
flutter test

# Vérifier la couverture de test
flutter test --coverage

✨ Résumé des Conventions

Élément Convention Exemple
Classes PascalCase UserRepository
Fonctions camelCase getUserData()
Variables camelCase userName
Constantes camelCase defaultTimeout
Fichiers snake_case user_repository.dart
Imports Organisés Dart → Flutter → Packages → Relatif
Indentation 2 espaces
Const Par défaut Autant que possible
Null Safety Strict ? et ! correctement
Lignes Max 100 chars

Cette page a été en partie générée avec l'aide de Claude Haiku 4.5

⚠️ **GitHub.com Fallback** ⚠️