Что означает принцип DRY в разработке на Dart/Flutter?

«Что означает принцип DRY в разработке на Dart/Flutter?» — вопрос из категории SOLID и принципы, который задают на 36% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

DRY (Don't Repeat Yourself — «Не повторяйся») — это фундаментальный принцип разработки ПО, который гласит: «Каждое знание должно иметь единственное, однозначное, авторитетное представление в системе». На практике это означает устранение дублирования логики, стилей или структуры кода.

Проблема дублирования в Flutter-проекте:

// ❌ Нарушение DRY: одинаковая стилизация кнопки в разных местах
ElevatedButton(
  onPressed: () {},
  style: ElevatedButton.styleFrom(
    backgroundColor: Colors.blue,
    foregroundColor: Colors.white,
    shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
  ),
  child: Text('Save'),
)
// ... и тот же самый стиль повторяется для кнопки 'Submit', 'Confirm' и т.д.

Решения в соответствии с DRY:

  1. Вынос в константу или метод:

    // ✅ Единый источник стиля
    final ButtonStyle myPrimaryButtonStyle = ElevatedButton.styleFrom(
      backgroundColor: Colors.blue,
      foregroundColor: Colors.white,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
    );
    
    // Использование
    ElevatedButton(style: myPrimaryButtonStyle, onPressed: () {}, child: Text('Save')),
    ElevatedButton(style: myPrimaryButtonStyle, onPressed: () {}, child: Text('Submit')),
  2. Создание кастомного виджета:

    // ✅ Кастомная кнопка с инкапсулированной логикой и стилем
    class PrimaryButton extends StatelessWidget {
      final String label;
      final VoidCallback onPressed;
      const PrimaryButton({super.key, required this.label, required this.onPressed});
    
      @override
      Widget build(BuildContext context) {
        return ElevatedButton(
          onPressed: onPressed,
          style: myPrimaryButtonStyle, // Используем константу из примера выше
          child: Text(label),
        );
      }
    }
    // Теперь изменение стиля всех кнопок происходит в одном месте.
  3. Использование тем (Theming) в Flutter:

    // ✅ Глобальное определение в ThemeData
    MaterialApp(
      theme: ThemeData(
        elevatedButtonTheme: ElevatedButtonThemeData(
          style: myPrimaryButtonStyle,
        ),
      ),
    );

Почему DRY критически важен:

  • Снижает количество ошибок: Исправление или улучшение логики требуется только в одном месте.
  • Упрощает поддержку: Код становится чище и понятнее.
  • Повышает согласованность: UI и поведение приложения единообразны.

Осторожно: Слепое следование DRY может привести к излишней абстракции и сложным зависимостям. Иногда небольшое, осознанное дублирование («прагматичное дублирование») лучше, чем неправильная абстракция.

Видео-ответы